WDK logoWDK documentation

Bridge USD₮0 EVM API Reference

Complete API documentation for @tetherto/wdk-protocol-bridge-usdt0-evm

Table of Contents

ClassDescriptionMethods
Usdt0ProtocolEvmMain class for bridging USD₮0 tokens across blockchains. Extends BridgeProtocol from @tetherto/wdk-wallet/protocols.Constructor, Methods

Usdt0ProtocolEvm

The main class for bridging USD₮0 tokens across different blockchains using the LayerZero protocol. Extends BridgeProtocol from @tetherto/wdk-wallet/protocols.

Constructor

new Usdt0ProtocolEvm(account, config?)

Parameters:

  • account (WalletAccountEvm | WalletAccountEvmErc4337 | WalletAccountReadOnlyEvm | WalletAccountReadOnlyEvmErc4337): The wallet account to use for bridge operations
  • config (BridgeProtocolConfig, optional): Configuration object
    • bridgeMaxFee (number | bigint, optional): Rejects bridge() when the implementation's combined fee value is at or above this cap

Example:

import Usdt0ProtocolEvm from '@tetherto/wdk-protocol-bridge-usdt0-evm'
import { WalletAccountEvm } from '@tetherto/wdk-wallet-evm'

const account = new WalletAccountEvm(seedPhrase, "0'/0/0", {
  provider: 'https://eth.drpc.org'
})

const bridgeProtocol = new Usdt0ProtocolEvm(account, {
  bridgeMaxFee: 1000000000000000n // Standard Ethereum account: source native base units
})

Methods

MethodDescriptionReturnsThrows
bridge(options, config?)Bridges tokens to another blockchainPromise<BridgeResult>If no provider or the combined fee is at or above the cap
quoteBridge(options, config?)Estimates the cost of a bridge operationPromise<Omit<BridgeResult, 'hash'>>If no provider
getSupportedChains()Returns chain descriptors from bundled configurationPromise<SwidgeSupportedChain[]>
getSupportedTokens(options?)Returns configured USD₮0 or XAU₮0 descriptors, with optional filtersPromise<SwidgeSupportedToken[]>

bridge(options, config?)

Bridges tokens to a different blockchain using the USD₮0 protocol.

With a standard EVM account, approve the source-chain bridge spender before calling bridge(). If you pass oftContractAddress, use the same address as the approval spender. Supported ERC-4337 accounts do not need a separate approval call; the protocol bundles an approval and helper call into one UserOperation.

Parameters:

  • options (BridgeOptions): Bridge operation options
    • targetChain (string): Destination chain name
    • recipient (string): Address that will receive the bridged tokens (EVM hex address, Solana base58 address, TON address, or TRON address)
    • token (string): Token contract address on source chain
    • amount (number | bigint): Amount to bridge in token base units
    • oftContractAddress (string, optional): Custom OFT contract address to use instead of auto-resolving from the source chain
    • dstEid (number, optional): Custom LayerZero destination endpoint ID override
  • config (Erc4337BridgeConfig, optional): ERC-4337 gas-payment overrides plus optional bridgeMaxFee
    • bridgeMaxFee (number | bigint, optional): Override maximum bridge fee

Returns: Promise<BridgeResult> - Bridge operation result

Throws:

  • Error if account is read-only
  • Error if no provider is configured
  • Error if the combined fee value is equal to or greater than bridgeMaxFee

Example:

// Standard EVM account
const standardBridgeProtocol = new Usdt0ProtocolEvm(standardAccount)

await standardAccount.approve({
  token: '0x...', // USDT contract address
  spender: '0x...', // OFT or bridge spender address
  amount: 1000000n
})

const result = await standardBridgeProtocol.bridge({
  targetChain: 'arbitrum',
  recipient: '0x...', // Recipient address
  token: '0x...', // ₮ contract address
  amount: 1000000n,
  oftContractAddress: '0x...' // Same address used as approval spender
})

console.log('Bridge hash:', result.hash)
console.log('Account transaction fee:', result.fee)
console.log('Bridge fee:', result.bridgeFee)

