Skip to main content

Import

import {
  createEvmBuilder,
  getEvmProof,
  parseInitTransferEvent,
  getInitTransferTopic,
  BRIDGE_TOKEN_FACTORY_ABI,
  ERC20_ABI,
} from "@omni-bridge/evm"

createEvmBuilder

Factory function to create an EVM transaction builder for a specific chain.

Signature

function createEvmBuilder(config: EvmBuilderConfig): EvmBuilder

Parameters

config
EvmBuilderConfig
required
Configuration object for the EVM builder.

Returns

EvmBuilder
EvmBuilder
An EVM transaction builder instance.

Example

import { createEvmBuilder } from "@omni-bridge/evm"
import { ChainKind } from "@omni-bridge/core"

// Create builder for Ethereum mainnet
const ethBuilder = createEvmBuilder({
  network: "mainnet",
  chain: ChainKind.Eth,
})

// Create builder for Base
const baseBuilder = createEvmBuilder({
  network: "mainnet",
  chain: ChainKind.Base,
})

// Create builder for Arbitrum testnet
const arbBuilder = createEvmBuilder({
  network: "testnet",
  chain: ChainKind.Arb,
})

console.log(ethBuilder.chainId) // 1
console.log(ethBuilder.bridgeAddress) // "0x..."

EvmBuilder Methods

buildTransfer

Builds an unsigned transfer transaction for bridging tokens from an EVM chain.

Signature

builder.buildTransfer(validated: ValidatedTransfer): EvmUnsignedTransaction

Parameters

validated
ValidatedTransfer
required
A validated transfer object from bridge.validateTransfer(). The source chain in the validated transfer must match the builder’s configured chain.

Returns

EvmUnsignedTransaction
EvmUnsignedTransaction
An unsigned transaction object compatible with viem and ethers v6.

Example

import { createBridge } from "@omni-bridge/core"
import { createEvmBuilder } from "@omni-bridge/evm"
import { ChainKind } from "@omni-bridge/core"

const bridge = createBridge({ network: "mainnet" })
const evm = createEvmBuilder({ network: "mainnet", chain: ChainKind.Eth })

// Validate the transfer
const validated = await bridge.validateTransfer({
  token: "eth:0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
  amount: 1000000n, // 1 USDC
  fee: 0n,
  nativeFee: 0n,
  sender: "eth:0xYourAddress",
  recipient: "near:alice.near",
})

// Build the unsigned transaction
const tx = evm.buildTransfer(validated)

// Send with viem
await walletClient.sendTransaction(tx)

// Or send with ethers v6
await signer.sendTransaction(tx)

Native Token Transfers

When bridging native tokens (ETH, BNB, etc.), use the zero address:
import { parseEther } from "viem"

const validated = await bridge.validateTransfer({
  token: "eth:0x0000000000000000000000000000000000000000",
  amount: parseEther("0.1"),
  fee: 0n,
  nativeFee: 0n,
  sender: "eth:0xYourAddress",
  recipient: "near:alice.near",
})

const tx = evm.buildTransfer(validated)
// tx.value includes the transfer amount

Transaction Value Calculation

The value field is calculated automatically based on token type:
Token Typetx.value Contains
ERC20 tokensnativeFee only
Native tokens (ETH, BNB, etc.)amount + nativeFee
// ERC20: value = nativeFee
const validated = await bridge.validateTransfer({
  token: "eth:0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
  amount: 1000000n,
  nativeFee: 1000000000000000n, // 0.001 ETH
  // ...
})
const tx = evm.buildTransfer(validated)
console.log(tx.value) // 1000000000000000n (just nativeFee)

// Native ETH: value = amount + nativeFee
const validated = await bridge.validateTransfer({
  token: "eth:0x0000000000000000000000000000000000000000",
  amount: 1000000000000000000n, // 1 ETH
  nativeFee: 1000000000000000n, // 0.001 ETH
  // ...
})
const tx = evm.buildTransfer(validated)
console.log(tx.value) // 1001000000000000000n (amount + nativeFee)
For ERC20 tokens, you must call buildApproval() first to approve the bridge contract to spend your tokens.

buildApproval

Builds an ERC20 approval transaction for the bridge contract.

Signature

builder.buildApproval(token: Address, amount: bigint): EvmUnsignedTransaction

Parameters

token
Address
required
The ERC20 token contract address (without chain prefix), e.g., "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48".
amount
bigint
required
The amount to approve in the token’s smallest unit.

Returns

EvmUnsignedTransaction
EvmUnsignedTransaction
An unsigned approval transaction. The to field is the token contract address, and value is always 0n.

Example

const approvalTx = evm.buildApproval(
  "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
  1000000n // 1 USDC
)

await walletClient.sendTransaction(approvalTx)

buildMaxApproval

Builds an unlimited (max uint256) approval transaction for the bridge contract.

Signature

builder.buildMaxApproval(token: Address): EvmUnsignedTransaction

Parameters

