Page cover

Genius Router

The GeniusRouter is a contract that simplifies the process of creating cross-chain orders in the Genius bridge protocol. It provides convenient functions for users to swap tokens and create bridge orders in a single transaction, with optional Permit2 integration for gasless approvals and enhanced user experience.

The router acts as a bridge between users and the core vault functionality, handling token transfers, swaps, and order creation in a streamlined manner. It supports both traditional token approvals and gasless Permit2 transactions, making it accessible to a wide range of users and wallet types.

The GeniusRouter contract - overview

The GeniusRouter contract is an immutable contract that serves as the primary user interface for the Genius bridge protocol. It integrates with the vault, proxy call, fee collector, and Permit2 contracts to provide a seamless experience for creating cross-chain orders.

The contract handles the complexity of token management, fee calculation, and order creation, allowing users to focus on their desired cross-chain operations rather than the underlying technical details.

The GeniusRouter contract - key features

Integrated swap and order creation

The router allows users to swap tokens and create cross-chain orders in a single transaction, eliminating the need for multiple separate transactions and reducing gas costs.

Permit2 integration

Supports gasless token approvals through Uniswap's Permit2 system, enabling users to create orders without requiring pre-approved token allowances.

Flexible token input

Supports multiple input tokens in a single transaction, allowing users to swap various tokens for stablecoins before creating bridge orders.

Automatic fee calculation

Integrates with the fee collector to automatically calculate and include the appropriate fees for cross-chain orders based on destination chain and order size.

Proxy call integration

Leverages the GeniusProxyCall contract for executing complex swap operations and ensuring secure token transfers.

Immutable architecture

Uses immutable state variables for critical contract addresses, ensuring security and preventing unauthorized modifications.

User-friendly interface

Provides simple, intuitive functions that abstract away the complexity of the underlying protocol while maintaining full functionality.

Comprehensive error handling

Implements detailed error messages and validation to help users understand and resolve any issues with their transactions.

Understanding the workflow of GeniusRouter

  1. Token Input: Users provide input tokens either through direct transfers or Permit2 permits.

  2. Token Swapping: The router executes swaps using the proxy call contract to convert input tokens to stablecoins.

  3. Fee Calculation: The fee collector calculates the appropriate fees for the destination chain and order size.

  4. Order Creation: The router creates a cross-chain order with the vault using the swapped stablecoins.

  5. Order Execution: The order is then executed by orchestrators on the destination chain.

Core functions and their purposes

Swap and Create Order

GeniusRouter.sol
function swapAndCreateOrder(
    bytes32 seed,
    address[] calldata tokensIn,
    uint256[] calldata amountsIn,
    address target,
    address toApprove,
    bytes calldata data,
    address owner,
    uint256 destChainId,
    uint256 feeSurplus,
    bytes32 receiver,
    uint256 minAmountOut,
    bytes32 tokenOut
) public payable override {
    if (tokensIn.length != amountsIn.length)
        revert GeniusErrors.ArrayLengthsMismatch();

    // Transfer input tokens to proxy call
    for (uint256 i = 0; i < tokensIn.length; i++) {
        if (msg.sender != address(PROXYCALL)) {
            IERC20(tokensIn[i]).safeTransferFrom(
                msg.sender,
                address(PROXYCALL),
                amountsIn[i]
            );
        }
    }

    // Execute swap operation
    if (target == address(PROXYCALL))
        PROXYCALL.execute{value: msg.value}(target, data);
    else
        PROXYCALL.approveAddressAndExecute{value: msg.value}(
            tokensIn,
            target,
            data,
            toApprove
        );

    uint256 delta = STABLECOIN.balanceOf(address(this));

    // Calculate fees
    IFeeCollector.FeeBreakdown memory feeBreakdown = FEE_COLLECTOR
        .getOrderFees(delta, destChainId);

    // Create order
    IGeniusVault.Order memory order = IGeniusVault.Order({
        seed: seed,
        trader: VAULT.addressToBytes32(owner),
        receiver: receiver,
        tokenIn: VAULT.addressToBytes32(address(STABLECOIN)),
        tokenOut: tokenOut,
        amountIn: delta,
        minAmountOut: minAmountOut,
        destChainId: destChainId,
        srcChainId: block.chainid,
        fee: feeBreakdown.totalFee + feeSurplus
    });

    VAULT.createOrder(order);
}

