Documentation Index Fetch the complete documentation index at: https://bridge.near.tools/llms.txt
Use this file to discover all available pages before exploring further.
This guide covers bridging from any EVM chain. The process is identical — you just change the chain parameter.
Setup
import { createBridge , ChainKind } from "@omni-bridge/core"
import { createEvmBuilder } from "@omni-bridge/evm"
const bridge = createBridge ({ network: "mainnet" })
// Pick your chain
const evm = createEvmBuilder ({ network: "mainnet" , chain: ChainKind . Eth })
// Or: ChainKind.Base, ChainKind.Arb, ChainKind.Pol, ChainKind.Bnb
Complete Transfer
import { createBridge , ChainKind } from "@omni-bridge/core"
import { createEvmBuilder } from "@omni-bridge/evm"
import { createWalletClient , createPublicClient , http } from "viem"
import { mainnet } from "viem/chains"
import { privateKeyToAccount } from "viem/accounts"
const bridge = createBridge ({ network: "mainnet" })
const evm = createEvmBuilder ({ network: "mainnet" , chain: ChainKind . Eth })
const account = privateKeyToAccount ( "0x..." )
const wallet = createWalletClient ({ chain: mainnet , transport: http (), account })
const publicClient = createPublicClient ({ chain: mainnet , transport: http () })
// 1. Validate
const validated = await bridge . validateTransfer ({
token: "eth:0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" , // USDC
amount: 100_000_000 n , // 100 USDC
sender: `eth: ${ account . address } ` ,
recipient: "near:alice.near" ,
fee: 0 n ,
nativeFee: 0 n ,
})
// 2. Approve (ERC20 only — skip for native ETH)
const approval = evm . buildApproval (
"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" ,
100_000_000 n
)
const approvalHash = await wallet . sendTransaction ( approval )
await publicClient . waitForTransactionReceipt ({ hash: approvalHash })
// 3. Transfer
const tx = evm . buildTransfer ( validated )
const hash = await wallet . sendTransaction ( tx )
console . log ( "Transfer initiated:" , hash )
Using ethers v6 instead of viem
import { createBridge , ChainKind } from "@omni-bridge/core"
import { createEvmBuilder } from "@omni-bridge/evm"
import { ethers } from "ethers"
const bridge = createBridge ({ network: "mainnet" })
const evm = createEvmBuilder ({ network: "mainnet" , chain: ChainKind . Eth })
const provider = new ethers . JsonRpcProvider ( "https://eth.llamarpc.com" )
const signer = new ethers . Wallet ( "0x..." , provider )
// 1. Validate
const validated = await bridge . validateTransfer ({
token: "eth:0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" ,
amount: 100_000_000 n ,
sender: `eth: ${ signer . address } ` ,
recipient: "near:alice.near" ,
fee: 0 n ,
nativeFee: 0 n ,
})
// 2. Approve
const approval = evm . buildApproval (
"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" ,
100_000_000 n
)
await ( await signer . sendTransaction ( approval )). wait ()
// 3. Transfer
const tx = evm . buildTransfer ( validated )
const receipt = await signer . sendTransaction ( tx )
console . log ( "Transfer initiated:" , receipt . hash )
Native ETH Transfers
For native ETH (not WETH), use the zero address and skip approval:
import { parseEther } from "viem"
const validated = await bridge . validateTransfer ({
token: "eth:0x0000000000000000000000000000000000000000" , // Native ETH
amount: parseEther ( "0.1" ),
sender: `eth: ${ account . address } ` ,
recipient: "near:alice.near" ,
fee: 0 n ,
nativeFee: 0 n ,
})
// No approval needed — go straight to transfer
const tx = evm . buildTransfer ( validated )
await wallet . sendTransaction ( tx )
The value field in the transaction includes both the transfer amount and any native fee.
L2 Chains
The same code works for L2s — just change the chain config:
import { base } from "viem/chains"
// Base
const baseBuilder = createEvmBuilder ({ network: "mainnet" , chain: ChainKind . Base })
const baseWallet = createWalletClient ({ chain: base , transport: http (), account })
const validated = await bridge . validateTransfer ({
token: "base:0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913" , // USDC on Base
amount: 100_000_000 n ,
sender: `base: ${ account . address } ` ,
recipient: "near:alice.near" ,
fee: 0 n ,
nativeFee: 0 n ,
})
const tx = baseBuilder . buildTransfer ( validated )
await baseWallet . sendTransaction ( tx )
Receiving on EVM (From NEAR)
When tokens come from NEAR to an EVM chain, the transfer finalizes automatically if the sender paid relayer fees. The tokens appear in the recipient’s address.
If you need to finalize manually (no fees paid), see Manual Finalization .
Approvals
For ERC20 tokens, you must approve the bridge contract before transferring.
Exact approval — Approve only what you need:
const approval = evm . buildApproval ( tokenAddress , amount )
Unlimited approval — Approve once, transfer many times:
const approval = evm . buildMaxApproval ( tokenAddress )
buildTransfer() returns an EvmUnsignedTransaction:
interface EvmUnsignedTransaction {
to : `0x ${ string } ` // Bridge contract
data : `0x ${ string } ` // Encoded function call
value : bigint // Native token (ETH) if applicable
chainId : number // Chain ID for signing
}
This works directly with viem and ethers — no conversion needed.
Error Handling
import { ValidationError } from "@omni-bridge/core"
try {
const validated = await bridge . validateTransfer ( params )
const tx = evm . buildTransfer ( validated )
await wallet . sendTransaction ( tx )
} catch ( error ) {
if ( error instanceof ValidationError ) {
switch ( error . code ) {
case "INVALID_ADDRESS" :
console . error ( "Invalid address format" )
break
case "TOKEN_NOT_REGISTERED" :
console . error ( "Token not supported" )
break
case "AMOUNT_TOO_SMALL" :
console . error ( "Amount too small — see /core-concepts/decimals" )
break
}
}
}
Chain Reference
Chain ChainKind Token Prefix Mainnet ID Testnet ID Ethereum Etheth:1 11155111 (Sepolia) Base Basebase:8453 84532 Arbitrum Arbarb:42161 421614 Polygon Polpol:137 80002 (Amoy) BNB Chain Bnbbnb:56 97
Next Steps
Pay Relayer Fees Automatic finalization on destination
Track Status Monitor your transfer’s progress