Bridge USD₮0 EVM API Reference
Complete API documentation for @tetherto/wdk-protocol-bridge-usdt0-evm
Table of Contents
| Class | Description | Methods |
|---|---|---|
| Usdt0ProtocolEvm | Main 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(IWalletAccountorIWalletAccountReadOnlyfrom@tetherto/wdk-wallet): The wallet account to use for bridge operations. See account requirements.config(BridgeProtocolConfig, optional): Configuration objectbridgeMaxFee(number | bigint, optional): Rejectsbridge()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
})Account requirements
The constructor accepts the shared IWalletAccount and IWalletAccountReadOnly interfaces in 1.0.0-beta.9. For execution, bridge() checks whether the account has a callable sendTransaction() method instead of requiring a WalletAccountEvm instance.
The account must still implement EVM-compatible getAddress() and quoteSendTransaction() operations. Both bridge methods require an RPC URL or EIP-1193 provider in the wallet configuration. The constructor reads account._config.provider, an internal field absent from the shared interfaces. Implementing the interface alone does not establish runtime compatibility; an account without _config fails construction.
Read-only accounts can use quoteBridge(), subject to the same provider, route, balance, and allowance requirements. They cannot execute bridge() without sendTransaction().
ERC-4337 helper selection and approval batching still depend on the concrete classes resolved by the bridge package: WalletAccountReadOnlyEvmErc4337 for helper construction and quotes, and WalletAccountEvmErc4337 for execution. A custom account or an account from a separate copy of the ERC-4337 package does not receive that path solely because it implements sendTransaction(). The bridge release depends on ERC-4337 wallet 1.0.0-beta.11; verify package deduplication and runtime class identity when combining wallet versions. See Bridge with ERC-4337.
Methods
| Method | Description | Returns | Throws |
|---|---|---|---|
bridge(options, config?) | Bridges tokens to another blockchain | Promise<BridgeResult> | If no provider or the combined fee is at or above the cap |
quoteBridge(options, config?) | Estimates the cost of a bridge operation | Promise<Omit<BridgeResult, 'hash'>> | If no provider |
getSupportedChains() | Returns chain descriptors from bundled configuration | Promise<SwidgeSupportedChain[]> | — |
getSupportedTokens(options?) | Returns configured USD₮0 or XAU₮0 descriptors, with optional filters | Promise<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. On Ethereum mainnet, when the resolved token is USD₮ at 0xdAC17F958D2ee523a2206206994597C13D831ec7, the protocol queries that ERC-4337 account's allowance for the token and the transaction-value helper spender. If the current allowance and the computed approveAmount are both greater than zero, it prepends approve(spender, 0), then approve(spender, approveAmount), then the helper bridge call in the same batch. Standard EVM accounts and every other chain/token path are unchanged.
Parameters:
options(BridgeOptions): Bridge operation optionstargetChain(string): Destination chain namerecipient(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 chainamount(number | bigint): Amount to bridge in token base unitsoftContractAddress(string, optional): Custom OFT contract address to use instead of auto-resolving from the source chaindstEid(number, optional): Custom LayerZero destination endpoint ID override
config(Erc4337BridgeConfig, optional): ERC-4337 gas-payment overrides plus optionalbridgeMaxFeebridgeMaxFee(number | bigint, optional): Override maximum bridge fee
Returns: Promise<BridgeResult> - Bridge operation result
Throws:
- Error if the account has no callable
sendTransaction()method - 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...', // USDt 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. Read-only accounts are accepted, and this method does not enforce bridgeMaxFee.
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. For WalletAccountReadOnlyEvmErc4337, quoteBridge() uses the same ordered batch as bridge(): on Ethereum mainnet for the resolved USD₮ token at 0xdAC17F958D2ee523a2206206994597C13D831ec7, an existing non-zero allowance and non-zero approveAmount produce approve(spender, 0), approve(spender, approveAmount), then the helper bridge call; otherwise the batch is the approval followed by the helper call.
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 flow | fee | bridgeFee |
|---|---|---|
WalletAccountEvm | Source-chain native base units | Source-chain native base units |
| Other compatible accounts using the single-transaction path | Account-specific quoteSendTransaction() fee units | Source-chain native base units |
| ERC-4337 with native gas | Source-chain native base units | Bridged-token base units |
| ERC-4337 with token-paid gas | Paymaster-token base units | Bridged-token base units |
| ERC-4337 with sponsored gas | 0 | Bridged-token base units |
In 1.0.0-beta.9, bridge() numerically adds fee + bridgeFee when checking bridgeMaxFee, even when the fields have different denominations. This affects ERC-4337 helper flows and any compatible account whose quoted fee is not in source-chain native base units. Do not interpret that sum as a total monetary cost. Set a 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
}Node.js Quickstart
Get started with WDK in a Node.js environment
WDK Bridge USD₮0 EVM Protocol Configuration
Get started with WDK's Bridge USD₮0 EVM Protocol configuration
WDK Bridge USD₮0 EVM Protocol Usage
Get started with WDK's Bridge USD₮0 EVM Protocol usage