token
Address
required
The ERC20 token contract address (without chain prefix).

Returns

EvmUnsignedTransaction
EvmUnsignedTransaction
An unsigned approval transaction for type(uint256).max.

Example

// Approve unlimited USDC spending
const approvalTx = evm.buildMaxApproval(
  "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
)

await walletClient.sendTransaction(approvalTx)
Max approvals are convenient for repeated transfers but carry higher security risk. Consider using exact amounts for better security.

buildFinalization

Builds a finalization transaction for completing incoming transfers to an EVM chain.

Signature

builder.buildFinalization(
  payload: TransferPayload,
  signature: Uint8Array
): EvmUnsignedTransaction

Parameters

payload
TransferPayload
required
The transfer payload containing transfer details.
signature
Uint8Array
required
The MPC signature authorizing the finalization.

Returns

EvmUnsignedTransaction
EvmUnsignedTransaction
An unsigned finalization transaction. The value is always 0n.

Example

const finalizeTx = evm.buildFinalization(
  {
    destinationNonce: 42n,
    originChain: 1, // NEAR
    originNonce: 123n,
    tokenAddress: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
    amount: 1000000n,
    recipient: "0xRecipientAddress",
    feeRecipient: "near:relayer.near",
  },
  signature // MPC signature bytes
)

await walletClient.sendTransaction(finalizeTx)

buildLogMetadata

Builds a transaction to log token metadata on-chain. This is used to register token information for bridging.

Signature

builder.buildLogMetadata(token: Address): EvmUnsignedTransaction

Parameters

token
Address
required
The ERC20 token contract address to log metadata for.

Returns

EvmUnsignedTransaction
EvmUnsignedTransaction
An unsigned transaction to call logMetadata on the bridge contract.

Example

const logTx = evm.buildLogMetadata(
  "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" // USDC
)

await walletClient.sendTransaction(logTx)

buildDeployToken

Builds a transaction to deploy a bridged token representation on the EVM chain.

Signature

builder.buildDeployToken(
  signature: Uint8Array,
  metadata: TokenMetadata
): EvmUnsignedTransaction

Parameters

signature
Uint8Array
required
The MPC signature authorizing the token deployment.
metadata
TokenMetadata
required
The token metadata for the bridged token.

Returns

EvmUnsignedTransaction
EvmUnsignedTransaction
An unsigned transaction to deploy the bridged token contract.

Example

const deployTx = evm.buildDeployToken(signature, {
  token: "wrap.near",
  name: "Wrapped NEAR",
  symbol: "wNEAR",
  decimals: 24,
})

await walletClient.sendTransaction(deployTx)

Proof Utilities

getEvmProof

Generates a Merkle proof for an EVM transaction, used for cross-chain verification.

Signature

async function getEvmProof(
  txHash: Hex,
  topic: Hex,
  chain: EvmChainKind,
  network: Network,
  customRpcUrl?: string
): Promise<EvmProof>

Parameters

txHash
Hex
required
The transaction hash to generate a proof for, e.g., "0x...".
topic
Hex
required
The event topic to prove. Use getInitTransferTopic() for transfer proofs.
chain
EvmChainKind
required
The EVM chain where the transaction occurred. One of: ChainKind.Eth, ChainKind.Base, ChainKind.Arb, ChainKind.Pol, ChainKind.Bnb
network
Network
required
The network: "mainnet" or "testnet".
customRpcUrl
string
Optional custom RPC URL. If not provided, uses default public RPC endpoints.

Returns

EvmProof
EvmProof
The Merkle proof data for cross-chain verification.

Example

import { getEvmProof, getInitTransferTopic } from "@omni-bridge/evm"
import { ChainKind } from "@omni-bridge/core"

const proof = await getEvmProof(
  "0x1234567890abcdef...",
  getInitTransferTopic(),
  ChainKind.Eth,
  "mainnet"
)

// Use with custom RPC
const proofWithCustomRpc = await getEvmProof(
  "0x1234567890abcdef...",
  getInitTransferTopic(),
  ChainKind.Eth,
  "mainnet",
  "https://my-rpc-endpoint.com"
)

parseInitTransferEvent

Parses the InitTransfer event from transaction logs. Works with both viem and ethers receipt log formats.

Signature

function parseInitTransferEvent(logs: readonly LogEntry[]): EvmInitTransferEvent

Parameters

logs
readonly LogEntry[]
required
Array of log entries from a transaction receipt.

Returns

EvmInitTransferEvent
EvmInitTransferEvent
Parsed event data.

Throws

Throws an error if no InitTransfer event is found in the logs.

Example

import { parseInitTransferEvent } from "@omni-bridge/evm"

// With viem
const receipt = await publicClient.getTransactionReceipt({ hash: txHash })
const event = parseInitTransferEvent(receipt.logs)

console.log(`Transfer nonce: ${event.originNonce}`)
console.log(`Amount: ${event.amount}`)
console.log(`Recipient: ${event.recipient}`)

