# Brand Assets
Source: https://docs.train.tech/brand-assets
Download the TRAIN logo, symbol, and brand colors
Use these assets when referencing TRAIN in articles, partner integrations, or marketing materials. Please don't recolor, distort, or add effects to the logo. The full brand kit is available in [Figma](https://www.figma.com/design/d6Eg6ehTBdKahTnwxNEoBY/Train-Brand-Assets).
## Logo with backgrounds
## Colors
| Name | Hex |
| ---------------- | --------- |
| **Primary Blue** | `#278EF6` |
# Protocol Updates
Source: https://docs.train.tech/changelog/overview
Protocol updates and improvements
* Released contracts **v3**: all deployment addresses rotated (deterministic CreateX deploys, salt `train.protocol.v3`) — see the updated [Deployments](/deployments) page.
* Solver locks are now keyed by **(hashlock, solver address)** instead of an incremental index. Each solver gets exactly one slot per hashlock (the double-lock guard), so a blind retry can never double-fund a swap and no one can squat another solver's slot. The [Core spec](/protocol-spec/core) and [implementation guides](/protocol-spec/implementation-solver) are updated to the v3 interface.
* Recorded mainnet deployments for Starknet, Fuel Ignition, and Tempo alongside the 7 EVM mainnets.
* Aztec upgraded to v5.0.1 with solver-keyed locks on testnet; Solana devnet now covers the full SOL/SPL reward matrix with three gasless rails.
* EVM contracts rewritten on Foundry with deterministic CREATE2 deployment, and relaunched on mainnet with one shared address across Ethereum, Arbitrum One, OP Mainnet, Base, Polygon PoS, BSC, and Robinhood.
* Updated the Starknet and Fuel mainnet contracts to the current version.
* Launched on [Tempo](https://tempo.xyz) mainnet, TRAIN's first deployment to a chain with no native gas token.
* See the new [Deployments](/deployments) page for the full, current list of mainnet, testnet, and in-progress network addresses — it replaces the old Contracts page.
* Introduced [Wallet HTLC](/protocol/atomic-swaps-secret_gen), secret generation from the wallet mechanism.
* Added [HKDF specification](/protocol-spec/HKDF) describing HKDF usage in TRAIN.
* Updated the [Auction Mechanism](/protocol-spec/auction) to enable solver competition and ensure users receive the best possible swap price.
* Added research about [cross-chain trading dynamics](/research/cross-chain-trading) with TRAIN protocol.
* Released TRAIN to mainnet.
* Mainnet contracts are available [here](/deployments).
* Added Bridge Deployment API documentation (later retired).
* Updated the [Edge Cases](/protocol-spec/edge-cases) specification with more detailed explanations.
* Rebranded to TRAIN from Layerswap V8. All repositories have been migrated to the new [TrainProtocol](https://github.com/trainProtocol) organization.
* Removed the Atomic Pool concept.
* Introduced the new [Reward & Slash mechanism](/protocol/slashing) embedded in Atomic Swaps themselves, eliminating the need for Atomic Pools.
* Added introduction to the [Auction system](/protocol/auction) and the [technical details](/protocol-spec/auction).
* Released TRAIN [Bridge dApp](https://app.train.tech) to use [Signature flow](/protocol-spec/core) instead of requiring two transactions; users now complete one transaction and one signature.
* Updated [dApp Implementation](/protocol-spec/implementation-dApp) and [dApp](/protocol/dApp) pages to include details for verifying the state of destination chains via Light Clients and/or multiple providers.
* Replaced 'LP' terminology with 'Solver' to avoid confusion with passive liquidity providing and to better explain the concept.
* Prepared branch for EVM security audit
* EVM Gas Optimization
| Function | Optimization | Gas (new) | Gas (old) |
| -------------- | ------------ | --------- | --------- |
| `commit()` | 52.7% | 146,300 | 309,608 |
| `addLock()` | 56.6% | 34,250 | 78,961 |
| `addLockSig()` | 48.9% | 42,103 | 82,447 |
| `refund()` | 35.5% | 39,460 | 61,262 |
| `redeem()` | 45.5% | 45,835 | 84,110 |
* Released the first version of the TRAIN protocol on EVM, Fuel, Starknet, Solana, and TON testnets.
* Released the first version of the Bridge Deployment API (later retired).
* Released the documentation page.
# Deployments
Source: https://docs.train.tech/deployments
Live and in-progress TRAIN Protocol contract deployments across every supported network
TRAIN's HTLC contracts are deployed deterministically wherever possible (CreateX on EVM chains, native contract-ID determinism on Fuel), so all EVM chains share the same `Train` contract address. The current release is **v3**. Deployment source of truth lives in the [contracts repository](https://github.com/TrainProtocol/contracts) — `main` carries the latest state of every production-track network, while early-stage networks are developed on their own `main-add-` branch. The contracts have not yet been externally audited. To learn how the `TrainRouter` powers gasless swaps, see [Gasless Flows](/protocol/gasless).
### Atomic Swap (HTLC) Contracts
| Contract | Address | Explorer |
| -------- | -------------------------------------------- | ------------------------------------------------------------------------------------ |
| Train | `0x265978c3e2E5dB9C3Ea665cC40C5925A5fc13Ee8` | [View](https://etherscan.io/address/0x265978c3e2E5dB9C3Ea665cC40C5925A5fc13Ee8#code) |
| Contract | Address | Explorer |
| -------- | -------------------------------------------- | ----------------------------------------------------------------------------------- |
| Train | `0x265978c3e2E5dB9C3Ea665cC40C5925A5fc13Ee8` | [View](https://arbiscan.io/address/0x265978c3e2E5dB9C3Ea665cC40C5925A5fc13Ee8#code) |
| Contract | Address | Explorer |
| -------- | -------------------------------------------- | ----------------------------------------------------------------------------------------------- |
| Train | `0x265978c3e2E5dB9C3Ea665cC40C5925A5fc13Ee8` | [View](https://optimistic.etherscan.io/address/0x265978c3e2E5dB9C3Ea665cC40C5925A5fc13Ee8#code) |
| Contract | Address | Explorer |
| -------- | -------------------------------------------- | ------------------------------------------------------------------------------------ |
| Train | `0x265978c3e2E5dB9C3Ea665cC40C5925A5fc13Ee8` | [View](https://basescan.org/address/0x265978c3e2E5dB9C3Ea665cC40C5925A5fc13Ee8#code) |
| Contract | Address | Explorer |
| -------- | -------------------------------------------- | --------------------------------------------------------------------------------------- |
| Train | `0x265978c3e2E5dB9C3Ea665cC40C5925A5fc13Ee8` | [View](https://polygonscan.com/address/0x265978c3e2E5dB9C3Ea665cC40C5925A5fc13Ee8#code) |
| Contract | Address | Explorer |
| -------- | -------------------------------------------- | ----------------------------------------------------------------------------------- |
| Train | `0x265978c3e2E5dB9C3Ea665cC40C5925A5fc13Ee8` | [View](https://bscscan.com/address/0x265978c3e2E5dB9C3Ea665cC40C5925A5fc13Ee8#code) |
| Contract | Address | Explorer |
| -------- | -------------------------------------------- | ------------------------------------------------------------------------------------------------ |
| Train | `0x265978c3e2E5dB9C3Ea665cC40C5925A5fc13Ee8` | [View](https://robinhoodchain.blockscout.com/address/0x265978c3e2E5dB9C3Ea665cC40C5925A5fc13Ee8) |
| Contract | Address | Explorer |
| -------- | ------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
| Train | `0x397630513a04161f0f73bc1aaf76c6e10f85d8b17b42d00d11e8767a1cf5255` | [View](https://voyager.online/contract/0x397630513a04161f0f73bc1aaf76c6e10f85d8b17b42d00d11e8767a1cf5255) |
| Contract | Address | Explorer |
| -------- | -------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
| Train | `0x445464bf4d8f2ad1cdffefa8345438f6769c44fc4aedf0eb9c2e34f5756f5750` | [View](https://app.fuel.network/contract/0x445464bf4d8f2ad1cdffefa8345438f6769c44fc4aedf0eb9c2e34f5756f5750/code) |
| Contract | Address | Explorer |
| -------- | -------------------------------------------- | ------------------------------------------------------------------------------------ |
| Train | `0xCb74407724c463EAA9bC661818364b532F8B5Cb5` | [View](https://explore.tempo.xyz/address/0xCb74407724c463EAA9bC661818364b532F8B5Cb5) |
### Atomic Swap (HTLC) Contracts
| Contract | Address | Explorer |
| ------------------- | -------------------------------------------- | --------------------------------------------------------------------------------------- |
| Train | `0x265978c3e2E5dB9C3Ea665cC40C5925A5fc13Ee8` | [View](https://sepolia.etherscan.io/address/0x265978c3e2E5dB9C3Ea665cC40C5925A5fc13Ee8) |
| TrainRouter | `0xF406475230bE1A65d06bd87A2724F78F4b6A2928` | [View](https://sepolia.etherscan.io/address/0xF406475230bE1A65d06bd87A2724F78F4b6A2928) |
| ConstantPayoutCurve | `0xf5522F01B44D95f3A8d8be5d78F3eee91d26543C` | [View](https://sepolia.etherscan.io/address/0xf5522F01B44D95f3A8d8be5d78F3eee91d26543C) |
| Contract | Address | Explorer |
| ------------------- | -------------------------------------------- | -------------------------------------------------------------------------------------- |
| Train | `0x265978c3e2E5dB9C3Ea665cC40C5925A5fc13Ee8` | [View](https://sepolia.arbiscan.io/address/0x265978c3e2E5dB9C3Ea665cC40C5925A5fc13Ee8) |
| TrainRouter | `0xF406475230bE1A65d06bd87A2724F78F4b6A2928` | [View](https://sepolia.arbiscan.io/address/0xF406475230bE1A65d06bd87A2724F78F4b6A2928) |
| ConstantPayoutCurve | `0xf5522F01B44D95f3A8d8be5d78F3eee91d26543C` | [View](https://sepolia.arbiscan.io/address/0xf5522F01B44D95f3A8d8be5d78F3eee91d26543C) |
| Contract | Address | Explorer |
| ------------------- | -------------------------------------------- | --------------------------------------------------------------------------------------- |
| Train | `0x265978c3e2E5dB9C3Ea665cC40C5925A5fc13Ee8` | [View](https://sepolia.basescan.org/address/0x265978c3e2E5dB9C3Ea665cC40C5925A5fc13Ee8) |
| TrainRouter | `0xF406475230bE1A65d06bd87A2724F78F4b6A2928` | [View](https://sepolia.basescan.org/address/0xF406475230bE1A65d06bd87A2724F78F4b6A2928) |
| ConstantPayoutCurve | `0xf5522F01B44D95f3A8d8be5d78F3eee91d26543C` | [View](https://sepolia.basescan.org/address/0xf5522F01B44D95f3A8d8be5d78F3eee91d26543C) |
| Contract | Address | Explorer |
| ------------------- | -------------------------------------------- | ------------------------------------------------------------------------------------------------ |
| Train | `0x265978c3e2E5dB9C3Ea665cC40C5925A5fc13Ee8` | [View](https://sepolia-optimism.etherscan.io/address/0x265978c3e2E5dB9C3Ea665cC40C5925A5fc13Ee8) |
| TrainRouter | `0xF406475230bE1A65d06bd87A2724F78F4b6A2928` | [View](https://sepolia-optimism.etherscan.io/address/0xF406475230bE1A65d06bd87A2724F78F4b6A2928) |
| ConstantPayoutCurve | `0xf5522F01B44D95f3A8d8be5d78F3eee91d26543C` | [View](https://sepolia-optimism.etherscan.io/address/0xf5522F01B44D95f3A8d8be5d78F3eee91d26543C) |
| Contract | Address | Explorer |
| ------------------- | -------------------------------------------- | -------------------------------------------------------------------------------------- |
| Train | `0x265978c3e2E5dB9C3Ea665cC40C5925A5fc13Ee8` | [View](https://testnet.bscscan.com/address/0x265978c3e2E5dB9C3Ea665cC40C5925A5fc13Ee8) |
| TrainRouter | `0xF406475230bE1A65d06bd87A2724F78F4b6A2928` | [View](https://testnet.bscscan.com/address/0xF406475230bE1A65d06bd87A2724F78F4b6A2928) |
| ConstantPayoutCurve | `0xf5522F01B44D95f3A8d8be5d78F3eee91d26543C` | [View](https://testnet.bscscan.com/address/0xf5522F01B44D95f3A8d8be5d78F3eee91d26543C) |
| Contract | Address | Explorer |
| ------------------- | -------------------------------------------- | ------------------------------------------------------------------------------------------ |
| Train | `0x265978c3e2E5dB9C3Ea665cC40C5925A5fc13Ee8` | [View](https://sepolia.lineascan.build/address/0x265978c3e2E5dB9C3Ea665cC40C5925A5fc13Ee8) |
| TrainRouter | `0xF406475230bE1A65d06bd87A2724F78F4b6A2928` | [View](https://sepolia.lineascan.build/address/0xF406475230bE1A65d06bd87A2724F78F4b6A2928) |
| ConstantPayoutCurve | `0xf5522F01B44D95f3A8d8be5d78F3eee91d26543C` | [View](https://sepolia.lineascan.build/address/0xf5522F01B44D95f3A8d8be5d78F3eee91d26543C) |
| Contract | Address | Explorer |
| ------------------- | -------------------------------------------- | ---------------------------------------------------------------------------------------- |
| Train | `0x265978c3e2E5dB9C3Ea665cC40C5925A5fc13Ee8` | [View](https://testnet.monadscan.com/address/0x265978c3e2E5dB9C3Ea665cC40C5925A5fc13Ee8) |
| TrainRouter | `0xF406475230bE1A65d06bd87A2724F78F4b6A2928` | [View](https://testnet.monadscan.com/address/0xF406475230bE1A65d06bd87A2724F78F4b6A2928) |
| ConstantPayoutCurve | `0xf5522F01B44D95f3A8d8be5d78F3eee91d26543C` | [View](https://testnet.monadscan.com/address/0xf5522F01B44D95f3A8d8be5d78F3eee91d26543C) |
| Contract | Address | Explorer |
| ------------------- | ------------------------------------ | ------------------------------------------------------------------------------- |
| Train | `TRooTQxWa3pgP6oA5QiyASxGKcRFRKY8k9` | [View](https://nile.tronscan.org/#/contract/TRooTQxWa3pgP6oA5QiyASxGKcRFRKY8k9) |
| TrainRouter | `TE8xNnkiWu71q6rs1mSYLV9Q5ZRaxTwHWX` | [View](https://nile.tronscan.org/#/contract/TE8xNnkiWu71q6rs1mSYLV9Q5ZRaxTwHWX) |
| ConstantPayoutCurve | `TXnXbz7UKN3KAJV8yNZtkFsHmzBuQ3hSu9` | [View](https://nile.tronscan.org/#/contract/TXnXbz7UKN3KAJV8yNZtkFsHmzBuQ3hSu9) |
| Contract | Address | Explorer |
| ------------------- | -------------------------------------------- | -------------------------------------------------------------------------------------------- |
| Train | `0xCb74407724c463EAA9bC661818364b532F8B5Cb5` | [View](https://explore.testnet.tempo.xyz/address/0xCb74407724c463EAA9bC661818364b532F8B5Cb5) |
| ConstantPayoutCurve | `0x758347A30b49d353F9C4dc8189F5c8f91FeaB27b` | [View](https://explore.testnet.tempo.xyz/address/0x758347A30b49d353F9C4dc8189F5c8f91FeaB27b) |
| Contract | Address | Explorer |
| ------------------- | ------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
| Train | `0x331d2d504d582a6918a70928fa31207f73600f45e8089310283223f439d52b0` | [View](https://sepolia.voyager.online/contract/0x331d2d504d582a6918a70928fa31207f73600f45e8089310283223f439d52b0) |
| TrainRouter | `0x1049d123293e9c182397ba1b5de795ee35c9ca0a1f2fecfec2eca14e38cecc8` | [View](https://sepolia.voyager.online/contract/0x1049d123293e9c182397ba1b5de795ee35c9ca0a1f2fecfec2eca14e38cecc8) |
| ConstantPayoutCurve | `0x27e92c85cf5da7861549ceba60096737a773f9b94f49046604ff0a0035cc351` | [View](https://sepolia.voyager.online/contract/0x27e92c85cf5da7861549ceba60096737a773f9b94f49046604ff0a0035cc351) |
| Contract | Address | Explorer |
| ------------------- | -------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| Train | `0x445464bf4d8f2ad1cdffefa8345438f6769c44fc4aedf0eb9c2e34f5756f5750` | [View](https://app-testnet.fuel.network/contract/0x445464bf4d8f2ad1cdffefa8345438f6769c44fc4aedf0eb9c2e34f5756f5750/code) |
| ConstantPayoutCurve | `0xfc598e7d022590a0eecc2f58c9ba865ace7c2ca5acae881dced5f2dbb37eb33b` | [View](https://app-testnet.fuel.network/contract/0xfc598e7d022590a0eecc2f58c9ba865ace7c2ca5acae881dced5f2dbb37eb33b/code) |
| Contract | Address | Explorer |
| ------------------- | ---------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
| Train | `2cQYFAiud2LBg3r6MxKPJ1oS83yyrRwDsgxQSwhL97LJ` | [View](https://explorer.solana.com/address/2cQYFAiud2LBg3r6MxKPJ1oS83yyrRwDsgxQSwhL97LJ?cluster=devnet) |
| ConstantPayoutCurve | `Dp4ReoYGG8VRXpnst4vT8g6UDVwUicJwAuiikQWk8HMF` | [View](https://explorer.solana.com/address/Dp4ReoYGG8VRXpnst4vT8g6UDVwUicJwAuiikQWk8HMF?cluster=devnet) |
| Contract | Address | Explorer |
| ------------------- | -------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
| Train | `0x1e36ef80d7d02ab8ed33aa07635f85152e015b9c4b09fbf5fe54ec11154d3133` | [View](https://aztecscan.xyz/contracts/instances/0x1e36ef80d7d02ab8ed33aa07635f85152e015b9c4b09fbf5fe54ec11154d3133) |
| ConstantPayoutCurve | `0x0f39abe60a09d7750b0f3fc1dada72f151d815f10f63a4413db9a9e2cb5d2fc7` | [View](https://aztecscan.xyz/contracts/instances/0x0f39abe60a09d7750b0f3fc1dada72f151d815f10f63a4413db9a9e2cb5d2fc7) |
Networks below have contract implementations under active development but no live deployment yet.
| Network | Status |
| ------- | ------ |
| TON | WIP |
| Stacks | WIP |
| Bitcoin | WIP |
| Sui | WIP |
| Aptos | WIP |
| XRP | WIP |
| Zcash | WIP |
# HKDF
Source: https://docs.train.tech/protocol-spec/HKDF
Describes HMAC-based Key Derivation Function(HKDF) usage in TRAIN
Train uses HKDF (HMAC-based Key Derivation Function) to generate deterministic and secure secrets for atomic swaps.
HKDF is a standardized key-derivation algorithm, which lets us turn one signature into any number of unique, swap-specific secrets.
If you are not familiar with HKDF you can consider it as just hashing.
The users signs the message `I am using Train`.
`initial_key = HKDF-Extract(signature)`
This key is cached locally by the dApp, as long as the cache persists, more signatures are not needed.
`secret = HKDF-Expand(initial_key, salt = (source_chain, destination_chain, timelock))`
For each swap, dapp derives a new secret using initial\_key, and the salt.
### Advanatges of HKDF derived secrets.
* **Deterministic**: The dApp can always recompute the secret as salt is not random, but is based on public data from the blockchain.
* **Unique**: Even if two swaps involve the same user, they will have different secrets because the salts differ.
* **No user Friction**: The user signs only once, and the dapp produces unlimited secrets from that one signature.
* **Recoverable**: If the cached initial\_key is lost, the user can simply sign the same message again and regenerate the identical initial key.
# Core
Source: https://docs.train.tech/protocol-spec/core
The core HTLC contract interface of the TRAIN protocol
The core of the protocol relies on the HTLC contract (`Train`). This contract is responsible for locking and unlocking funds based on specific conditions. All locks are keyed by the **hashlock** — `sha256(secret)` — and every network implements the same lifecycle.
### Core Functions
User creates an HTLC on the source chain with a hashlock derived from the recoverable secret generation mechanism. This locks the user's funds for the specified Solver. A gasless variant, `userLockFor`, lets a relayer fund and submit the lock attributed to the user (see [Gasless Flows](/protocol/gasless)).
Solver locks matching funds on the destination chain with the same hashlock, plus a reward secured by a `rewardTimelock`. Solver locks are keyed by **(hashlock, solver address)** — each solver gets exactly one permanent slot per hashlock (`SolverLockAlreadyExists` guard), so a blind retry can never double-fund the same swap, and no one can squat another solver's slot.
Anyone holding the secret can redeem: `redeemSolver` releases the Solver's destination lock to the user (paying the reward), and `redeemUser` releases the user's source lock to the Solver. Redeeming reveals the secret on-chain, which atomically unlocks both sides.
Return locked funds to the `refundTo` address after the timelock expires if the exchange wasn't completed. The user lock's recipient may refund at any time. A solver whose lock was refunded cannot re-lock the same hashlock from the same address — a retry requires a different solver address.
Implementation of the HTLC core contracts can be found in the [TRAIN contracts repo](https://github.com/trainprotocol/contracts). `main` carries every production-track network: [EVM](https://github.com/trainprotocol/contracts/tree/main/chains/evm), [Starknet](https://github.com/trainprotocol/contracts/tree/main/chains/starknet), [Fuel](https://github.com/trainprotocol/contracts/tree/main/chains/fuel), [Solana](https://github.com/trainprotocol/contracts/tree/main/chains/solana), and [Aztec](https://github.com/trainprotocol/contracts/tree/main/chains/aztec). Early-stage networks live on their own `main-add-` branch, e.g. [Bitcoin](https://github.com/trainprotocol/contracts/tree/main-add-bitcoin) and [Sui](https://github.com/trainprotocol/contracts/tree/main-add-sui).
The condensed EVM interface (see [`Train.sol`](https://github.com/TrainProtocol/contracts/blob/main/chains/evm/solidity/src/Train.sol) for the full implementation):
```solidity theme={null}
contract Train {
/// @dev The hashlock is the lock identifier: sha256(abi.encodePacked(secret)).
/// User locks are keyed by hashlock; solver locks are keyed by (hashlock, solver) —
/// at most ONE lock per solver per hashlock, ever (the retry / double-funding guard).
enum LockStatus { Empty, Pending, Refunded, Redeemed }
/// @notice Parameters for creating a user lock.
struct UserLockParams {
bytes32 hashlock;
uint256 amount;
uint256 rewardAmount; // reward expected on the destination side (informational)
uint48 timelockDelta; // refund becomes possible at startTime + timelockDelta
uint48 rewardTimelockDelta; // echoed for the solver (informational)
uint48 quoteExpiry; // lock creation reverts after this timestamp (QuoteExpired)
address recipient; // receives the payout on redeem
address refundTo; // receives the funds on refund
address token; // address(0) for native
address payoutCurve; // optional payout curve, address(0) for full payout
bytes payoutCurveData;
string rewardToken;
string rewardRecipient;
string srcChain;
}
/// @notice Parameters for creating a solver lock.
struct SolverLockParams {
bytes32 hashlock;
uint256 amount;
uint256 reward; // escrowed alongside the amount
uint48 timelockDelta;
uint48 rewardTimelockDelta; // reward routes to rewardRecipient before this, to the redeemer after
address recipient;
address rewardRecipient;
address refundTo;
address token;
address rewardToken;
address payoutCurve;
bytes payoutCurveData;
string srcChain;
}
/// @notice Cross-chain destination details (logged only, not stored).
struct DestinationInfo {
string dstChain;
string dstAddress;
uint256 dstAmount;
string dstToken;
}
/// @dev Emitted when a user creates a lock.
event UserLocked(
bytes32 indexed hashlock,
address indexed sender,
address indexed recipient,
string srcChain,
address token,
uint256 amount,
uint48 timelock,
address payoutCurve,
string dstChain,
string dstAddress,
uint256 dstAmount,
string dstToken,
uint256 rewardAmount,
string rewardToken,
string rewardRecipient,
uint48 rewardTimelockDelta,
uint48 quoteExpiry,
bytes userData,
bytes solverData
);
/// @dev Emitted when a solver creates a lock. `sender` is the solver —
/// at most one lock per (hashlock, solver).
event SolverLocked(
bytes32 indexed hashlock,
address indexed sender,
address indexed recipient,
string srcChain,
address token,
uint256 amount,
uint256 reward,
address rewardToken,
address rewardRecipient,
uint48 timelock,
uint48 rewardTimelock,
address payoutCurve,
string dstChain,
string dstAddress,
uint256 dstAmount,
string dstToken,
bytes data
);
/// @dev Emitted on redemption. `rewardTo` is the rewardRecipient before
/// rewardTimelock, and the redeemer after it.
event UserRedeemed(bytes32 indexed hashlock, address redeemer, uint256 secret, uint256 payout, uint256 excess);
event SolverRedeemed(
bytes32 indexed hashlock,
address indexed solver,
address redeemer,
uint256 secret,
uint256 payout,
uint256 excess,
address rewardTo,
uint256 reward
);
/// @dev Emitted on refund (full amount — and for solver locks, the reward — returns to refundTo).
event UserRefunded(bytes32 indexed hashlock, address refundTo, uint256 amount);
event SolverRefunded(bytes32 indexed hashlock, address indexed solver, address refundTo, uint256 amount, uint256 reward);
/// @notice Create a user lock to initiate a cross-chain swap (caller funds the lock).
/// @dev Payable: send `params.amount` as msg.value for native locks; 0 for ERC20 locks.
function userLock(UserLockParams calldata params, DestinationInfo calldata dst, bytes calldata userData, bytes calldata solverData) external payable { ... }
/// @notice Permissionless, ERC20-only variant: funds are pulled from msg.sender but the
/// lock is attributed to `user`. This is the gasless TrainRouter's forwarding target.
function userLockFor(address user, UserLockParams calldata params, DestinationInfo calldata dst, bytes calldata userData, bytes calldata solverData) external { ... }
/// @notice Create a solver lock (amount + reward escrowed). Reverts with
/// SolverLockAlreadyExists if this solver already used this hashlock.
function solverLock(SolverLockParams calldata params, DestinationInfo calldata dst, bytes calldata data) external payable { ... }
/// @notice Redeem a user lock with the secret. Recipient gets the payout
/// (curve-computed, full amount when no curve); any excess goes to refundTo.
function redeemUser(bytes32 hashlock, uint256 secret) external { ... }
/// @notice Redeem a specific solver's lock with the secret. The reward goes to
/// rewardRecipient before rewardTimelock, and to the caller after it.
function redeemSolver(bytes32 hashlock, address solver, uint256 secret) external { ... }
/// @notice Refund a user lock: recipient may refund anytime, others after the timelock.
function refundUser(bytes32 hashlock) external { ... }
/// @notice Refund a solver's lock after its timelock (amount + reward to refundTo).
function refundSolver(bytes32 hashlock, address solver) external { ... }
/// @notice Lock lookups.
function getUserLock(bytes32 hashlock) external view returns (UserLock memory) { ... }
function getSolverLock(bytes32 hashlock, address solver) external view returns (SolverLock memory) { ... }
/// @notice Windowed enumeration of a user's historical locks (scale-safe).
function getUserLockHashes(address user, uint256 offset, uint256 limit) external view returns (bytes32[] memory, uint256 total) { ... }
function getUserLocks(address user, uint256 offset, uint256 limit) external view returns (UserLock[] memory, uint256 total) { ... }
}
```
# Edge Cases
Source: https://docs.train.tech/protocol-spec/edge-cases
Describes potential failure scenarios and how the protocol handles them to ensure fund safety and transaction integrity
### Solver Fails to Act on the User's Lock
In a rare scenario where the selected Solver fails to act on the User's lock, the User only needs to wait for the timelock period (usually \~15 minutes) to receive their funds back.
```mermaid theme={null}
sequenceDiagram
participant User
participant SC as Source Chain
participant Solver
participant DC as Destination Chain
User->>SC: userLock() with hashlock
SC-->>Solver: UserLocked
Note over User,SC: Timelock passes
User->>SC: refundUser()
SC-->>User: UserRefunded
```
### User Fails to Transmit Secret to Solver
If the User does not transmit the derived secret to the Solver in time, both parties can refund their funds after the timelock period expires.
```mermaid theme={null}
sequenceDiagram
participant User
participant SC as Source Chain
participant Solver
participant DC as Destination Chain
User->>SC: userLock() with hashlock
SC-->>Solver: UserLocked
Solver->>DC: solverLock() with same hashlock
DC-->>User: SolverLocked
Note over User,SC: Timelock passes
User->>SC: refundUser()
SC-->>User: UserRefunded
Note over Solver,DC: Timelock passes
Solver->>DC: refundSolver()
DC-->>Solver: SolverRefunded
```
### Solver Fails to Release the User's Funds
In scenarios where the Solver releases their own funds but fails to release the User's funds, the protocol provides two mechanisms:
1. **Manual Redemption**: The User already possesses the secret (they transmitted it to the Solver). If the Solver fails to redeem on the destination chain, the User can directly use the secret to manually redeem their own funds on the destination chain, bypassing the Solver's failure.
2. **Reward Mechanism**: Other actors can redeem on behalf of the user and earn a reward for completing the swap. The original Solver loses their reward by failing to act in time.
```mermaid theme={null}
sequenceDiagram
participant User
participant SC as Source Chain
participant Solver
participant DC as Destination Chain
User->>SC: userLock() with hashlock
SC-->>Solver: UserLocked
Solver->>DC: solverLock() with same hashlock
DC-->>User: SolverLocked
User->>Solver: sign(secret)
Solver->>SC: redeemUser(secret)
SC-->>Solver: UserRedeemed
User->>DC: redeemSolver(secret)
DC-->>User: SolverRedeemed
```
### Solver Fails to Release Any Funds
If the Solver fails to release any funds, both the User and Solver can wait for the timelock period to expire and then refund their funds.
```mermaid theme={null}
sequenceDiagram
participant User
participant SC as Source Chain
participant Solver
participant DC as Destination Chain
User->>SC: userLock() with hashlock
SC-->>Solver: UserLocked
Solver->>DC: solverLock() with same hashlock
DC-->>User: SolverLocked
User->>Solver: sign(secret)
Note over Solver,DC: Timelock passes
Solver->>DC: refundSolver()
DC-->>Solver: SolverRefunded
Note over User,SC: Timelock passes
User->>SC: refundUser()
SC-->>User: UserRefunded
```
# dApp Implementation
Source: https://docs.train.tech/protocol-spec/implementation-dApp
Describes the protocol implementation for the User/dApp
Using the [recoverable secret generation mechanism](/protocol/atomic-swaps-secret_gen), derive a secret from the user's wallet signature, source chain, destination chain, and timelock parameters. Hash the secret to create the hashlock.
Call the `userLock()` function to lock funds with the derived hashlock and a timelock of [$T + \Delta$](/protocol-spec/model/#standard-flow). For a gasless experience, sign an intent and let a relayer submit it through the [TrainRouter](/protocol/gasless) instead.
* Watch for the `SolverLocked` event or query the lock directly by calling `getSolverLock(hashlock, solver)`.
* Verify that the `hashlock` of the lock on the destination chain matches your derived hashlock and provides sufficient time, ensuring it is at least [$T + 2\Delta$](/protocol-spec/model/#standard-flow).
The state of the destination chain should be read from a Light Client if one exists; if not, it should be read from multiple RPC providers.
Sign a message containing the derived secret and transmit this signed message to the Solver or any available actor. This allows them to use the secret to unlock funds on both chains without requiring further user interaction.
This signature transmission can happen via off-chain channels (WebSocket, API, etc.). The signature includes the actual secret, which the Solver can now use.
The Solver reveals the secret on the destination chain to unlock the user's funds and on the source chain to claim their own funds. Both the user and Solver can now complete their side of the transaction.
[Edge Case: Solver Fails to Act on the User’s Commitment/Intent](/protocol-spec/edge-cases#solver-fails-to-act-on-the-users-commitment-intent)
* Wait for the `timelock` to expire.
* Call `refundUser()` on the source chain to reclaim your funds.
[Edge Case: Solver Fails to Release Any Funds](/protocol-spec/edge-cases#solver-fails-to-release-any-funds)
* Wait for the `timelock` to expire.
* Call `refundUser()` on the source chain to reclaim your funds.
[Edge Case: Solver Fails to Release the User’s Funds](/protocol-spec/edge-cases#solver-fails-to-release-the-users-funds)
* If funds are not released on the destination chain, watch the source chain for the `UserRedeemed` event (or the `getUserLock(hashlock)` function).
* Once detected, capture the `secret` and call `redeemSolver()` on the destination chain.
# Solver Implementation
Source: https://docs.train.tech/protocol-spec/implementation-solver
Describes the protocol implementation for the Solver
Subscribe to `UserLocked` events to detect any locks made to your address with a hashlock.
* When a lock is detected, call `solverLock()` on the destination chain and pass the same `hashlock` with `timelock` of [$T + 2\Delta$](/protocol-spec/model/#standard-flow), along with the reward and `rewardTimelock`.
* Solver locks are keyed by **(hashlock, your solver address)** — you get exactly one slot per hashlock, ever. A blind retry reverts with `SolverLockAlreadyExists` instead of double-funding the swap; if your lock was refunded (e.g. a botched fill), re-filling the same hashlock requires a different solver address.
* Monitor the source chain for the `UserLocked` event details (or use the `getUserLock(hashlock)` function) on the detected lock.
* Verify that the `hashlock` matches what the user used.
* Verify that the `timelock` provides sufficient time to act, ensuring it is at least [$T + \Delta$](/protocol-spec/model/#standard-flow).
* Verify that the `payoutCurve` is one you recognize (only fill locks whose curve you trust — the curve determines the redeem payout).
The user will sign and transmit the derived secret to you via off-chain channels. Verify that when hashed, this secret matches the hashlock on both chains.
* Once you receive the secret, call `redeemSolver()` on the destination chain to unlock the user's funds. You are incentivized to do this quickly: before the `rewardTimelock` expires, the reward routes to you; after it expires, any actor can redeem and claim the reward instead.
* Call `redeemUser()` on the source chain to claim your primary fee/reward.
* Pass in the secret value received from the user.
[Edge Case: User Fails to Act on the Solver's Lock](/protocol-spec/edge-cases#user-fails-to-act-on-the-solvers-lock)
* If the source lock is never completed, wait for the `timelock` to expire.
* Call `refundSolver()` on the destination chain to reclaim your funds and reward.
# Model
Source: https://docs.train.tech/protocol-spec/model
Outlines the main protocol model for performing atomic swaps between parties
The protocol model relies on atomic swaps with recoverable secret generation for parties exchanging assets across different chains. The model outlines the core flow of assets and actions that should be taken by each party for a successful asset exchange. The protocol uses the [Standard flow](#standard-flow) for asset exchange between parties.
### Standard flow
When a party (Solver) directly supports both the source and destination chains and is willing to perform the swap, the standard flow applies. The user derives a secret using the [recoverable secret generation mechanism](/protocol/atomic-swaps-secret_gen) and locks funds on the source chain with the hashlock of that secret, setting the timelock to $T + \Delta$, where $T$ is the current timestamp and $\Delta$ is a reasonable duration (e.g., 15 minutes). The Solver observes this lock and creates a matching lock on the destination chain with the same hashlock and timelock of $T + 2\Delta$. The user then signs and transmits the derived secret to the Solver. The Solver reveals the secret on both chains to complete the swap.
Here are the steps:
The user derives a secret using [HKDF](/protocol-spec/HKDF) and creates a lock object on the source chain with the hashlock and a timelock of $T + \Delta$.
The Solver observes the lock on the source chain and creates a matching lock object on the destination chain with the same hashlock and a timelock of $T + 2\Delta$.
The user signs and transmits the derived secret to the Solver via off-chain channels.
The Solver reveals the secret on the destination chain to unlock the user's funds (earning a reward for this action), then reveals it on the source chain to claim their primary fee. The Solver is economically incentivized to complete the destination redemption promptly—if they delay, any other actor can step in and claim the reward instead.
```mermaid theme={null}
sequenceDiagram
participant User
participant SC as Source Chain
participant Solver
participant DC as Destination Chain
User->>SC: userLock() with hashlock
SC-->>Solver: UserLocked
Solver->>DC: solverLock() with same hashlock
DC-->>User: SolverLocked
User->>Solver: sign(secret)
Solver->>DC: redeemSolver(secret)
DC-->>User: SolverRedeemed
Solver->>SC: redeemUser(secret)
SC-->>Solver: UserRedeemed
```
# Reward-Slash
Source: https://docs.train.tech/protocol-spec/reward-slashing
Explains how the system penalizes Solver misbehavior and rewards others for acting to release user funds.
While users can always manually claim their funds, this protocol aims to prevent delays and inconvenience through economic incentives.
Solvers can exhibit unpredictable behavior that leads to various edge cases, such as refusing to release user funds. While users always retain the ability to manually claim their funds, preventing any permanent loss, this situation creates significant inconvenience.
## Core Mechanism
The **Reward-Slashing Mechanism** incentivizes proper Solver behavior. The process begins when a Solver locks funds for a user. At this point, they must also lock an additional reward amount secured by a timelock. This reward serves as an incentive - if the Solver successfully transfers the user's assets before the timelock expires, they receive their reward back. However, if they fail to act within the specified timeframe, the reward transfers to whoever executes the function to release the user's assets.
## Implementation Details
When a Solver locks funds for a user, the **solverLock** function escrows an additional **reward** amount along with a **rewardTimelock** parameter. This timelock must be set to a future timestamp and cannot exceed the timelock duration of the associated lock. The reward details are recorded in the **SolverLocked** event and stored inside the solver's lock itself — solver locks are keyed by **(hashlock, solver address)**, so anyone can read the reward for a given swap by calling **getSolverLock(hashlock, solver)**.
The `rewardTimelock` must always be set to a future timestamp and cannot exceed the HTLC timelock duration.
## Redemption Process
The **redeemSolver** function routes the reward differently based on timing. The logic is illustrated below using pseudocode:
```solidity theme={null}
transfer(funds, recipient);
if (!rewardTimelock.expired) {
transfer(reward, rewardRecipient); // the Solver acted in time
} else {
transfer(reward, msg.sender); // bounty for whoever redeems
}
```
## Security Considerations
The `rewardTimelock` serves as a crucial protection against MEV attacks. It provides Solvers adequate time to assess whether they can execute the **redeemSolver** function within the specified timeframe. Even if Solvers miss their initial window, they can still call the function later to retrieve their reward, provided no one else has already executed it.
# Original HTLC
Source: https://docs.train.tech/protocol/atomic-swaps-overview
Introduction to original Atomic Swaps and their challenges
Atomic Swaps (HTLC - Hashed Time Lock Contract) enable peer-to-peer asset exchange without requiring one Network to know the state of the other. The User generates a secret and locks funds on the Source Network. Then, the Solver locks funds on the Destination Network. They exchange the secret to unlock their respective funds, with a time limit ensuring fund retrieval if the exchange fails.
### The Standard HTLC Flow
The User generates a *Secret* S and computes *Hashlock* HASH(S). Then, they create an HTLC, locking funds for the selected Solver in the Source Network.
The Solver detects this HTLC and creates a counterparty HTLC with the same Hashlock. This locks funds for the User (initial amount minus the *Solver Fee*) in the Destination Network.
The User detects the HTLC in the Destination Network and reveals S to claim the funds.
The Solver detects the revealed S and reveals it in the Source Network to claim their funds.
### Challenges with HTLCs
Despite their potential, HTLCs have proven impractical for real-world bridging due to three main issues:
* **Secret Management**: Users must generate and securely manage a Secret until the counterparty completes their transaction.
* **Liveness**: Users must maintain the state of the bridging process locally and actively monitor and respond to counterparty transactions.
These challenges significantly impact the User experience and create barriers to adoption. The requirement for Users to manage the Secret creates a dependency issue. If the User closes the browser, clears the cache, or loses access to the Secret, the transaction flow cannot be recovered from the chain data.
# Wallet HTLC
Source: https://docs.train.tech/protocol/atomic-swaps-secret_gen
TRAIN Protocol atomic swaps with recoverable secret generation from the wallet
The **Wallet HTLC** approach is TRAIN's solution for practical atomic swaps with recoverable secret generation. Instead of requiring users to manually manage secrets or complete multiple transactions per swap, secrets are derived from the user's wallet signature. This enables **N+1 interactions for N swaps** — after an initial sign-in, users can perform unlimited swaps without additional signing steps.
## The Challenge
Traditional HTLC implementations face a key tradeoff: **User-generated secrets**. Private key/secret management burden on users; if the browser clears cache or the user loses access, the transaction cannot be recovered
Wallet HTLC solves this by making secret derivation **reproducible and recoverable from on-chain data**, while delegating the management entirely to the dApp.
### Sign In
The users signs the message `I am using Train`.
The dapp calls a [HKDF](/protocol-spec/HKDF) to derive an initial key from the signature, and keeps the key in the cache.
### Wallet HTLC Flow
The dApp derives a secret from the user's cached initial key, source chain, destination chain, and the timelock of the swap using [HKDF](/protocol-spec/HKDF).
User locks funds on the source chain using the hash of the derived secret as the hashlock.
Solver observes the source lock and creates a matching HTLC on the destination chain with the same hashlock.
The dApp signs a message containing the actual derived secret and transmits this signed secret to the Solver (or broadcasts it to any available actor).
The Solver reveals the secret on the destination chain to unlock the user's funds (earning a designated reward for this action) and on the source chain to claim their primary fee. The Solver is economically incentivized to execute the destination redemption promptly—if they delay, any other actor can step in and claim the reward instead. Both user and Solver complete the swap.
This way we keep all the advantages of HTLC, but delegate the secret management to the dapp.
As long as the user does not clear the cache the dapp can crete newer and newer secrets.
And if the cache is cleared than the user can sign the message again and get the initial key,
after that the secret can be recovered as the other parameters used to derive the key are publicly stored in the blockchain.
## Passkey-Based Implementation
For enhanced security and UX, the secret generation can also be derived from passkeys (WebAuthn credentials) instead of wallet signatures. This allows for fully passwordless authentication while maintaining the same recoverable secret generation properties.
**Implementation details:** See the [auth package](https://github.com/TrainProtocol/app/tree/dev/packages/auth) in the TRAIN app repository for the passkey-based implementation using HKDF key derivation.
# dApp
Source: https://docs.train.tech/protocol/dApp
Explains the details of the dApp using the protocol
### Overview
The [TRAIN Bridge dApp](https://testnet.train.tech/) serves as the central interface for seamless cross-chain transactions. It submits user intents for Solver matching, receives the selected Solver quote, and orchestrates the [HTLC flow with recoverable secret generation](/protocol/atomic-swaps-secret_gen).
The dApp has **four** main responsibilities:
1. Accept user swap intent and obtain a Solver quote
2. Display the winning Solver quote and allow the user to initiate the swap (specifying the winning Solver)
3. Execute the [HTLC flow](/protocol/atomic-swaps-secret_gen):
* Derive a secret from the user's wallet signature
* Lock funds on the source chain with the derived hashlock
* Observe the Solver's lock on the destination chain
* Sign and transmit the derived secret to the Solver so they can unlock funds on both chains
4. Optionally monitor and verify that funds are unlocked on both chains. The Solver is economically incentivized to redeem on the destination chain quickly because a reward is reserved for whoever completes that transaction—if they delay, any other actor can step in and claim it.
### Observing the Destination Network
The dApp must observe the destination lock created by the Solver to verify the swap is proceeding correctly. The dApp can observe this transaction through the following methods, listed in order of priority:
1. Bootstrap a Light Client (e.g., [Helios](https://github.com/a16z/helios)) for the destination chain and read the lock state from it
2. If no Light Client is available, read and verify the lock state from multiple RPC providers
# Gasless Flows
Source: https://docs.train.tech/protocol/gasless
How the TrainRouter enables gasless swaps, and how gasless flows work on non-EVM chains
Starting a swap normally costs the user two things: an ERC20 `approve` transaction and the lock transaction itself — both requiring gas on the source chain. TRAIN's gasless flow removes both. The user only **signs a message off-chain**; a relayer (typically the Solver) submits it on-chain and pays the gas, and the funds are locked in the `Train` contract attributed to the user.
On EVM chains and Starknet this is handled by a dedicated contract, the **TrainRouter**. On chains with protocol-level fee abstraction (Tempo, Aztec, Solana), no router is needed — the chain itself provides the gasless mechanism.
The TrainRouter and payout curves are currently deployed on **testnets only**. Mainnet deployments are `Train` alone — mainnet locks pass `payoutCurve = 0` (full payout) — with the Router's deterministic address reserved for a later rollout. See [Deployments](/deployments) for current addresses.
## TrainRouter Architecture
The TrainRouter is a **stateless forwarding contract**: it has no owner, no privileged roles, no stored addresses, and it never holds funds between transactions. Its only job is to pull the user's tokens using a gasless token-transfer standard and forward them into `Train.userLockFor` in the same transaction.
```mermaid theme={null}
sequenceDiagram
participant User
participant Relayer
participant Router as TrainRouter
participant Train
User->>Relayer: signed intent (off-chain)
Relayer->>Router: forwardWithPermit / Permit2 / Authorization
Router->>Router: pull user's ERC20 (Permit2 / ERC-2612 / EIP-3009)
Router->>Train: approve exact amount, userLockFor(user, ...)
Train-->>User: lock attributed to user
Router->>Router: reset approval, verify no residual balance
```
### The signed intent
Everything the relayer is allowed to do is fixed by the user's signature. The intent commits to:
`(user, train, token, amount, keccak256(callData), nonce, deadline)`
Because the hash of the full calldata is signed, the relayer can only execute **the exact call the user authorized** — the destination contract, the recipient, the hashlock, the timelock, and every other lock parameter are all locked in by the signature. The Router itself never inspects or interprets the calldata; it is *target-agnostic* by design.
### Three signature paths
The Router supports the three widely adopted gasless-transfer standards, so it works with any mainstream ERC20:
| Path | Standard | How the intent is bound |
| -------------------------- | ------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------- |
| `forwardWithPermit` | ERC-2612 permit | A separate EIP-712 intent signature, verified with `SignatureChecker` — works for EOAs **and** ERC-1271 smart accounts |
| `forwardWithPermit2` | Permit2 (`permitWitnessTransferFrom`) | The intent hash is embedded as the Permit2 **witness** — one signature covers both the transfer and the intent |
| `forwardWithAuthorization` | EIP-3009 (`receiveWithAuthorization`, e.g. USDC) | The intent hash is forced to be the authorization **nonce** — one signature covers both |
### Safety guarantees
* **Exact-amount forwarding.** The Router approves the target for exactly `amount`, makes the call, then resets the approval to zero. The target can never consume more than the user signed for.
* **Conservation check.** After forwarding, the Router asserts its own token balance returned to the pre-pull value. If the target contract fails to consume the funds, the entire transaction reverts and the user keeps their tokens — the Router can never end up custodying a balance.
* **Replay protection.** Every intent carries a user-chosen `nonce` and a `deadline`. The Router records each consumed intent and rejects re-use across **all three paths** — a signed intent executes at most once, and never after its deadline.
* **ERC20 only.** Native assets can't be moved by signature, so the gasless path is ERC20-only; native-asset locks use the direct `userLock` flow. Standard (non-fee-on-transfer, non-rebasing) tokens are expected.
## Payout Curves
Locks created through any path can reference a **payout curve** — a contract implementing `IPayoutCurve` that computes how much of the locked amount the recipient receives at redeem time (any remainder returns to the refund address). The curve is called via `STATICCALL`, so it can never mutate the HTLC state, and `Train` validates EIP-165 support before accepting one.
The single shipped curve, `ConstantPayoutCurve`, returns the full amount — a deliberate no-op that keeps the mechanism extensible for future pricing models. Since anyone can supply a curve when creating a lock, Solvers only fill locks whose payout curve they recognize (the curve address is included in the lock event before they commit).
## Per-Chain Variants
Starknet runs the same `Train` + `TrainRouter` + payout-curve architecture, ported to Cairo. The router follows the same signed-intent forwarding model as the EVM version, adapted to Starknet's account-abstraction-native signature scheme.
Tempo has no native gas token: fees are paid in **pathUSD**, and the chain natively supports transaction batching and fee-payer sponsorship. A sponsor can co-sign and pay the fees of a user's transaction directly, which replaces everything the TrainRouter does. Tempo therefore runs a dedicated `Train` contract variant (no native-asset code paths) and **no TrainRouter at all**.
Aztec has fee abstraction built into the protocol: fees are paid in **Fee Juice** (bridged from L1) or covered by a sponsored **Fee Paying Contract (FPC)** acting as a paymaster. Gasless UX comes from the chain itself, so no TRAIN-side router exists on Aztec.
Every TRAIN lock instruction separates the `payer` account (fees and rent) from the `sender` account (funds authority), which enables three gasless rails: **fee-payer sponsorship** (the relayer pays fees, the user co-signs only to authorize the debit), **durable nonce** (same, but the user can sign fully offline with no expiry), and **signed intent** (the user signs only an off-chain message — verified on-chain via the ed25519 precompile — and never signs a transaction at all, with a single-use consumed-intent guard mirroring the EVM Router's replay protection).
Tron runs the same `Train` + `TrainRouter` pair as other EVM chains, but Tron has no CREATE2 factory and uses a different address derivation, so its contract addresses differ from the shared EVM set.
Current contract addresses for every network are listed on the [Deployments](/deployments) page.
# Introduction
Source: https://docs.train.tech/protocol/introduction
A trustless, permissionless cross-chain bridging (swapping) solution.
The **TRAIN** Protocol (**TR**ustless **A**tomic **IN**tents) is a peer-to-peer system for bridging and swapping crypto assets between blockchain networks. The protocol is implemented as a set of persistent, non-upgradable smart contracts deployed to all [supported networks](/deployments).
* TRAIN is built on top of [HTLC with recoverable secret generation](/protocol/atomic-swaps-secret_gen). This allows two parties—the **User** and the **Solver**—to exchange assets trustlessly across different chains. Users send their **Intents** to Solvers, who fulfill these Intents using Atomic Swaps.
* There are **no third parties or gatekeepers**. The security of the exchange is fully ensured by:
* The cryptographic protocol (Atomic Swaps)
* Local verification through a [Light Client](/protocol/dApp) running in the User's browser
Experience TRAIN on all major network testnets, including EVM-compatible chains, Starknet, Solana, and Fuel.
Explore the core protocol concepts: Users, Solvers, Auctions, and Atomic Swaps.
Dive deeper into the protocol specification and detailed protocol design.
# Security
Source: https://docs.train.tech/protocol/security
Key security details of the TRAIN protocol
* **Homogeneous Security**: The protocol establishes consistent cryptographic security for all permissionless participants. Security attributes remain unchanged when adding new networks or Solvers.
* **Battle-Tested**: The core technology of Atomic Swaps (HTLC) has been successfully used in production for the Lightning Network.
* **No Pools**: No single contract holds large amounts of funds. This design choice significantly reduces the risk of being targeted by attackers.
* **Immutability**: The contracts are immutable. This eliminates the risks associated with upgrades.
* **Simplicity**: HTLC contracts are straightforward locking mechanisms — a single [`Train` contract](https://github.com/TrainProtocol/contracts/blob/main/chains/evm/solidity/src/Train.sol) per chain with a small surface: lock, redeem, refund.
The TRAIN contracts have not yet been externally audited. The properties above describe the protocol's design; an independent audit and bug bounty are planned before the protocol is considered production-final.
# Reward-Slash
Source: https://docs.train.tech/protocol/slashing
Incentivizing Solvers to act honestly without creating inconveniences for users
Solvers can sometimes misbehave, leading to various edge cases. For example, a Solver might refuse to release a user’s funds. While users can always manually claim their funds, ensuring no loss, this process creates significant inconvenience.
To address this, we introduce a [Reward-Slashing Mechanism](/protocol-spec/reward-slashing) to incentivize Solvers to act correctly. When locking funds for a user, the Solver also locks an additional reward amount with a timelock. If the Solver successfully transfers the user’s assets before the timelock expires, the reward is released to the Solver. However, if the Solver fails to act in time, the reward is transferred to the party that executes the function to release the user’s assets.
This mechanism serves as both an incentive for the Solver and a penalty (or "slash") for failing to fulfill their responsibility.
# The Protocol
Source: https://docs.train.tech/protocol/the-protocol
Overview of the TRAIN protocol with all main components
The TRAIN protocol consists of **two** main components:
The Bridge UI/dApp or integration in a wallet, connected to the Auction Manager. This dApp submits user intents, receives the selected Solver, and executes the atomic swap.
These are the contracts responsible for ensuring secure asset exchange between the User and Solver on different chains using HTLC with recoverable secret generation.
# Adding a New Network
Source: https://docs.train.tech/protocol/usage-add-new-network
Explains how networks can be added to the protocol
Implement [HTLC with recoverable secret generation](/protocol/atomic-swaps-secret_gen) for the new network on its own `main-add-` branch of the [contracts repo](https://github.com/TrainProtocol/contracts). Networks are developed and tested on their branch, then merged into `main` once production-track and published on the [Deployments](/deployments) page.
If there is no existing implementation (e.g., EVM), implement the Solver Agent Chain Library for the new network (functions for interacting with deployed HTLC contracts on specific chains). See the [Solver Implementation](/protocol-spec/implementation-solver) spec.
Run a Solver for two networks—one well connected to others (already active Solvers) and the new network.
If there is no existing implementation (e.g., EVM), implement the Client Chain Library for the new network (functions for interacting with wallets on specific chains, subscribing to contract events, and composing user transactions). See the [dApp Implementation](/protocol-spec/implementation-dApp) spec.
Create a pull request for a [popular bridge UI](https://testnet.train.tech/) or fork and deploy a separate UI.
These steps can be performed independently without needing permission or interaction with any party or entity — anyone can open a `main-add-` branch and start integrating a new chain. The network-adding process in the TRAIN protocol is **similar to adding an ERC20 token to the Uniswap protocol**, making bridging trustless and permissionless; a network graduates to `main` and to the [Deployments](/deployments) page once its implementation is complete and verified end-to-end. The detailed implementation steps can be found in the [Solver Implementation](/protocol-spec/implementation-solver) spec.
# Cross-Chain Swap
Source: https://docs.train.tech/protocol/usage-swap
Explains how the protocol can be used for cross-chain swaps
Send an intent to find the best Solver/price for the given source and destination.
Perform an atomic swap using [HTLC with recoverable secret generation](/protocol/atomic-swaps-secret_gen).
The TRAIN Protocol makes bridging **completely transparent and fully controllable** by the client. The integrator has complete control over every aspect, from selecting and ranking Solvers independently to performing final verification, ensuring the entire process is **trustless, transparent, and under their control**. The detailed implementation steps can be found in the [dApp Implementation](/protocol-spec/implementation-dApp) spec.
# Cross-Chain Trading
Source: https://docs.train.tech/research/cross-chain-trading
Introduces how a market can emerge around the TRAIN protocol
The **TRAIN Protocol** enables two parties to exchange assets across different blockchain networks using [HTLC with recoverable secret generation](/protocol/atomic-swaps-secret_gen). This method enables practical atomic swaps while introducing specific operational constraints that shape the type of market the protocol can realistically support. This document outlines these constraints and explains the participants and markets that emerge as a result.
***
## How the TRAIN Protocol Works
The TRAIN Protocol operates through a **sequential process**:
1. **Party 1 locks funds** for Party 2.
2. **Party 2 locks funds** for Party 1.
3. **Party 1 decides** to either:
* Release the funds and complete the trade.
* Cancel and refund.
### Key Constraints
* The total operation time is **limited to 15–20 minutes** to protect both parties.
* Under normal conditions, a transaction can complete within **1–2 minutes** if both parties act promptly.
* Both parties can **cancel the transaction at any time** before finalization without penalty (except for blockchain transaction fees).
***
## Challenges in Cross-Chain Trading
### **Market Price Fluctuations**
* **Within the 20-minute window**, market prices for assets may fluctuate:
* If the price moves **unfavorably for Party 2**, they are incentivized to cancel the trade.
* If the price moves **favorably for Party 1**, they are incentivized to proceed, disadvantaging Party 2.
### **Rational Behavior and Market Instability**
* If both parties act rationally to maximize profit:
* **No stable market equilibrium can form.**
* Trades will be canceled whenever market movements make them unprofitable for either party.
***
## A Sustainable Market: Necessity vs. Profit
A sustainable market can only exist if **one side of the trade (Party 1)** is motivated by **necessity** rather than pure profit maximization. For example:
> A person needing gasoline in an emergency may be willing to pay a slightly elevated price without overanalyzing market conditions.
### Characteristics of Participants
* **Party 1**: Acts as a **retail, non-sophisticated participant**.
* Their primary goal is to execute the trade for **practical or urgent reasons**, not financial optimization.
* **Party 2**: Acts as a **strategic actor**.
* They must offer prices that balance two factors:
1. The price must not be so unfavorable that **Party 1 refuses the trade**.
2. The price must account for **potential market fluctuations** over the next 20 minutes to ensure Party 2 still wants to complete the trade (avoiding wasted transaction fees).
***
## The TRAIN Protocol Market
The TRAIN Protocol inherently creates a **specialized type of cross-chain market**:
* A market where **Party 1 acts out of necessity** rather than trading sophistication.
* A market where **Party 2 strategically prices the trade**, accounting for volatility and transaction costs.
* A market that **cannot support active speculative traders** on both sides because the structure incentivizes trade cancellations under rational profit-seeking behavior.
***
## Conclusion
The TRAIN Protocol does not simulate traditional exchanges. Instead, it creates a **transaction environment** that prioritizes **execution certainty** over financial optimization. This unique approach enables cross-chain markets to serve users with practical needs, ensuring trades are completed even in volatile conditions.
**Key Takeaway**: The TRAIN Protocol thrives in scenarios where one party prioritizes necessity over profit, creating a stable and reliable cross-chain trading environment.