// ERC-4337 account: approval is bundled automatically
const erc4337BridgeProtocol = new Usdt0ProtocolEvm(erc4337Account)

const result2 = await erc4337BridgeProtocol.bridge({
  targetChain: 'arbitrum',
  recipient: '0x...', // Recipient address
  token: '0x...', // USDT contract address
  amount: 1000000n,
  oftContractAddress: '0x...' // Optional custom OFT contract
}, {
  paymasterToken: { address: '0x...' } // Paymaster token configuration
})

console.log('Bridge hash:', result2.hash) // Single hash for bundled operations
console.log('Account fee:', result2.fee)
console.log('Bridge fee:', result2.bridgeFee)

quoteBridge(options, config?)

Estimates the cost of a bridge operation without executing it.

For standard EVM accounts, some providers estimate the same bridge transaction that bridge() sends. If that estimate fails because token allowance is missing, approve the source-chain bridge spender before calling quoteBridge(). ERC-4337 quotes include the bundled approval transaction.

Parameters:

  • options (BridgeOptions): Bridge operation options (same as bridge method)
  • config (Erc4337QuoteConfig, optional): ERC-4337 gas-payment overrides

Returns: Promise<Omit<BridgeResult, 'hash'>> - Bridge cost estimate

Throws: Error if no provider is configured

Standard-account example:

const quote = await bridgeProtocol.quoteBridge({
  targetChain: 'polygon',
  recipient: '0x...', // Recipient address
  token: '0x...', // USDT contract address
  amount: 1000000n
})

console.log('Estimated transaction fee:', quote.fee)
console.log('Bridge fee:', quote.bridgeFee)

// Check if fees are acceptable
if (quote.fee + quote.bridgeFee >= 1000000000000000n) {
  console.log('Bridge fees too high')
} else {
  // Proceed with bridge
  await account.approve({
    token: '0x...', // USDT contract address
    spender: '0x...', // OFT or bridge spender address
    amount: 1000000n
  })

  const result = await bridgeProtocol.bridge({
    targetChain: 'polygon',
    recipient: '0x...', // Recipient address
    token: '0x...', // USDT contract address
    amount: 1000000n,
    oftContractAddress: '0x...' // Same address used as approval spender
  })
}

getSupportedChains()

Returns the chain descriptors from the package's bundled configuration. This method does not make a network request.

const chains = await bridgeProtocol.getSupportedChains()
// [{ id: 'ethereum', name: 'Ethereum', type: 'evm', nativeToken: 'ETH' }, ...]

getSupportedTokens(options?)

Returns USD₮0 and XAU₮0 descriptors for chains that have a matching bridge contract in bundled configuration. Optional fromChain or toChain filters accept a chain key, chain ID, or endpoint ID. fromToken filters by token symbol.

const allTokens = await bridgeProtocol.getSupportedTokens()
const ethereumTokens = await bridgeProtocol.getSupportedTokens({
  fromChain: 'ethereum'
})
const xaut0Tokens = await bridgeProtocol.getSupportedTokens({
  fromToken: 'XAUT0'
})

The returned descriptors omit on-chain token addresses because this discovery method does not resolve them. Solana, TON, and TRON are destination-only entries and are not returned by getSupportedTokens().

These discovery methods expose separate static chain and token lists. They do not prove that a source token has an on-chain peer for a destination. Confirm the exact pair with quoteBridge() before execution.

Types

BridgeOptions

interface BridgeOptions {
  targetChain: string;              // Destination chain name
  recipient: string;                // Address that will receive bridged tokens
  token: string;                    // Token contract address on source chain
  amount: number | bigint;          // Amount to bridge in token base units
  oftContractAddress?: string;      // Optional custom OFT contract address
  dstEid?: number;                  // Optional destination endpoint ID override
}

BridgeResult

interface BridgeResult {
  hash: string;                     // Main bridge transaction hash
  fee: bigint;                      // Account quote fee; unit depends on account gas-payment mode
  bridgeFee: bigint;                // Standard: source native unit; ERC-4337 helper: bridged-token base units
}

BridgeProtocolConfig

