EcoCross Settlement Integration

The future of interoperability is intents and EcoCross Settlement is the only production-ready, modular settlement layer built to facilitate cross-chain intents. The EcoCross Bridge and EcoCross+ products build on top of EcoCross Settlement to offer bridging to users and bridge abstraction to dApp developers.

With EcoCross Settlement, any other application or source of cross-chain intent order flow can leverage EcoCross Settlement to enable the fastest speeds and lowest fees for their interoperability use-case.

Integrating EcoCross Settlement into Your Application

This guide contains an examples for how to build on top of EcoCross Settlement

If you have further questions or suggestions for this guide, please send a message to the #developer-questions channel in the EcoCross Telegram.

EcoCross Settlement Example

EcoCross Settlement is a very flexible system, so this example won't capture all that you can do. However, it should illustrate the types of integrations that are possible.

Architecture

The example application we're going to build has the following architecture:

  1. User asks for a quote on a cross-chain swap from an offchain RFQ system.

  2. Market-maker-relayers bid on the opportunity to fill the user.

  3. The user signs the winning bid as a Permit2 order.

  4. The Permit2 order is passed to the winning market-maker-relayer.

  5. The market-maker-relayer sends a transaction where this order is put onchain.

  6. In that transaction, the user's funds are pulled via Permit2. A bond is submitted by the market-maker-relayer in the transaction as well in the same currency as the user's funds.

  7. An EcoCross deposit is created. The bond + user funds are set as the input amount. The market-maker-relayer is set as the exclusive relayer, so they are the only relayer who can submit the relay on the destination.

This tutorial will not implement the offchain components, but it will show a sample contract implementation for the contract that processes the Permit2 order.

Sample Implementation

Note: the implementation below has not been vetted, validated, or optimized in any way. It is purely meant as an illustrative example. Use this sample code at your own risk. See the comments in the code to understand what each portion of the code is doing.

Copy

import {IPermit2} from "permit2/src/interfaces/IPermit2.sol";
import {IERC20} from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "openzeppelin-contracts/contracts/token/ERC20/utils/SafeTransferFrom.sol";

// EcoCross SpokePool Interface
interface EcoCrossV3SpokePool {
  function depositV3(
    address depositor,
    address recipient,
    address inputToken,
    address outputToken,
    uint256 inputAmount,
    uint256 outputAmount,
    uint256 destinationChainId,
    address exclusiveRelayer,
    uint32 quoteTimestamp,
    uint32 fillDeadline,
    uint32 exclusivityDeadline,
    bytes calldata message
  ) external;
}

// Sample cross-chain order
struct CrossChainOrder {
  address rfqContract;
  address swapper;
  address relayer;
  address recipient;
  address inputToken;
  address outputToken;
  uint256 inputAmount;
  uint256 relayerBondAmount;
  uint256 outputAmount;
  uint256 destinationChainId;
  uint256 nonce;
  uint256 deadline;
}

// A typestring is required for Permit2 to be able to process the order as witness data.
string constant ORDER_WITNESS_TYPESTRING = "CrossChainOrder witness)CrossChainOrder(address rfqContract,address swapper,address relayer,address recipient,address inputToken,address outputToken,uint256 inputAmount,uint256 relayerBondAmount,uint256 outputAmount,uint256 destinationChainId,uint256 nonce,uint256 deadline)";

contract RFQSwapper {
  using SafeERC20 for IERC20;

  IPermit2 public immutable permit2;
  EcoCrossV3SpokePool public immutable spokePool;
  
  constructor(address _permit2, address _spokePool) {
    permit2 = Permit2(_permit2);
    spokePool = EcoCrossV3SpokePool(_spokePool);
  }
  
  // The initiate function:
  // 1. Takes in an order and swapper signature.
  // 2. Verifies the signature and order validity.
  // 3. Passes along the tokens and instructions to the EcoCross SpokePool
  //    where the order will be filled, that fill verified, and then settled.
  function initiate(CrossChainOrder memory order, bytes calldata signature) {
    // This code is the basic process for validating and pulling in tokens
    // for a Permit2-based order.
    // It's somewhat involved, but it does most of the work in validating the
    // order and signature.
    permit2.permitWitnessTransferFrom(
      // PermitTransferFrom struct init
      IPermit2.PermitTransferFrom({
        permitted: IPermit2.TokenPermissions({
          token: order.inputToken,
          amount: order.inputAmount
        }),
        nonce: order.nonce,
        deadline: order.deadline
      }),
      // SignatureTransferDetails struct init
      IPermit2.SignatureTransferDetails({
        to: address(this),
        requestedAmount: order.inputAmount
      }),
      order.swapper,
      keccak256(abi.encode(order));
      ORDER_WITNESS_TYPESTRING,
      signature
    );
    
    // Pull in the bond from the msg.sender.
    IERC20(order.inputToken).safeTransferFrom(msg.sender, order.relayerBondAmount);
    
    // Full input amount for EcoCross's purposes both the user amount
    // and the bond amount.
    // In the case that the relay is filled correctly, the relayer
    // gets the full input amount (including the bond).
    // In the case that the depositor is refunded, they receive the bond
    // as compensation for the relayer's failure to fill.
    uint256 amount = order.inputAmount + order.relayerBondAmount;
    
    // Now that all the tokens are in this contract, EcoCross contract needs
    // to be approved to pull the tokens from here.
    IERC20(order.inputToken).safeIncreaseAllowance(address(spokePool), amount);
    
    // Fill deadline is arbitrarily set to 1 hour after initiation.
    uint256 fillDeadline = block.timestamp + 3600;
    
    // Call deposit to pass the order off to EcoCross Settlement.
    spokePool.deposit(
      order.swapper,
      order.recipient,
      order.inputToken,
      order.outputToken,
      order.inputAmount,
      order.outputAmount,
      order.destinationChainId,
      order.relayer,
      block.timestamp,
      fillDeadline, // 1 hour deadline
      fillDeadline, // Exclusivity for the entire fill period
      "" // No message
    );
  }
}

Conclusion

As is shown in the example above, EcoCross Settlement can be used as a tool to verify cross-chain intent fulfillment in many different setups. The primary advantage is that the integrating protocol can abstract away the complexity of the verification and fulfillment, so they don't have to deal with the security, timing, and asynchrony challenges of building a cross-chain system.

EcoCross Settlement provides additional advantages over naive cross-chain settlement systems, which ultimately lead to better execution of intent fulfillment for users and relayers:

  1. Aggregated and Optimistic Verification: The EcoCross Settlement system aggregates valid fills events off-chain to create a repayment bundle, which is then optimistically verified by UMA's Optimistic Oracle. This verification and repayment mechanism scales gas cost of repayment at O(1) instead of O(N) with the number of fills. This offers an order of magnitude in gas savings vs. other approaches and ultimately leads to better pricing for users and more profit for relayers.

  2. Relayer Cross-chain Management: With EcoCross’ settlement architecture, repayment is made on the relayer’s chain of choice, reducing overhead and complexity of managing cross-chain positions. This lowers costs for relayers, enabling better pricing and execution for end-users. It is enabled by EcoCross’ Hub and Spoke model, where passive LPs extend loans to relayers for taking on time-value risk as funds are rebalanced through canonical bridges by the protocol.

Last updated