Permit2 Swap and Create Order

GeniusRouter.sol
function swapAndCreateOrderPermit2(
    bytes32 seed,
    IAllowanceTransfer.PermitBatch calldata permitBatch,
    bytes calldata permitSignature,
    address target,
    address toApprove,
    bytes calldata data,
    uint256 destChainId,
    uint256 feeSurplus,
    bytes32 receiver,
    uint256 minAmountOut,
    bytes32 tokenOut
) public payable override {
    address owner = msg.sender;

    // Handle Permit2 token transfers
    address[] memory tokensIn = _permitAndBatchTransfer(
        permitBatch,
        permitSignature,
        owner
    );

    // Execute swap operation
    if (target == address(PROXYCALL))
        PROXYCALL.execute{value: msg.value}(target, data);
    else
        PROXYCALL.approveAddressAndExecute{value: msg.value}(
            tokensIn,
            target,
            data,
            toApprove
        );

    uint256 delta = STABLECOIN.balanceOf(address(this));

    // Calculate fees and create order
    IFeeCollector.FeeBreakdown memory feeBreakdown = FEE_COLLECTOR
        .getOrderFees(delta, destChainId);

    IGeniusVault.Order memory order = IGeniusVault.Order({
        seed: seed,
        trader: VAULT.addressToBytes32(owner),
        receiver: receiver,
        tokenIn: VAULT.addressToBytes32(address(STABLECOIN)),
        tokenOut: tokenOut,
        amountIn: delta,
        minAmountOut: minAmountOut,
        destChainId: destChainId,
        srcChainId: block.chainid,
        fee: feeBreakdown.totalFee + feeSurplus
    });

    VAULT.createOrder(order);
}

Permit2 Order Creation

GeniusRouter.sol
function createOrderPermit2(
    bytes32 seed,
    IAllowanceTransfer.PermitBatch calldata permitBatch,
    bytes calldata permitSignature,
    uint256 destChainId,
    uint256 fee,
    bytes32 receiver,
    uint256 minAmountOut,
    bytes32 tokenOut
) external payable override {
    address owner = msg.sender;
    if (permitBatch.details.length != 0)
        revert GeniusErrors.ArrayLengthsMismatch();
    if (permitBatch.details[0].token != address(STABLECOIN))
        revert GeniusErrors.InvalidTokenIn();

    // Transfer stablecoins using Permit2
    _permitAndBatchTransfer(permitBatch, permitSignature, owner);

    uint256 delta = STABLECOIN.balanceOf(address(this));

    // Create order directly with stablecoins
    IGeniusVault.Order memory order = IGeniusVault.Order({
        seed: seed,
        trader: VAULT.addressToBytes32(owner),
        receiver: receiver,
        tokenIn: VAULT.addressToBytes32(address(STABLECOIN)),
        tokenOut: tokenOut,
        amountIn: delta,
        minAmountOut: minAmountOut,
        destChainId: destChainId,
        srcChainId: block.chainid,
        fee: fee
    });

    VAULT.createOrder(order);
}

Permit2 Token Transfer Helper

GeniusRouter.sol
function _permitAndBatchTransfer(
    IAllowanceTransfer.PermitBatch calldata permitBatch,
    bytes calldata permitSignature,
    address owner
) private returns (address[] memory tokensIn) {
    tokensIn = new address[](permitBatch.details.length);
    if (permitBatch.spender != address(this))
        revert GeniusErrors.InvalidSpender();

    // Execute permit
    PERMIT2.permit(owner, permitBatch, permitSignature);

    // Prepare transfer details
    IAllowanceTransfer.AllowanceTransferDetails[]
        memory transferDetails = new IAllowanceTransfer.AllowanceTransferDetails[](
            permitBatch.details.length
        );
    for (uint i; i < permitBatch.details.length; i++) {
        tokensIn[i] = permitBatch.details[i].token;
        transferDetails[i] = IAllowanceTransfer.AllowanceTransferDetails({
            from: owner,
            to: address(PROXYCALL),
            amount: permitBatch.details[i].amount,
            token: permitBatch.details[i].token
        });
    }

    // Execute transfers
    PERMIT2.transferFrom(transferDetails);
}

Function types and use cases

Traditional Token Approvals

  • Function: swapAndCreateOrder()

  • Use case: Users who prefer traditional token approvals

  • Process: Direct token transfers followed by swap and order creation

Gasless Permit2 Operations

  • Function: swapAndCreateOrderPermit2()

  • Use case: Users wanting gasless token approvals

  • Process: Permit2 signature validation followed by swap and order creation

Direct Stablecoin Orders

  • Function: createOrderPermit2()

  • Use case: Users with stablecoins wanting direct bridge orders

  • Process: Permit2 stablecoin transfer followed by order creation

Integration with other contracts

The GeniusRouter integrates with several core contracts in the Genius ecosystem:

  • GeniusVault: Creates cross-chain orders

  • GeniusProxyCall: Executes swap operations

  • FeeCollector: Calculates order fees

  • Permit2: Handles gasless token approvals

  • Stablecoin: The underlying stablecoin for bridge operations

Key state variables

  • STABLECOIN: The stablecoin token used for bridge operations

  • VAULT: The GeniusVault contract for order creation

  • PERMIT2: The Permit2 contract for gasless approvals

  • PROXYCALL: The GeniusProxyCall contract for swap execution

  • FEE_COLLECTOR: The FeeCollector contract for fee calculation

Security features

Immutable Architecture

All critical contract addresses are immutable, preventing unauthorized modifications and ensuring contract integrity.

Input Validation

Comprehensive validation of input parameters including:

  • Array length matching

  • Valid token addresses

  • Proper spender addresses

  • Sufficient token amounts

Safe Token Transfers

All token transfers use SafeERC20 to prevent common token-related vulnerabilities.

Permit2 Security

Proper validation of Permit2 signatures and spender addresses to prevent unauthorized token transfers.

Native Token Protection

The contract rejects direct native token transfers to prevent accidental fund loss.

User experience features

Single Transaction Operations

Users can swap tokens and create bridge orders in a single transaction, reducing gas costs and improving convenience.

Gasless Approvals

Permit2 integration allows users to create orders without requiring pre-approved token allowances, saving gas and improving user experience.

Flexible Token Support

Supports multiple input tokens, allowing users to bridge various assets by first converting them to stablecoins.

Automatic Fee Handling

Fees are automatically calculated and included, eliminating the need for users to manually determine appropriate fee amounts.

Clear Error Messages

Comprehensive error handling provides clear feedback when transactions fail, helping users understand and resolve issues.

Order creation process

Step 1: Token Input

  • Users provide input tokens through direct transfers or Permit2 permits

  • Multiple tokens can be provided in a single transaction

Step 2: Token Swapping

  • Input tokens are transferred to the proxy call contract

  • Swaps are executed to convert tokens to stablecoins

  • Swap operations can target any DEX or DeFi protocol

Step 3: Fee Calculation

  • The fee collector calculates appropriate fees based on:

    • Destination chain

    • Order amount

    • Current fee tiers

Step 4: Order Creation

  • A cross-chain order is created with the vault

  • Order includes all necessary parameters for execution

  • Order is queued for processing by orchestrators

Error handling and validation

Input Validation

  • Array lengths must match

  • Token addresses must be valid

  • Spender addresses must be correct

  • Permit signatures must be valid

Operation Validation

  • Token transfers must succeed

  • Swap operations must complete

  • Fee calculations must be valid

  • Order creation must succeed

Security Checks

  • Native tokens are rejected

  • Unauthorized spenders are blocked

  • Invalid permits are rejected

The GeniusRouter is a critical user-facing component of the Genius bridge protocol, providing a simple and efficient interface for creating cross-chain orders. Its integration with Permit2, support for complex swaps, and automatic fee handling make it accessible to users of all technical levels while maintaining the security and functionality of the underlying protocol.

Last updated