// With ethers v6
const receipt = await provider.getTransactionReceipt(txHash)
const event = parseInitTransferEvent(receipt.logs)

getInitTransferTopic

Returns the topic hash for the InitTransfer event.

Signature

function getInitTransferTopic(): Hex

Returns

Hex
Hex
The keccak256 hash of the InitTransfer event signature: "0xaa7e1f77d43faa300bc5ae8f012f0b7cf80174f4c0b1cffeab250cb4966bb88c"

Example

import { getInitTransferTopic } from "@omni-bridge/evm"

const topic = getInitTransferTopic()
// "0xaa7e1f77d43faa300bc5ae8f012f0b7cf80174f4c0b1cffeab250cb4966bb88c"

Contract ABIs

BRIDGE_TOKEN_FACTORY_ABI

The ABI for the bridge token factory contract. Includes functions for:
  • initTransfer - Initiate a cross-chain transfer
  • finTransfer - Finalize an incoming transfer
  • deployToken - Deploy a bridged token
  • logMetadata - Log token metadata
  • nearToEthToken - Look up bridged token address
  • InitTransfer - Event emitted on transfer initiation
import { BRIDGE_TOKEN_FACTORY_ABI } from "@omni-bridge/evm"

ERC20_ABI

A minimal ERC20 ABI with approve and allowance functions.
import { ERC20_ABI } from "@omni-bridge/evm"

Types

EvmUnsignedTransaction

An unsigned EVM transaction object compatible with both viem and ethers v6.
interface EvmUnsignedTransaction {
  to: `0x${string}`   // Target contract address
  data: `0x${string}` // Encoded function call data
  value: bigint       // ETH value to send
  chainId: number     // Chain ID
}
Can be passed directly to:
  • viem: walletClient.sendTransaction(tx)
  • ethers v6: signer.sendTransaction(tx)

EvmBuilderConfig

Configuration for creating an EVM builder.
interface EvmBuilderConfig {
  network: "mainnet" | "testnet"
  chain: EvmChainKind
}

TokenMetadata

Metadata for deploying a bridged token.
interface TokenMetadata {
  token: string    // Original token identifier
  name: string     // Token name
  symbol: string   // Token symbol
  decimals: number // Decimal places
}

TransferPayload

Payload for finalizing an incoming transfer.
interface TransferPayload {
  destinationNonce: bigint
  originChain: number
  originNonce: bigint
  tokenAddress: Address
  amount: bigint
  recipient: Address
  feeRecipient: string
}

EvmProof

Merkle proof data for cross-chain verification.
interface EvmProof {
  log_index: bigint
  log_entry_data: Uint8Array
  receipt_index: bigint
  receipt_data: Uint8Array
  header_data: Uint8Array
  proof: Uint8Array[]
}

EvmInitTransferEvent

Parsed InitTransfer event from bridge transactions.
interface EvmInitTransferEvent {
  sender: string
  tokenAddress: string
  originNonce: bigint
  amount: bigint
  fee: bigint
  nativeTokenFee: bigint
  recipient: string
  message: string
}

LogEntry

Log entry format compatible with both viem and ethers receipts.
interface LogEntry {
  topics: readonly string[] | string[]
  data: string
}

Complete Transfer Example

import { createBridge, ChainKind } from "@omni-bridge/core"
import { createEvmBuilder, parseInitTransferEvent } from "@omni-bridge/evm"
import { createPublicClient, createWalletClient, http, parseUnits } from "viem"
import { mainnet } from "viem/chains"
import { privateKeyToAccount } from "viem/accounts"

// Setup clients
const account = privateKeyToAccount("0x...")
const publicClient = createPublicClient({ chain: mainnet, transport: http() })
const walletClient = createWalletClient({
  chain: mainnet,
  transport: http(),
  account,
})

// Create bridge and builder
const bridge = createBridge({ network: "mainnet" })
const evm = createEvmBuilder({ network: "mainnet", chain: ChainKind.Eth })

// 1. Validate the transfer
const validated = await bridge.validateTransfer({
  token: "eth:0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
  amount: parseUnits("100", 6), // 100 USDC
  fee: 0n,
  nativeFee: 0n,
  sender: `eth:${account.address}`,
  recipient: "near:recipient.near",
})

// 2. Approve the bridge (for ERC20 tokens)
const approvalTx = evm.buildApproval(
  "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
  validated.params.amount
)
const approvalHash = await walletClient.sendTransaction(approvalTx)
await publicClient.waitForTransactionReceipt({ hash: approvalHash })

// 3. Execute the transfer
const transferTx = evm.buildTransfer(validated)
const transferHash = await walletClient.sendTransaction(transferTx)
const receipt = await publicClient.waitForTransactionReceipt({
  hash: transferHash,
})

// 4. Parse the transfer event
const event = parseInitTransferEvent(receipt.logs)
console.log(`Transfer initiated with nonce: ${event.originNonce}`)