Page cover

Proxy Call

The GeniusProxyCall is a multi-call aggregation contract that enables the execution of complex cross-chain operations, token swaps, and arbitrary contract calls in a single transaction. It serves as the execution engine for the Genius bridge protocol, allowing orchestrators to perform intricate operations like swapping stablecoins for other tokens and executing custom logic on destination chains.

The contract provides a secure and efficient way to bundle multiple operations together, reducing gas costs and improving user experience. It supports token approvals, swaps, transfers, and arbitrary contract calls while maintaining strict access controls and comprehensive error handling.

The GeniusProxyCall contract - overview

The GeniusProxyCall contract is a non-upgradeable contract that implements a comprehensive multi-call system. It allows authorized callers to execute complex sequences of operations including token approvals, swaps, transfers, and arbitrary contract calls in a single transaction.

The contract inherits from MultiSendCallOnly for batch transaction processing and implements AccessControl for secure role management. It provides a flexible interface for orchestrating complex cross-chain operations while maintaining security and efficiency.

The GeniusProxyCall contract - key features

Multi-call aggregation

The contract enables the execution of multiple operations in a single transaction, significantly reducing gas costs and improving efficiency for complex cross-chain operations.

Token approval and execution

Supports automatic token approvals for external contracts, execution of the target operation, and cleanup of approvals to maintain security.

Swap and call operations

Combines token swaps with arbitrary contract calls, allowing for complex operations like swapping stablecoins for other tokens and then executing custom logic.

Native token support

Fully supports native token (ETH) operations alongside ERC20 tokens, providing flexibility for different blockchain networks.

Role-based access control

Implements strict access controls where only authorized callers (orchestrators) can execute operations, preventing unauthorized access and potential exploits.

Comprehensive error handling

Provides detailed error messages and validation for all operations, ensuring reliable execution and clear debugging.

Batch operations

Supports batch processing of multiple tokens and operations, enabling efficient handling of complex scenarios.

Security-first design

Implements security best practices including contract validation, approval cleanup, and safe token transfers.

Understanding the workflow of GeniusProxyCall

  1. Authorization: Only addresses with CALLER_ROLE or the contract itself can execute operations.

  2. Operation Execution: The contract supports various operation types:

    • Simple contract calls via execute()

    • Complex swap and call operations via call()

    • Token approval and execution via approveTokenExecute()

    • Batch token operations via approveTokensAndExecute()

  3. Token Management: The contract handles token approvals, transfers, and balance management automatically.

  4. Result Processing: Operations return execution results, effective token addresses, and amounts for further processing.

  5. Cleanup: Approvals are automatically cleaned up after execution to maintain security.

Core functions and their purposes

Complex Swap and Call Operations

GeniusProxyCall.sol
function call(
    address receiver,
    address swapTarget,
    address callTarget,
    address stablecoin,
    address tokenOut,
    uint256 minAmountOut,
    bytes calldata swapData,
    bytes calldata callData
)
    external
    override
    onlyCallerOrSelf
    returns (
        address effectiveTokenOut,
        uint256 effectiveAmountOut,
        bool success
    )
{
    bool isSwap = swapTarget != address(0);
    bool isCall = callTarget != address(0);

    uint256 stablecoinBalance = IERC20(stablecoin).balanceOf(address(this));
    effectiveAmountOut = stablecoinBalance;
    effectiveTokenOut = stablecoin;
    success = true;

    if (isSwap) {
        bytes memory wrappedSwapData = abi.encodeWithSelector(
            IGeniusProxyCall.approveTokenExecuteAndVerify.selector,
            stablecoin,
            swapTarget,
            swapData,
            tokenOut,
            minAmountOut,
            isCall ? address(this) : receiver
        );
        bytes memory returnData;
        (success, returnData) = address(this).call(wrappedSwapData);
        if (success) {
            effectiveTokenOut = tokenOut;
            effectiveAmountOut = abi.decode(returnData, (uint256));
        } else {
            IERC20(stablecoin).safeTransfer(receiver, stablecoinBalance);
            return (stablecoin, stablecoinBalance, success);
        }
    }

    if (isCall) {
        bytes memory wrappedCallData = abi.encodeWithSelector(
            IGeniusProxyCall.transferTokenAndExecute.selector,
            tokenOut,
            callTarget,
            callData
        );

        (success, ) = address(this).call{value: address(this).balance}(
            wrappedCallData
        );
    }

    // Transfer final balances to receiver
    if (effectiveTokenOut != NATIVE_TOKEN) {
        uint256 balance = IERC20(effectiveTokenOut).balanceOf(address(this));
        if (balance != 0)
            IERC20(effectiveTokenOut).safeTransfer(receiver, balance);
    }

    return (effectiveTokenOut, effectiveAmountOut, success);
}

Token Approval and Execution with Verification

GeniusProxyCall.sol
function approveTokenExecuteAndVerify(
    address token,
    address target,
    bytes calldata data,
    address tokenOut,
    uint256 minAmountOut,
    address expectedTokenReceiver
) external payable override onlyCallerOrSelf returns (uint256) {
    uint256 balancePreSwap;
    uint256 balancePostSwap;
    bool isNativeOut = tokenOut == NATIVE_TOKEN;

    if (isNativeOut) {
        balancePreSwap = address(expectedTokenReceiver).balance;
        _approveTokenAndExecute(token, target, data);
        balancePostSwap = address(expectedTokenReceiver).balance;
    } else {
        balancePreSwap = IERC20(tokenOut).balanceOf(expectedTokenReceiver);
        _approveTokenAndExecute(token, target, data);
        balancePostSwap = IERC20(tokenOut).balanceOf(expectedTokenReceiver);
    }

    uint256 amountOut = balancePostSwap - balancePreSwap;
    if (amountOut < minAmountOut)
        revert GeniusErrors.InvalidAmountOut(amountOut, minAmountOut);
    else return amountOut;
}

Batch Token Operations

GeniusProxyCall.sol
function _approveAddressAndExecute(
    address[] memory tokens,
    address target,
    bytes calldata data,
    address toApprove
) internal {
    if (target == address(0)) revert GeniusErrors.NonAddress0();
    if (!_isContract(target)) revert GeniusErrors.TargetIsNotContract();
    if (!_isContract(toApprove))
        revert GeniusErrors.ApprovalTargetIsNotContract();

    if (target == address(this)) {
        (bool _success, ) = target.call{value: msg.value}(data);
        if (!_success) revert GeniusErrors.ExternalCallFailed(target);
    } else {
        uint256 tokensLength = tokens.length;
        for (uint256 i; i < tokensLength; i++) {
            IERC20(tokens[i]).approve(toApprove, type(uint256).max);
        }

        (bool _success, ) = target.call{value: msg.value}(data);
        if (!_success) revert GeniusErrors.ExternalCallFailed(target);

        for (uint i; i < tokensLength; i++) {
            IERC20(tokens[i]).approve(toApprove, 0);
        }
    }
}

Simple Contract Execution

GeniusProxyCall.sol
function execute(
    address target,
    bytes calldata data
) external payable override onlyCallerOrSelf {
    if (target == address(0)) revert GeniusErrors.NonAddress0();
    if (!_isContract(target)) revert GeniusErrors.TargetIsNotContract();

    (bool _success, ) = target.call{value: msg.value}(data);
    if (!_success) revert GeniusErrors.ExternalCallFailed(target);
}

Operation types and use cases

Simple Execution

  • Purpose: Execute arbitrary contract calls

  • Use case: Simple operations that don't require token management

  • Function: execute()

Swap Operations

  • Purpose: Swap tokens using external DEX protocols

  • Use case: Converting stablecoins to other tokens on destination chains

  • Function: approveTokenExecuteAndVerify()

Swap and Call

  • Purpose: Combine token swaps with custom logic execution

  • Use case: Complex DeFi operations requiring multiple steps

  • Function: call()

Batch Operations

  • Purpose: Execute operations with multiple tokens

  • Use case: Complex protocols requiring multiple token approvals

  • Function: approveTokensAndExecute()

Transfer and Execute

  • Purpose: Transfer tokens and execute custom logic

  • Use case: Protocols that require token deposits before execution

  • Function: transferTokenAndExecute()

Security features

Access Control

The contract implements strict role-based access control:

  • Admin: Can manage roles and configuration

  • Caller: Can execute operations (typically orchestrators)

  • Self: The contract can call itself for internal operations

Contract Validation

All target addresses are validated to ensure they are actual contracts, preventing calls to EOA addresses.

Approval Management

Token approvals are automatically cleaned up after execution to prevent potential security issues.

Safe Token Transfers

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

Error Handling

Comprehensive error handling with custom errors provides clear feedback for debugging and monitoring.

Native Token Support

Proper handling of native tokens (ETH) alongside ERC20 tokens with appropriate balance checks.

Integration with other contracts

The GeniusProxyCall interacts with several other contracts in the Genius ecosystem:

  • GeniusVault: Called by the vault for order execution

  • DEX Protocols: Various decentralized exchanges for token swaps

  • DeFi Protocols: External protocols for complex operations

  • Token Contracts: ERC20 tokens for transfers and approvals

Key state variables

  • NATIVE_TOKEN: Constant address representing native tokens (ETH)

  • CALLER_ROLE: Role identifier for authorized callers

  • DEFAULT_ADMIN_ROLE: Role identifier for administrators

Events

The contract inherits events from the interfaces and emits various events for operation tracking:

  • ExternalCallFailed: When external contract calls fail

  • InvalidAmountOut: When swap output doesn't meet minimum requirements

  • InvalidCaller: When unauthorized addresses attempt operations

  • TargetIsNotContract: When target address is not a contract

Operation flow examples

Simple Token Swap

  1. User creates order to swap USDC for ETH

  2. Vault calls call() with swap target (DEX)

  3. Contract approves USDC for DEX

  4. Executes swap on DEX

  5. Verifies minimum output amount

  6. Transfers ETH to receiver

  7. Cleans up approvals

Complex DeFi Operation

  1. User creates order for complex DeFi operation

  2. Vault calls call() with both swap and call targets

  3. Contract swaps stablecoin for protocol token

  4. Transfers protocol token to DeFi contract

  5. Executes custom logic on DeFi contract

  6. Returns any remaining tokens to receiver

Error handling and validation

Input Validation

  • Target address must be non-zero

  • Target must be a contract

  • Caller must have appropriate role

  • Token addresses must be valid

Execution Validation

  • External calls must succeed

  • Swap outputs must meet minimum requirements

  • Token transfers must complete successfully

Security Checks

  • Approvals are cleaned up after use

  • Native token balances are properly handled

  • Contract state is validated before operations

The GeniusProxyCall is a critical component of the Genius bridge protocol, providing the execution engine for complex cross-chain operations. Its sophisticated multi-call capabilities, security features, and flexible interface enable the protocol to support a wide range of DeFi operations while maintaining efficiency and security.

Last updated