WDK logoWDK documentation
USD₮0 bridgeFrom SolanaGuides

Bridge Tokens

Quote and send USD₮ from Solana to EVM, TON, and TRON recipients, confirm the transaction, and cap fees.

This guide covers standard Solana accounts: prerequisites, how to quote bridge fees, send the bridge, confirm it, use the right recipient format, and set bridgeMaxFee. For an account that holds no SOL, see Bridge with a gasless account.

Prerequisites

Complete Get Started: an account from new WalletAccountSolana(seed, path, config?) and a bridge from new Usdt0ProtocolSolana(account, config?). The account's RPC must point at Solana mainnet.

The account needs two balances:

  • USD₮ for the amount. The quote does not read this balance, so check it with getTokenBalance() first.
  • SOL for fee and bridgeFee, both paid from this account.

There is no approval step. Do not look for a spender address, because the bridge transaction moves the tokens directly.

Quote bridge fees

You can estimate fees without sending a transaction using quoteBridge(). A quote also confirms that the route has capacity for the amount:

Quote before bridging
const USDT_MINT = 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB'

const options = {
  targetChain: 'arbitrum',
  recipient: process.env.ARBITRUM_RECIPIENT,
  token: USDT_MINT,
  amount: 1000000n // 1 USDt, 6 decimals
}

const quote = await bridgeProtocol.quoteBridge(options)

console.log('Solana transaction fee:', quote.fee, 'lamports')
console.log('LayerZero fee:', quote.bridgeFee, 'lamports')

bridgeFee does not depend on the amount. It does depend on the destination, as the table below shows.

Send the bridge

You can send the transfer by calling bridge() with the same options. Amount 1000000n is 1 USD₮:

Bridge USDt to Arbitrum
const result = await bridgeProtocol.bridge(options)

console.log('Solana transaction hash:', result.hash)
console.log('Solana transaction fee:', result.fee, 'lamports')
console.log('LayerZero fee:', result.bridgeFee, 'lamports')

bridge() builds and quotes the transaction again when it runs, so an earlier quote does not bind the fee. Use bridgeMaxFee to bound it.

The recipient receives the amount less the Legacy Mesh fee, which neither method reports.

Confirm the bridge

bridge() returns once the transaction is submitted. Wait for it on Solana with waitForTransaction():

Confirm on Solana
const receipt = await account.waitForTransaction(result.hash)

if (receipt.success !== true) {
  throw new Error('Bridge transaction did not succeed')
}

A timeout does not prove that the transaction failed. Check the hash before retrying, so you do not bridge twice.

Solana confirmation does not prove settlement on the destination. Verify the destination balance before spending the bridged funds.

Recipient formats

quoteBridge() and bridge() validate recipient against the target chain before any fee is paid. A failure reads Invalid recipient address for target chain '<chain>': <REASON>.

targetChainFormatCommon reasons
ethereum, arbitrum, celoHex address. Mixed case must carry a valid checksum.INVALID_FORMAT, INVALID_CHECKSUM, ZERO_ADDRESS
tonUser-friendly or raw address on workchain 0INVALID_FORMAT, INVALID_CHECKSUM, UNSUPPORTED_WORKCHAIN, ZERO_ADDRESS
tronBase58Check address, starting with TINVALID_FORMAT, INVALID_PREFIX, INVALID_CHECKSUM, ZERO_ADDRESS
Bridge USDt to TON and TRON
const tonResult = await bridgeProtocol.bridge({
  targetChain: 'ton',
  recipient: process.env.TON_RECIPIENT,
  token: USDT_MINT,
  amount: 1000000n
})

const tronResult = await bridgeProtocol.bridge({
  targetChain: 'tron',
  recipient: process.env.TRON_RECIPIENT,
  token: USDT_MINT,
  amount: 1000000n
})

Cap fees with bridgeMaxFee

You can pass bridgeMaxFee to the constructor, or per call as the second argument of bridge(). On a standard account, bridge() rejects when fee + bridgeFee is greater than the cap, in lamports. A total equal to the cap is allowed. quoteBridge() does not enforce it.

Cap fees for one bridge
const result = await bridgeProtocol.bridge(options, {
  bridgeMaxFee: 2_000_000n // 0.002 SOL
})

The LayerZero fee differs widely by destination, so size the cap per route. These mainnet quotes were sampled on November 2, 2026, and they move with destination gas prices:

DestinationbridgeFee in lamportsAbout
Arbitrum799,0310.0008 SOL
Celo809,9800.0008 SOL
TON1,157,4180.0012 SOL
Ethereum6,614,0310.0066 SOL
TRON119,003,2280.119 SOL

fee was 5,000 lamports on each route.

A single cap of 10_000_000n (0.01 SOL) accepts the first four routes and rejects TRON. An account also needs that much SOL available, so check its balance against the quote for the route you use.

Next Steps

Bridge without holding SOL in Bridge with a gasless account, or harden your integration with Handle errors.


Need Help?

On this page