Skip to main content

Overview

CallProxy executes arbitrary smart contract calls on behalf of cross-chain messages. It provides context about the original sender and chain, enabling secure cross-chain interactions. Contract Location: contracts/periphery/CallProxy.sol

Key Features

  • Execute contract calls with cross-chain context
  • Support for both native ETH and ERC-20 token transfers
  • Fallback handling for failed calls
  • Reentrancy protection
  • Multi-send support for batched operations

Context Variables

submissionChainIdFrom
uint256
Chain ID where the cross-chain message originated
submissionNativeSender
bytes
Original sender address on the source chain (encoded as bytes)
These context variables are available to the target contract during execution, allowing it to verify the cross-chain caller.

Main Functions

call

Executes a contract call with native ETH.
function call(
    address _reserveAddress,
    address _receiver,
    bytes memory _data,
    uint256 _flags,
    bytes memory _nativeSender,
    uint256 _chainIdFrom
) external payable returns (bool _result)
_reserveAddress
address
required
Address to receive leftover funds if call fails
_receiver
address
required
Target contract to call
_data
bytes
required
Encoded function call data
_flags
uint256
required
Execution flags (revert behavior, sender proxying, etc.)
_nativeSender
bytes
required
Original sender on source chain
_chainIdFrom
uint256
required
Source chain ID

callERC20

Executes a contract call with ERC-20 tokens.
function callERC20(
    address _token,
    address _reserveAddress,
    address _receiver,
    bytes memory _data,
    uint256 _flags,
    bytes memory _nativeSender,
    uint256 _chainIdFrom
) external returns (bool _result)

Usage Example

Target contracts can access the cross-chain context:
Accessing Context
contract MyContract {
    ICallProxy public callProxy;
    
    function handleCrossChainCall() external {
        // Get original sender from source chain
        bytes memory nativeSender = callProxy.submissionNativeSender();
        address sender = abi.decode(nativeSender, (address));
        
        // Get source chain ID
        uint256 chainId = callProxy.submissionChainIdFrom();
        
        // Verify the caller is authorized
        require(sender == authorizedSender && chainId == expectedChain);
        
        // Execute logic...
    }
}

Execution Flags

Flags control execution behavior:
  • REVERT_IF_EXTERNAL_FAIL: Revert entire transaction if target call fails
  • PROXY_WITH_SENDER: Provide native sender context to target contract
  • SEND_HASHED_DATA: Send hashed data instead of full calldata
  • SEND_EXTERNAL_CALL_GAS_LIMIT: Allow custom gas limits
Setting Flags
using Flags for uint256;

uint256 flags = uint256(0)
    .setFlag(Flags.REVERT_IF_EXTERNAL_FAIL, true)
    .setFlag(Flags.PROXY_WITH_SENDER, true);

Multi-Send Support

CallProxy supports batched transactions:
Batch Execution
bytes memory transactions = abi.encodePacked(
    // Transaction 1
    uint8(0),           // operation (0 = call)
    target1,            // to address
    value1,             // ETH value
    dataLength1,        // data length
    data1,              // calldata
    
    // Transaction 2
    uint8(0),
    target2,
    value2,
    dataLength2,
    data2
);

callProxy.multiSend(transactions);
Multi-send operations are atomic — if any transaction fails, all are reverted.

Security Considerations

  • Reentrancy protection via lock modifier
  • Only callable by DeBridgeGate
  • Excess funds returned to reserve address
  • Token approvals cleared after execution

Cross-Chain Calls Guide

Learn how to implement cross-chain calls

ICallProxy Interface

Interface reference

Build docs developers (and LLMs) love