interface BridgeProtocolConfig {
  bridgeMaxFee?: number | bigint;    // Reject when the implementation's fee + bridgeFee is at or above this value
}
type Erc4337QuoteConfig = Partial<
  | EvmErc4337WalletPaymasterTokenConfig
  | EvmErc4337WalletSponsorshipPolicyConfig
  | EvmErc4337WalletNativeCoinsConfig
>

type Erc4337BridgeConfig = Erc4337QuoteConfig & {
  bridgeMaxFee?: number | bigint
}

Fee units and bridgeMaxFee

Account flowfeebridgeFee
Standard EVMSource-chain native base unitsSource-chain native base units
ERC-4337 with native gasSource-chain native base unitsBridged-token base units
ERC-4337 with token-paid gasPaymaster-token base unitsBridged-token base units
ERC-4337 with sponsored gas0Bridged-token base units

In 1.0.0-beta.7, the ERC-4337 path numerically adds fee + bridgeFee when checking bridgeMaxFee, even when the fields have different denominations. Do not interpret that sum as a total monetary cost. Set an ERC-4337 cap only after confirming that the selected account payment mode produces compatible units. The equality boundary is rejected.

Erc4337QuoteConfig is a partial operation-level override of the wallet's token-paid, sponsored, or native-gas configuration. Sponsored gas uses isSponsored: true and can include sponsorshipPolicyId; native gas uses useNativeCoins: true. See the ERC-4337 wallet configuration for the complete account requirements.

Discovery types

type SwidgeSupportedChain = {
  id: string | number
  name: string
  type: string
  nativeToken: string
}

type SwidgeSupportedToken = {
  token: string
  chain: string | number
  symbol: string
  decimals: number
  address?: string
  name?: string
}

type SwidgeSupportedTokensOptions = {
  fromChain?: string | number
  fromToken?: string
  toChain?: string | number
}

Supported Chains

The bridge protocol supports the following chains:

Source Chains (EVM):

  • 'ethereum' (Chain ID: 1) - ERC-4337 helper support
  • 'arbitrum' (Chain ID: 42161) - ERC-4337 helper support
  • 'optimism' (Chain ID: 10)
  • 'polygon' (Chain ID: 137) - ERC-4337 helper support
  • 'berachain' (Chain ID: 80094)
  • 'ink' (Chain ID: 57073)
  • 'plasma' (Chain ID: 9745) - ERC-4337 helper support
  • 'conflux' (Chain ID: 1030)
  • 'corn' (Chain ID: 21000000)
  • 'avalanche' (Chain ID: 43114)
  • 'celo' (Chain ID: 42220)
  • 'flare' (Chain ID: 14)
  • 'hyperevm' (Chain ID: 999)
  • 'mantle' (Chain ID: 5000)
  • 'megaeth' (Chain ID: 4326)
  • 'monad' (Chain ID: 143)
  • 'morph' (Chain ID: 2818)
  • 'rootstock' (Chain ID: 30)
  • 'sei' (Chain ID: 1329)
  • 'stable' (Chain ID: 988)
  • 'unichain' (Chain ID: 130)
  • 'xlayer' (Chain ID: 196)

Configured destination keys:

  • EVM destinations: same as source-chain set above
  • 'solana' (EID: 30168)
  • 'ton' (EID: 30343)
  • 'tron' (EID: 30420)

The configured keys are not a Cartesian route matrix. Route execution still requires a matching source contract and a destination peer configured on-chain.

Error Handling

The bridge protocol throws specific errors for different failure cases:

try {
  await account.approve({
    token: '0x...', // USDT contract address
    spender: '0x...', // OFT or bridge spender address
    amount: 1000000n
  })

  const result = await bridgeProtocol.bridge({
    targetChain: 'arbitrum',
    recipient: '0x...', // Recipient address
    token: '0x...', // USDT contract address
    amount: 1000000n,
    oftContractAddress: '0x...' // Same address used as approval spender
  })
} catch (error) {
  if (error.message.includes('not supported')) {
    console.error('Chain or token not supported')
  }
  if (error.message.includes('Exceeded maximum fee')) {
    console.error('Bridge fee too high')
  }
  if (error.message.includes('must be connected to a provider')) {
    console.error('Wallet not connected to blockchain')
  }
  if (error.message.includes('requires the protocol to be initialized with a non read-only account')) {
    console.error('Cannot bridge with read-only account')
  }
  if (error.message.includes('cannot be equal to the source chain')) {
    console.error('Cannot bridge to the same chain')
  }
}

