Skip to main content

Swap native coins cross-chain

Learn how to use the Balanced contracts to swap between native coins on supported blockchains.

You can interact with the Balanced smart contracts to swap native coins between blockchains. In this guide, you’ll learn how to query contract data, calculate the swap amounts, and encode the payload to swap AVAX on Avalanche for ETH on Base.

Get the source code

For more details and advanced configurations, view the source code, documentation, and examples in the Balanced Examples repository.

Prerequisites

To use this guide, you’ll need a basic understanding of Solidity, smart contract interactions, and cross-chain transaction formats.

Here are the values you’ll need to swap AVAX on Avalanche for ETH on Base:

ItemValue
xCall contract address on AVAX0xfC83a3F252090B26f92F91DFB9dC3Eb710AdAf1b
xCall Manager contract address on AVAX0xDccd213951D8214fBACa720728474E2cEf9d247B
Asset Manager contract address on AVAX0xdf851B4f0D9b2323e03B3980b1C4Cf56273c0bd9
Balanced Router contract address on ICONcx21e94c08c03daee80c25d8ee3ea22a20786ec231
Pool ID for AVAX/bnUSD pool0x46
Pool ID for ETH/bnUSD pool0x3b
Network ID for Avalanche0xa86a.avax
Network ID for Base0x2105.base
Network ID for ICON0x1.icon

You’ll also need the ABI for these contracts:

1. Query the contract data

  1. Call the getProtocols() method on the xCall Manager contract on the source chain (Avalanche).

  2. Call the getFee(string _net, bool _rollback, string[] _sources) method on the xCall contract on the source chain (Avalanche).

  • _net is the network label of the destination chain
  • _rollback is a boolean that indicates if the transaction should roll back if it fails
  • _sources is the array list obtained from the getProtocols() method

2. Calculate the swap amounts

We can now calculate the required amount of AVAX to send (swap amount + fee):

  1. Call the getPoolStats(string id) method on the DEX contract to get the pool information for AVAX/bnUSD and ETH/bnUSD. Learn how to query a liquidity pool.

  2. Use the pool prices to calculate the amount of ETH to receive after slippage:

  • ETH amount = (AVAX amount x AVAX/bnUSD price) ÷ (ETH/bnUSD price)
  • ETH to receive = ETH amount - (ETH amount x slippage)

3. Encode the payload

It’s time to encode the payload for the transaction. The payload is a list of values encoded with RLP that uses this format:

[
'_swap', // operation identifier for Balanced
NETWORK_ADDRESS_OF_RECEIVER,
MIN_AMOUNT_TO_RECEIVE,
[ 1, SMART_CONTRACT_OF_BNUSD_TOKEN ],
[ 1, SMART_CONTRACT_OF_ETH_TOKEN ],
]
  • NETWORK_ADDRESS_OF_RECEIVER is the recipient wallet address. Use the NETWORK_ID/WALLET_ADDRESS format, e.g. 0x2105.base/0xf963B069aDCbc094cFe2500a668C1399aeC8F803.

  • MIN_AMOUNT_TO_RECEIVE is the minimum amount of ETH to receive after the swap, calculated in the previous step.

  • The [ #, SMART_CONTRACT_OF_TOKEN ] variables are the path for the swap. Our AVAX > ETH example will swap AVAX for bnUSD, then bnUSD for ETH.

    Each step in the swap path is an array with two values. The first value is an identifier that indicates whether to swap from the liquidity pool (1) or the Stability Fund on ICON (2). (2 is only necessary for swaps that involve a stablecoin other than bnUSD.) The second value is the smart contract address of the token on ICON.

Here’s an example of the payload before RLP encoding:

[
'_swap',
'0x2105.base/0xf963B069aDCbc094cFe2500a668C1399aeC8F803',
424273912089887,
[ 1, 'cx88fd7df7ddff82f7cc735c871dc519838cb235bb' ],
[ 1, 'cx288d13e1b63563459a2ac6179f237711f6851cb5' ]
]

The encoded payload is added to the data field of the transaction. The value field should be set to the amount of AVAX to swap.

4. Initiate the swap

Send the transaction by calling the depositNative method on the Asset Manager contract on the source chain (Avalanche).

depositNative(
uint256 amount,
string to,
bytes data
)
  • amount is the amount of AVAX required for the swap and transaction fees
  • to is the address of the Balanced Router contract on the ICON blockchain
  • data is the encoded payload

{
'amount': '0x2386f26fc10000',
'to': '0x1.icon/cx21e94c08c03daee80c25d8ee3ea22a20786ec231',
'data': '0xf871855f73776170b3307833382e6273632f3078663936334230363961444362633039346346653235303061363638433133393961654338463830338617fd480a8205d701950188fd7df7ddff82f7cc735c871dc519838cb235bbd70195012d552c485ec8bcaa75aac02424e2aca6ffdb2f1b'
}

Once the transaction has been sent, it will automatically route through the ICON blockchain and complete the swap.