EVM Smart contracts
The Order Intent
Fundamentally, the entire iLayer network revolves around the Order intent, a struct that can encode pretty much any action you could perform on-chain.
struct Order {
bytes32 user;
bytes32 recipient;
bytes32 filler;
Token[] inputs;
Token[] outputs;
uint32 sourceChainId;
uint32 destinationChainId;
bool sponsored;
uint64 primaryFillerDeadline;
uint64 deadline;
bytes32 callRecipient;
bytes callData;
uint256 callValue;
}
We use bytes32
for what in EVM would be an address
to ensure compatibility cross-chain. You will find a handy conversion utility library called BytesUtils
in our codebase to assist you with converting from address
to bytes32
as simple as callingBytesUtils.addressToBytes32(address).
The user is the order signer, and the one from which the input tokens will be transferred from. The recipient is who will receive the tokens in output in the destination chain.
For both a smart contract account and an EOA, the order creation step will have to be preceded by a token approve transaction. We support multiple input tokens, encoded as follows
enum Type {
NULL,
NATIVE,
FUNGIBLE_TOKEN, // ERC20
NON_FUNGIBLE_TOKEN, // ERC721
SEMI_FUNGIBLE_TOKEN // ERC1155
}
struct Token {
Type tokenType;
bytes32 tokenAddress;
uint256 tokenId;
uint256 amount;
}
Token structs are identical for both inputs and outputs, we assume a non-zero array in input and a possibly null array as output. The token outputs data can be obtained by querying the RFQ network and picking the preferred quote, usually based on a combination of gas cost and pricing.
"Native" refers to the blockchain native fee token, in the case of EVM Ethereum.
The
tokenId
field is optional for ERC20
The RFQ will also return the filler param, that binds the order to the picked solver to ensure the correct execution of the received quote. If the solver doesn't fill the order within the defined primaryFillerDeadline
, then any solver in the network can pick and fill it. For this reason it is very important to correctly choose this parameter. Finally, the deadline
is the order deadline, a time after which no solver will pick the order and the user can withdraw it and the related funds from the Hub.
The chain identifier (chainId
) can be found on this website.
If the order is marked as sponsored
(sponsored ⇒ true), then the filler will execute the order creation and cover for the entire blockchain fees, usually by adding a premium to the quote to recoup the tx gas cost.
The last three parameters are optional, if not needed they can be filled with null values and essentially allow to call an arbitrary smart contract with an arbitrary call data.
bytes32 callRecipient; // destination address
bytes callData; // on EVM: abi-encoded selector + arguments
uint256 callValue; // (optional) any value to pass along
This execution hook feature can be very useful to execute DeFi actions with orders or to encode complex interactions. Ideally, an order could not have any output token but simply pay for a cross-chain code execution.
We block reentrant calls for security reasons!
Create an order
To add a new order to the iLayer network you need to get the address of the Hub contract of the source chain. Then you will need to craft the order request, the ERC2612 gasless token permits (optional) and pass the order signature.
function createOrder(
OrderRequest memory request,
bytes[] memory permits,
bytes memory signature,
IRouter.Bridge bridgeSelector,
bytes memory extra,
)
external
payable
nonReentrant
returns (bytes32 orderId, uint64 orderNonce)
The OrderRequest
is as follows
struct OrderRequest {
uint64 deadline;
uint64 nonce;
Order order;
}
It features an incremental nonce, that doesn't need to be consequent with the previous nonce used but just bigger, the request deadline after which the order won't be created anymore and finally the order itself.
It's important to store the orderId
and the orderNonce
as they are useful to withdraw the order or track its status.
The Bridge
param is an enum that depends on the chain and user bridging choice, see Router page for more.
Withdraw an order
function withdrawOrder(Order memory order, uint64 orderNonce) external nonReentrant
Simply passing the order struct and the nonce will allow the user or the smart contract account to take back funds from the Hub if the order expired. We add a small time delay to avoid the possibility of solvers filling the order and users withdrawing funds at the same time.
The order delay is more or less equal to 1 block time.
Fill an order
To fill an existing order we need to interact with the corresponding OrderSpoke
contract on the destination chain, refer to this page to find the correct address.
Last updated