Usage Examples

Basic Bridge Operation

import Usdt0ProtocolEvm from '@tetherto/wdk-protocol-bridge-usdt0-evm'
import { WalletAccountEvm } from '@tetherto/wdk-wallet-evm'

async function bridgeTokens() {
  // Create wallet account
  const account = new WalletAccountEvm(seedPhrase, "0'/0/0", {
    provider: 'https://eth.drpc.org'
  })

  // Create bridge protocol
  const bridgeProtocol = new Usdt0ProtocolEvm(account)

  // Get quote first
  const quote = await bridgeProtocol.quoteBridge({
    targetChain: 'arbitrum',
    recipient: '0x...', // Recipient address
    token: '0x...', // USDT contract address
    amount: 1000000n
  })

  console.log('Bridge quote:', quote)

  // Execute bridge
  await account.approve({
    token: '0x...', // USDT contract address
    spender: '0x...', // OFT or bridge spender address
    amount: 1000000n
  })

  const result = await bridgeProtocol.bridge({
    targetChain: 'arbitrum',
    recipient: '0x...', // Recipient address
    token: '0x...', // USDT contract address
    amount: 1000000n,
    oftContractAddress: '0x...' // Optional custom OFT contract
  })

  console.log('Bridge result:', result)

  return result
}

Multi-Chain Bridge

async function bridgeToMultipleChains(account, bridgeProtocol) {
  const chains = ['arbitrum', 'polygon', 'ethereum']
  const token = '0x...' // USDT contract address
  const amount = 1000000n
  const recipient = '0x...' // Recipient address

  const results = []

  for (const chain of chains) {
    try {
      // Get quote
      const quote = await bridgeProtocol.quoteBridge({
        targetChain: chain,
        recipient,
        token,
        amount
      })

      console.log(`Bridge to ${chain}:`, quote)

      // Execute bridge
      await account.approve({
        token,
        spender: '0x...', // OFT or bridge spender address for the source route
        amount
      })

      const result = await bridgeProtocol.bridge({
        targetChain: chain,
        recipient,
        token,
        amount,
        oftContractAddress: '0x...' // Same address used as approval spender
      })

      results.push({ chain, result })
      console.log(`Bridge to ${chain} successful:`, result.hash)

    } catch (error) {
      console.error(`Bridge to ${chain} failed:`, error.message)
    }
  }

  return results
}

ERC-4337 Gasless Bridge

import { WalletAccountEvmErc4337 } from '@tetherto/wdk-wallet-evm-erc-4337'

async function gaslessBridge() {
  // Create ERC-4337 account
  const account = new WalletAccountEvmErc4337(seedPhrase, "0'/0/0", {
    chainId: 42161,
    provider: 'https://arb1.arbitrum.io/rpc',
    bundlerUrl: 'https://api.candide.dev/public/v3/42161',
    safeModulesVersion: '0.3.0',
    paymasterUrl: 'https://api.candide.dev/public/v3/42161',
    paymasterAddress: '0x8b1f6cb5d062aa2ce8d581942bbb960420d875ba',
    paymasterToken: { address: '0x...' } // Paymaster token configuration
  })

  // Create bridge protocol
  const bridgeProtocol = new Usdt0ProtocolEvm(account)

  // The protocol bundles approval and the helper call in one UserOperation.
  const result = await bridgeProtocol.bridge({
    targetChain: 'polygon',
    recipient: '0x...', // Recipient address
    token: '0x...', // USDT contract address
    amount: 1000000n,
    oftContractAddress: '0x...' // Optional custom OFT contract
  }, {
    paymasterToken: { address: '0x...' } // Paymaster token configuration
  })

  console.log('ERC-4337 bridge result:', result)
  return result
}

Need Help?

On this page