Wallet/Frontend Integration

Snowbridge V1: Transfer token from Ethereum to Polkadot

!! Note: We are in process of simplifying our API. The current snippets below will be simplified for better DevEx soon.

Asset Registry

The first step is to get the Snowbridge asset registry. It is a list of assets that may be transferred between chains. The list is a static file hosted in @snowbridge/registry.

1import { assetRegistryFor } from "@snowbridge/registry";
2
3// Configuration - Use 'polkadot_mainnet' for production, 'paseo_sepolia' for 
4// testnet
5const environmentName = "polkadot_mainnet";
6
7// Get the asset registry for the environment
8const registry = assetRegistryFor(environmentName);

Setup Context

Set the context, containing connections to all the required chains.

1const snowbridgeEnv = environment.SNOWBRIDGE_ENV[environmentName];
2
3if (!snowbridgeEnv) {
4	throw new Error(`Unknown environment '${environmentName}'`);
5}
6
7// Build the context from registry options
8const context = new Context({
9	environment: environmentName,
10	ethereum: {
11		ethChainId: snowbridgeEnv.ethChainId,
12		ethChains: Object.fromEntries(
13			Object.keys(snowbridgeEnv.config.ETHEREUM_CHAINS).map(chainId => [
14				chainId,
15				snowbridgeEnv.config.ETHEREUM_CHAINS[chainId](ethApiKey)
16			])
17		),
18		beacon_url: snowbridgeEnv.config.BEACON_HTTP_API,
19	},
20	polkadot: {
21		assetHubParaId: registryOptions.assetHubParaId,
22		bridgeHubParaId: registryOptions.bridgeHubParaId,
23		relaychain: registryOptions.relaychain,
24		parachains: snowbridgeEnv.config.PARACHAINS,
25	},
26	appContracts: {
27		gateway: registryOptions.gatewayAddress,
28		beefy: snowbridgeEnv.config.BEEFY_CONTRACT,
29	},
30});

Step 1: Get Delivery Fee

Before sending a transaction, calculate the delivery fee.

1const deliveryFee = await toPolkadotV2.getDeliveryFee(
2	{
3    	gateway: context.gateway(),
4    	assetHub: await context.assetHub(),
5    	destination: await context.parachain(destinationParaId),
6	},
7	registry,
8	tokenAddress,
9	destinationParaId
10);

Step 2: Create Transfer

Create the transfer object.

1const transfer = await toPolkadotV2.createTransfer(
2	registry,
3	ethereumAddress,
4	polkadotAddress,
5	tokenAddress,
6	destinationParaId,
7	transferAmount,
8	deliveryFee
9);

Step 3: Validate Transfer

Validate the transfer. This dry runs the transaction on all relevant chains to ensure the transaction will succeed. This step is crucial to ensure no funds are lost when the transaction is done.

1const validation = await toPolkadotV2.validateTransfer(
2	{
3    	ethereum: context.ethereum(),
4    	gateway: context.gateway(),
5    	bridgeHub: await context.bridgeHub(),
6    	assetHub: await context.assetHub(),
7    	destParachain: destinationParaId !== 1000
8    		? await context.parachain(destinationParaId)
9    		: undefined,
10	},
11	transfer
12);
13
14// Check for validation errors
15const errors = validation.logs.filter(log =>
16	log.kind === toPolkadotV2.ValidationKind.Error
17);
18
19if (errors.length > 0) {
20	console.error("❌ Validation errors:", errors);
21	throw new Error("Transfer validation failed");
22}

Step 4: Estimate Gas Cost

Calculate the gas that should be sent with the transaction.

1 const { tx, computed: { totalValue } } = transfer;
2 const estimatedGas = await context.ethereum().estimateGas(tx);
3 const feeData = await context.ethereum().getFeeData();
4 const executionFee = (feeData.gasPrice ?? 0n) * estimatedGas;

Step 5: Send Transaction

1const response = await ETHEREUM_ACCOUNT.sendTransaction(tx)
2const receipt = await response.wait(1)
3if (!receipt) {
4	throw Error(`Transaction ${response.hash} not included.`)
5}
6
7const message = await toPolkadotV2.getMessageReceipt(receipt)
8if (!message) {
9	throw Error(`Transaction ${receipt.hash} did not emit a message.`)
10}
11console.log(
12	`Success message with message id: ${message.messageId}
13	block number: ${message.blockNumber}  
14	tx hash: ${message.txHash}`
15)

Parachains

Parachains who would like to integrate with Snowbridge need to meet certain requirements to integrate. Teams are encouraged to reach out on Telegram for additional support from our team, since each parachain is different and might require specific changes. Please log an issue on Snowfork/snowbridge to get in touch.

Snowbridge V1

For the first version of Snowbridge, parachains need to ensure that:

  • XCM config
    • AssetHub is configured as a DOT reserve (example)
    • AssetHub is configured to be the reserve for foreign assets (example)
  • Install crates:
  • HRMP Channels
    • Ensure the parachain and AssetHub have an open HRMP channel

Snowbridge V2

Snowbridge V2 is set to go live in August 2025. It relies heavily on pallet-xcm::execute. Documentation will be added closer to the launch of V2.

Trustless bridging for Web3 teams