15 KiB
BridgeEndpoint
- Location:
xlink/packages/contracts/bridge-solidity/contracts - Deployed contracts: See Ethereum Contract Addresses.
This technical document provides a detailed overview of the Bridge Endpoint in EVM-compatible blockchains. The Bridge Endpoint facilitates communication between two blockchain networks by acting as the entry and exit point for assets moving along the Cross Chain Bridge. It passes messages between chains in the form of events, triggers contract calls, processes token transfers and validates and executes the unwrapping of tokens. The Bridge Endpoint functionality is implemented across two contracts, BridgeEndpoint and BridgeEndpointWithSwap. BridgeEndpointWithSwap extends BridgeEndpoint and implements the necessary functionality to source liquidity from external aggregators.
This functionality is implemented and distributed across the following contracts:
BridgeEndpoint: the base contract that facilitates bridging operations.BridgeEndpointWithSwap: extendsBridgeEndpointand integrates swaps during a bridge transfer.
Storage
registry
| Data | Type |
|---|---|
| Variable | BridgeRegistry |
Stores a reference to the BridgeRegistry contract, which manages approved tokens, relayers, and validators.
pegInAddress
| Data | Type |
|---|---|
| Variable | address |
The address from which non-burnable tokens are transferred during peg-in operations.
timeLock
| Data | Type |
|---|---|
| Variable | ITimeLock |
Manages locked transactions that require a delay before execution. Tokens amounts that exceed the threshold are not immediately sent to the user. Instead, the timeLock contract holds them until the waiting period expires and then releases the tokens, completing the transfer.
timeLockThreshold
| Data | Type |
|---|---|
| Variable | uint256 |
The global minimum token amount that triggers a timelock. By default, the value is set to 0.
timeLockThresholdByToken
| Data | Type |
|---|---|
| Variable | mapping(address => uint256) |
Optional custom timelock thresholds for different tokens. The timelock will be triggered when a token amount exceeds the custom threshold, if applicable. If no custom threshold is set, the token amount will need to exceed the global threshold set in timeLockThreshold.
unwrapSent
| Data | Type |
|---|---|
| Variable | mapping(bytes32 => OrderPackage) |
Stores unwrap orders that need to be finalized. It stores a mapping of OrderPackage structs, which contain a flag indicating whether the unwrap has been completed. bytes32 is a unique hash of the struct parameters, as calculated by transferToUnwrap.
swapExecutor
(only present in BridgeEndpointWithSwap)
| Data | Type |
|---|---|
| Variable | SwapExecutor |
Holds a reference to SwapExecutor, which is the contract that executes swaps.
swapSent
(only present in BridgeEndpointWithSwap)
| Data | Type |
|---|---|
| Variable | mapping(bytes32 => SwapOrderPackage) |
A mapping of SwapOrderPackage structs that contains details of swap orders.bytes32 is a unique hash of the swap parameters, as calculated by transferToSwap.
Data Types
OrderPackage
Holds details of a pending unwrap operation.
struct OrderPackage {
address recipient;
address token;
uint256 amount;
bool sent;
}
SignaturePackage
Contains signatures from validators to prove an order is legitimate. It is used for verifying cross-chain transfers.
struct SignaturePackage {
bytes32 orderHash;
address signer;
bytes signature;
}
SwapOrderPackage
(only present in BridgeEndpointWithSwap)
A struct that stores details of a swap order.
struct SwapOrderPackage {
address target;
address tokenIn;
address tokenOut;
uint256 amountIn;
uint256 amountOutMin;
bytes bridgePayloadSuccess;
bytes bridgePayloadFailure;
bool sent;
}
Modifiers
onlyApprovedToken(token): ensures the token is approved in the registry.onlyApprovedRelayer(): ensures the caller is an approved relayer.notWatchlist(recipient): prevents transfers to watchlisted addresses.nonReentrant: protects against reentrancy attacks.onlyAllowlisted: ensures only allowed addresses can execute certain functions.
Features
sendMessageWithToken
This function is called to initiate the peg-out process from an EVM-compatible blockchain onto other chains, such as Stacks or Solana. The user deposits tokens in the bridge contract, which are burned or locked, depending on the token. The contract checks that the token is approved, since sendMessageWithToken has the onlyApprovedToken modifier. The function calls _transfer, which performs validations. Finally, the function emits a SendMessageWithTokenEvent containing the transaction details, which will be reviewed by validators. Once they verify that the tokens were deposited in the BridgeEndpoint contract, the validators will sign the order and relayers will submit it in the destination chain.
Parameters
address token,
uint256 amount,
bytes calldata payload
sendMessage
Emits an event with a message.
Parameters
bytes calldata payload
transferToUnwrap
This function is called by a relayer when a user initiates a token transfer from another blockchain. The originating order may come from an EVM chain (via sendMessageWithToken), or from a non-EVM chain like Stacks or Solana. Relayers listen for the corresponding event on the source chain and call transferToUnwrap on the destination chain, supplying the recipient, token, amount, a salt (usually the source chain order hash), and an array of validator signatures (proofs). The contract verifies these proofs and generates an EIP-712-compliant hash, which acts as a unique identifier for each transfer.
Parameters
address token,
address recipient,
uint256 amount,
bytes32 salt,
SignaturePackage[] calldata proofs
finalizeUnwrap
This function completes a pending unwrap order for non-burnable tokens. It is called by a relayer once the timeLock period expires and the recipient can receive their locked tokens. It loops through each orderHash and calls _finalizeUnwrap(), which verifies that the order has not already been completed and transfers the token and amount stored in unwrapSent to the recipient. The order is then marked as completed, and the FinalizeUnwrapEvent is emitted.
Parameters
bytes32[] calldata orderHash
transferToSwap
(in contract BridgeEndpointWithSwap)`
This function executes a swap before bridging tokens. If the token is burnable, the contract mints the required amount before swapping, calls _executeSwap to perform the swap and emits a TransferToSwapEvent recording the details. If it is not burnable, it saves swap details in the swapSent mapping and emits SwapOrderCreated so the swap can be finalized later. In either case, the function will validate token and relayer permissions and generate a unique EIP-712 hash to identify the swap.
Parameters
address target,
address tokenIn,
address tokenOut,
uint256 amountIn,
uint256 amountOutMin,
bytes calldata swapPayload,
bytes calldata bridgePayloadSuccess,
bytes calldata bridgePayloadFailure,
bytes32 salt,
SignaturePackage[] calldata proofs
finalizeSwap
(in contract BridgeEndpointWithSwap)`
This function is used when a token is not burnable, leading transferToSwap to store the swap order instead of executing it immediately. It ensures input arrays are valid, and it loops through each orderHash and calls _finalizeSwap().
Parameters
bytes32[] calldata orderHashes,
bytes[] calldata swapPayloads
Governance Features
setTimeLock
Updates the contract managing timelocks.
Parameters
address _timeLock
setTimeLockThreshold
Sets the global timelock threshold.
Parameters
uint256 _timeLockThreshold
setTimeLockThresholdByToken
Sets a custom timelock threshold per token.
Parameters
address token,
uint256 _timeLockThreshold
addAllowList
Adds an address to the allowlist, granting it permission to perform specific contract actions.
removeAllowedList
Removes an address from the allowlist, revoking its access.
Parameters
address account
pause
Pauses the contract, preventing token transfers until the contract is unpaused.
unpause
Resumes contract operations after a pause, allowing bridging and transfers again.
Read-Only Functions
offAllowList
Returns true if the provided address is not on the allowlist.
Parameters
address account
onAllowList
Returns true if the provided address is on the allowlist, which means it has permission to use the contract’s functions.
Relevant Internal Functions
_transfer
This internal function is responsible for processing token transfers when a user sends tokens into the bridge. It is called from sendMessageWithToken and performs validations, calculates and deducts fees, and sends the remaining amount to the receiver. This function ensures the transfer amount is within allowed limits and that it is large enough to cover the minimum fee. If the token is burnable, if burns the amount minus the fee, which is sent to the BridgeRegistry contract.
Parameters
address token,
uint256 amount
_validateOrder
Verifies if an order is legitimate by checking validator signatures.
Parameters
bytes32 orderHash,
SignaturePackage[] calldata proofs
_finalizeUnwrap
Completes an unwrap transaction by transferring tokens to the recipient.
Parameters
bytes32 orderHash
_finalizeSwap
(in contract BridgeEndpointWithSwap)`
This function is called by finalizeSwap to retrieve a stored swap order and to execute the swap. It checks if the order exists and has not been executed, transfers amountIn tokens from the sender to the BridgeEndpointWithSwap contract and calls _executeSwap to perform the swap. Finally, it marks the order as sent and emits a SwapOrderFinalized event.
Parameters
bytes32 orderHash,
bytes memory swapPayload
_executeSwap
(in contract BridgeEndpointWithSwap)`
This function approves swapExecutor to spend tokenIn and calls its executeSwap() function to attempt the swap. If the swap succeeds, it either burns the swapped tokens or prepares them for transfer. To transfer the tokens, tokenOut is sent to pegInAddress for bridging and a SendMessageWithTokenEvent is emitted. If the swap fails, the error is logged via SwapExecutorError, approvals are revoked and a SendMessageWithTokenEvent with bridgePayloadFailure is emitted. In either case, the function will burn tokenIn tokens if applicable.
Parameters
address tokenIn,
address tokenOut,
address target,
uint256 amountIn,
uint256 amountOutMin,
bytes memory swapPayload,
bytes memory bridgePayloadSuccess,
bytes memory bridgePayloadFailure
Events
SendMessageEvent
Emitted when a user sends a message without transferring tokens.
Parameters
address indexed from,
uint256 value,
bytes payload
SendMessageWithTokenEvent
Emitted when a user initiates a peg-out order.
Parameters
address indexed from,
address indexed token,
uint256 amount,
uint256 fee,
bytes payload
TransferToUnwrapEvent
Emitted when an order is created to unwrap tokens. This event is emitted when an order is validated and tokens have to be transfered to a recipient.
Parameters
bytes32 orderHash,
bytes32 salt,
address indexed recipient,
address indexed token,
uint256 amount
FinalizeUnwrapEvent
Emitted when an unwrap order is finalized and tokens are successfully transferred to the recipient.
Parameters
bytes32 indexed orderHash
SetTimelockEvent
Emitted when timeLock is updated by the contract owner.
Parameters
address timeLock
SetTimeLockThresholdEvent
Emitted when the global time lock threshold is updated.
Parameters
uint256 timeLockThreshold
SetTimeLockThresholdByTokenEvent
Emitted when the time lock threshold for a specific token is updated.
Parameters
address token,
uint256 timeLockThreshold
SwapExecutorError
(only present in BridgeEndpointWithSwap)
Emitted when a swap operation fails during the bridge transfer.
Parameters
address indexed target,
bytes reason
SwapOrderCreated
(only present in BridgeEndpointWithSwap)
Emitted when a new swap order is created for non-burnable tokens. It logs the creation of swap orders, helping to track them before execution.
Parameters
bytes32 indexed orderHash,
address indexed target,
address indexed tokenIn,
address tokenOut,
uint256 amountIn,
uint256 amountOutMin,
bytes bridgePayloadSuccess,
bytes bridgePayloadFailure
SwapOrderFinalized
(only present in BridgeEndpointWithSwap)
Emitted when a swap order is executed and finalized, confirming a swap has been processed.
Parameters
bytes32 indexed orderHash,
address indexed executor,
uint256 amountOut,
bool success
TransferToSwapEvent
(only present in BridgeEndpointWithSwap)
Emitted when a token transfer and swap operation is executed.
Parameters
bytes32 orderHash,
address target,
bytes swapPayload,
address tokenIn,
address tokenOut,
uint256 amountIn,
uint256 amountOut,
bool success
Contract Calls (Interactions)
BridgeRegistry: this contract is called to process orders and to manage validator roles and fees. It acts as the central registry for approved tokens, relayers and validators.ITimeLock: theITimeLockinterface is utilized to interact with thetimeLockcontract by calling thecreateAgreementfunction when bridged amounts exceeds the threshold.IBurnable: this interface is used for burnable tokens to enable mint and burn operations.ERC20: all approved tokens within the bridge must implement theERC20Fixedstandard, which is an XLink's custom standard that extends ERC-20 to handle fixed precision. Token contract interactions occur in both peg-in and peg-out operations for non-burnable tokens, using thetransferFromFixed,transferFixed, andincreaseAllowanceFixedfunctions.SwapExecutor: this contract is called byBridgeEndpointWithSwapto execute swaps with external liquidity aggregators during bridging.