Token transfer Polkadot -> Ethereum

A guide on using the Snowbridge TypeScript SDK for integration.

Uses the @snowbridge/api toEthereumSnowbridgeV2 module to send the transaction. Please ensure you've completed Setup Steps before proceeding with this guide.

Pre-step: Create Transfer Impl

// Select the token you want to send. In this case we use Ether. The registry 
// contains the list of tokens.
const SOURCE_PARACHAIN = 1000
const TOKEN_CONTRACT = assetsV2.ETHER_TOKEN_ADDRESS
const transferImpl = await toEthereumSnowbridgeV2.createTransferImplementation(
    SOURCE_PARACHAIN,
    registry,
    TOKEN_CONTRACT
)

Step 1: Get Delivery Fee

The default fee asset for Snowbridge V2 is ether.

const fee = await transferImpl.getDeliveryFee(
    { SOURCE_PARACHAIN, context },
    registry,
    TOKEN_CONTRACT
)

If you would like to use another fee asset, pass the fee location as an extra option:

import { xcmBuilder } from "@snowbridge/api"
// Use DOT as fee asset
const feeTokenLocation = xcmBuilder.DOT_LOCATION
fee = await transferImpl.getDeliveryFee(
    { SOURCE_PARACHAIN, context },
    registry,
    TOKEN_CONTRACT,
    { feeTokenLocation, slippagePadPercentage: 20n }
)

Step 2: Create Transfer

The createTransfer() function generates a transfer object, which includes source and destination accounts, the amount to send, the token being transferred and the precomputed delivery fee. This object contains all data necessary to execute the cross-chain transfer and is later used for validation and signing.

const amount = 15_000_000_000_000n // 0.000015 ETH
const transfer = await transferImpl.createTransfer(
    { sourceParaId: SOURCE_PARACHAIN, context }, // The context and source parachain
    registry, // The asset registry
    POLKADOT_ACCOUNT_PUBLIC, // The source account
    ETHEREUM_ACCOUNT_PUBLIC, // The destination account
    TOKEN_CONTRACT, // The transfer token
    amount, // The transfer amount
    fee // The fee
)

Step 3: Validate Transfer

Although optional, validateTransfer() is strongly recommended. It performs local checks and dry-runs the transaction (when possible) to ensure:

  • The sender has enough funds

  • The asset is supported

  • The constructed transaction will succeed on-chain

This step can save users from wasting gas or fees on transactions that would otherwise revert.

const validation = await transferImpl.validateTransfer(context, transfer)

if (validation.logs.find((l) => l.kind == toEthereumSnowbridgeV2.ValidationKind.Error)) {
    throw Error(`validation has one of more errors.`)
}

Step 4: Send Transaction

Finally, the transaction is signed and submitted to the source chain. Use the SDK helper signAndSend() which manages construction, signing, and submission of the extrinsic.

const response = await toEthereumSnowbridgeV2.signAndSend(
    context,
    transfer,
    POLKADOT_ACCOUNT,
    {
        withSignedTransaction: true,
    }
)
if (!response) {
    throw Error(`Transaction ${response} not included.`)
}
console.log(
    `Success message with message id: ${response.messageId}
    block number: ${response.blockNumber}
    tx hash: ${response.txHash}`
)

Last updated