Skip to main content
Stargate protocol contracts (StargatePool and StargateOFT) implement the standard IOFT interface for Omnichain Fungible Tokens (OFTs), making crosschain transfers straightforward with just two methods: quoteSend() and send(). For architecture and concepts, see Stargate Finance.

Stargate Asset Deployments

View all available Stargate pools and OFT deployments across chains on the OFT Ecosystem & Stargate Assets page. Find contract addresses, supported chains, and asset types for seamless integration.

The IOFT Interface

All Stargate pool and HydraOFT contracts implement the same interface:
interface IStargate is IOFT {
    // Get underlying token address
    function token() external view returns (address);

    // Check if approval is required before sending
    function approvalRequired() external view returns (bool);

    // Quote the crosschain transfer fee
    function quoteSend(
        SendParam calldata _sendParam,
        bool _payInLzToken
    ) external view returns (MessagingFee memory);

    // Send tokens crosschain
    function send(
        SendParam calldata _sendParam,
        MessagingFee calldata _fee,
        address _refundAddress
    ) external payable returns (MessagingReceipt memory, OFTReceipt memory);
}
Helper Methods:
  • token(): Returns the underlying ERC20 token address (or address(0) for native assets like ETH)
  • approvalRequired(): Returns true if you need to approve tokens before sending, false for mint/burn or native assets
These methods allow you to write generic code that works with any Stargate asset (USDC pools, ETH pools, Hydra OFTs) without hardcoding token addresses or approval logic.

Interactive Interface Methods

quoteSend() - Get Transfer Fees

quoteOFT() - Get Detailed Transfer Quote

send() - Transfer Tokens

SendParam Structure

The key parameters for Stargate transfers is identical to OFT transfers:
struct SendParam {
    uint32 dstEid;          // Destination endpoint ID
    bytes32 to;             // Recipient address
    uint256 amountLD;       // Amount to send (local decimals)
    uint256 minAmountLD;    // Minimum amount (slippage protection)
    bytes extraOptions;     // Execution options for LayerZero
    bytes composeMsg;       // For composability (Taxi mode only)
    bytes oftCmd;           // "" for Taxi, bytes(1) for Bus
}

How send() Works

When you call send() on a Stargate contract, it triggers a chain of calls through LayerZero’s infrastructure: Call Flow:
  1. Stargate Contract → Debits tokens (lock or burn depending on contract type)
  2. LayerZero Endpoint → Routes the message to the configured MessageLib
  3. Message Library (SendUln302) → Requests quotes from DVNs and Executor
  4. Workers (DVNs + Executor) → Provide fee quotes for verification and execution
  5. Fee Aggregation → Returns total nativeFee from all workers
This multi-step process is why quoteSend() exists - it aggregates fees from all components in the security stack.

Quote Freshness

Call quoteSend() as close as possible to send() execution. Fee quotes can become stale due to:
  • Changing gas prices on source/destination chains
  • Price feed updates for crosschain gas estimation
  • DVN fee adjustments
In production, quote and send in the same transaction or block to ensure accurate fees.

Transfer Modes

Stargate supports two transfer modes with different characteristics:

Taxi Mode (Immediate)

Use when: You need immediate transfer or composability Set: oftCmd: "" Supports: Composability via composeMsg to trigger actions on destination
SendParam memory sendParam = SendParam({
    dstEid: dstEid,
    to: bytes32(uint256(uint160(recipient))),
    amountLD: amount,
    minAmountLD: amount * 995 / 1000,  // 0.5% slippage
    extraOptions: "",                   // Or compose options
    composeMsg: "",                     // Or encoded compose message
    oftCmd: ""                          // Empty for Taxi mode
});

Bus Mode (Batched)

Use when: You want gas savings and don’t need composability Set: oftCmd: new bytes(1) Does NOT support: Composability - no lzCompose() will be triggered
SendParam memory sendParam = SendParam({
    dstEid: dstEid,
    to: bytes32(uint256(uint160(recipient))),
    amountLD: amount,
    minAmountLD: amount * 995 / 1000,
    extraOptions: new bytes(0),
    composeMsg: new bytes(0),
    oftCmd: new bytes(1)                // bytes(1) for Bus mode
});

Composability Requirement

Composable strategies (e.g., Omnichain Vaults) require Taxi mode. Bus mode will not trigger lzCompose() calls.

Basic Transfer Example

Note: These examples assume you’re using existing Stargate contracts (pre-configured by the Stargate team). If deploying your own OFT, you must complete the configuration steps first - see OFT Quickstart - Deployment and Wiring. Since Stargate implements IOFT, sending tokens works exactly like any OFT - the only Stargate-specific aspect is the oftCmd field for Taxi vs Bus mode:
// Taxi Mode (immediate, supports composability)
SendParam memory sendParam = SendParam({
    dstEid: dstEid,
    to: bytes32(uint256(uint160(recipient))),
    amountLD: amount,
    minAmountLD: amount * 995 / 1000,
    extraOptions: "",
    composeMsg: "",
    oftCmd: ""  // Empty for Taxi mode
});

// Bus Mode (batched, no composability)
SendParam memory sendParam = SendParam({
    dstEid: dstEid,
    to: bytes32(uint256(uint160(recipient))),
    amountLD: amount,
    minAmountLD: amount * 995 / 1000,
    extraOptions: new bytes(0),
    composeMsg: new bytes(0),
    oftCmd: new bytes(1)  // bytes(1) for Bus mode
});

// Then call: IOFT(stargateAddress).send(sendParam, fee, refundAddress)
For complete send implementation: See OFT Quickstart - Send Tokens for detailed examples using CLI, Foundry scripts, or Hardhat tasks.

Composability

Taxi mode supports composability - triggering additional actions on the destination chain after Stargate assets arrive. Key Points:
  • Set composeMsg to your encoded data
  • Set to address to your composer contract
  • Add addExecutorLzComposeOption() for composer gas
  • Your composer receives via lzCompose() and decodes with OFTComposeMsgCodec
// Quick example: Send USDC with compose
bytes memory composeMsg = abi.encode(finalRecipient, action, params);
bytes memory extraOptions = OptionsBuilder.newOptions()
    .addExecutorLzComposeOption(0, 200_000, 0);

SendParam memory sendParam = SendParam({
    to: bytes32(uint256(uint160(composerAddress))),  // Your composer
    composeMsg: composeMsg,                          // Your data
    extraOptions: extraOptions,                      // Compose gas
    oftCmd: ""  // Must use Taxi mode
    // ... other fields
});
For complete composability implementation:

Finding Stargate Contracts

Method 1: Deployed Contracts Page

  1. Visit Deployed Contracts
  2. Search for your chain or asset (e.g., “USDC”, “Ethereum”)
  3. Stargate contracts appear at the top of each chain’s list
  4. Copy the address you need

Method 2: Stargate API

// Mainnet
const response = await fetch('https://mainnet.stargate-api.com/v1/metadata?version=v2');
const data = await response.json();

// Find USDC on Ethereum
const asset = data.data.v2.find((a) => a.chainKey === 'ethereum' && a.token.symbol === 'USDC');

console.log('StargatePool USDC:', asset.address);

Next Steps

Learn More: Build: Get Help: