LogoLogo
  • Introduction
    • What We Do
  • The DeFi Problem
  • How iLayer solves it
  • Use Cases
  • Architecture
    • RFQ
  • Hub & Spoke
    • OrderHub
    • OrderSpoke
  • Router
    • LayerZero Router
    • Axelar Router
    • NullRouter
    • AxLzRouter
  • Solvers
  • Integration
    • Industries
    • EVM Smart contracts
      • Example: cross-chain LPing on Aave
      • Example: cross-chain contract call
  • Audit
Powered by GitBook
On this page
  • The Order Intent
  • Create an order
  • Withdraw an order
  • Fill an order
Export as PDF
  1. Integration

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.

PreviousIndustriesNextExample: cross-chain LPing on Aave

Last updated 24 days ago