Skip to content

Near-One/bridge-sdk-js

Repository files navigation

Omni Bridge SDK

Status Stability

A TypeScript SDK for seamless cross-chain token transfers using the Omni Bridge protocol.

Important

This SDK is in beta and approaching production readiness. While core functionality is stable, some features may still change. We recommend thorough testing before using in production environments.

Features

  • 🔄 Cross-chain token transfers between Ethereum, NEAR, Solana, Base, and Arbitrum
  • 🤖 Automated transfer finalization through our relayer network
  • 🪙 Token deployment and management across chains
  • 📖 Comprehensive TypeScript type definitions
  • ⚡ Support for native chain-specific features
  • 🔍 Transfer status tracking and history

Getting Started

Installation

npm install omni-bridge-sdk
# or
yarn add omni-bridge-sdk

Quick Start with Relayers

The fastest way to get started is using our relayer service for automated transfer finalization:

import { omniTransfer, OmniBridgeAPI } from "omni-bridge-sdk";

// Get fees (includes relayer service fee)
const api = new OmniBridgeAPI();
const fees = await api.getFee("eth:0x123...", "near:bob.near", "eth:0x789...");

// Send tokens
await omniTransfer(wallet, {
  tokenAddress: "eth:0x789...", // Token contract
  recipient: "near:bob.near", // Destination address
  amount: BigInt("1000000"), // Amount to send
  fee: BigInt(fees.transferred_token_fee), // Includes relayer fee
  nativeFee: BigInt(fees.native_token_fee),
});

Complete Example

Here's a more detailed example showing wallet setup, error handling, and status monitoring:

import { setNetwork } from "omni-bridge-sdk";

// Set network type
setNetwork("testnet");

// 1. Setup wallet/provider
const wallet = provider.getSigner(); // for EVM
// or
const account = await near.account("sender.near"); // for NEAR
// or
const provider = new AnchorProvider(connection, wallet); // for Solana

// 2. Get fees (includes relayer service fee)
const api = new OmniBridgeAPI();
const sender = "eth:0x123...";
const recipient = "near:bob.near";
const token = "eth:0x789...";

const fees = await api.getFee(sender, recipient, token);

// 3. Send tokens
try {
  const result = await omniTransfer(wallet, {
    tokenAddress: token,
    recipient,
    amount: BigInt("1000000"),
    fee: BigInt(fees.transferred_token_fee),
    nativeFee: BigInt(fees.native_token_fee),
  });

  // 4. Monitor status
  const status = await api.getTransferStatus(sourceChain, result.nonce);
  console.log(`Transfer status: ${status}`);
} catch (error) {
  console.error("Transfer failed:", error);
}

Core Concepts

Addresses

All addresses in the SDK use the OmniAddress format, which includes the chain prefix:

type OmniAddress =
  | `eth:${string}` // Ethereum addresses
  | `near:${string}` // NEAR accounts
  | `sol:${string}` // Solana public keys
  | `arb:${string}` // Arbitrum addresses
  | `base:${string}`; // Base addresses

// Helper function
const addr = omniAddress(ChainKind.Near, "account.near");

Transfer Messages

Transfer messages represent cross-chain token transfers:

interface UtxoTransferOptions {
  maxFee?: bigint;  // Maximum BTC/Zcash network fee (in satoshis)
}

interface OmniTransferMessage {
  tokenAddress: OmniAddress; // Source token address
  amount: bigint; // Amount to transfer
  fee: bigint; // Token fee
  nativeFee: bigint; // Gas fee in native token
  recipient: OmniAddress; // Destination address
  message?: string; // Optional message field (for advanced use, overrides maxFee)
  options?: UtxoTransferOptions; // Chain-specific options
}

Chain-Specific Options: The options field allows you to specify chain-specific parameters:

  • UTXO chains (Bitcoin/Zcash): Use UtxoTransferOptions to specify:
    • maxFee: Maximum BTC/Zcash network fee allowed (in satoshis). This protects you from excessive fees.
      • Automatically converted to the nested message format: {"MaxGasFee":"5000"} (stringified int)
      • The contract validates that the actual gas fee doesn't exceed this limit
      • Cannot be used together with the message field (use one or the other)
    • The protocol fee is automatically calculated by the contract based on the configured protocol_fee_rate

Example for Bitcoin:

const transfer: OmniTransferMessage = {
  tokenAddress: "near:nbtc.near",
  recipient: "btc:bc1q...",
  amount: BigInt(100000),
  fee: BigInt(5000),
  nativeFee: BigInt(1000),
  options: {
    maxFee: BigInt(5000)  // Maximum BTC network fee in satoshis
  }
}

Transfer Guide

Using Relayers (Recommended)

While the SDK provides methods to manually handle the complete transfer lifecycle, we recommend using our relayer service for the best user experience. Benefits include:

  • Single transaction for end users
  • Automated message signing and finalization
  • No need to handle cross-chain message passing
  • Optimized gas fees
  • Simplified error handling

To use relayers, simply include the relayer fee when initiating the transfer:

const transfer = {
  tokenAddress: omniAddress(ChainKind.Near, "usdc.near"),
  amount: BigInt("1000000"),
  fee: BigInt(feeEstimate.transferred_token_fee), // Relayer fee included
  nativeFee: BigInt(feeEstimate.native_token_fee),
  recipient: omniAddress(ChainKind.Eth, recipientAddress),
};

// One transaction - relayers handle the rest
const result = await omniTransfer(account, transfer);

Status Monitoring

Track transfer progress using the API:

const api = new OmniBridgeAPI();
const status = await api.getTransferStatus(sourceChain, nonce);
// Status: "pending" | "ready_for_finalize" | "completed" | "failed"

// Get transfer history
const transfers = await api.findOmniTransfers(
  "near:sender.near",
  0, // offset
  10 // limit
);

Fee Estimation

const api = new OmniBridgeAPI();
const fee = await api.getFee(sender, recipient, tokenAddr);

console.log(`Native fee: ${fee.native_token_fee}`); // Includes relayer fee
console.log(`Token fee: ${fee.transferred_token_fee}`);
console.log(`USD fee: ${fee.usd_fee}`);

Fee Validation: Using api.getFee() is recommended to get accurate protocol and relayer fees. The smart contract validates fees on-chain and will reject transfers with insufficient fees. You can provide higher fees than the API suggests if desired (e.g., for priority processing or custom relayers).

Understanding Wormhole VAAs

What are VAAs?

Verified Action Approvals (VAAs) are cryptographic proofs used by the Wormhole protocol to verify cross-chain messages. When tokens are transferred from Solana to other chains, Wormhole Guardians observe the transaction and collectively sign a VAA that proves the transfer occurred.

When VAAs are Required

  • Solana → NEAR: VAA required for transfer finalization
  • Solana → Any Chain: VAA needed for token deployments
  • EVM → NEAR: EVM proof required instead of VAA
  • NEAR → Any Chain: MPC signature used instead of VAA

Working with VAAs

import { getVaa } from "omni-bridge-sdk";

// Get VAA after Solana transaction (may take 30-60 seconds)
const vaa = await getVaa(txHash, "Testnet");

// Use VAA for finalization on NEAR
await nearClient.finalizeTransfer(tokenId, recipient, storageDeposit, 
  ChainKind.Sol, vaa, undefined, ProofKind.InitTransfer);

Note: VAAs may take 30-60 seconds to become available after transaction confirmation. Implement retry logic for production applications.

Advanced Usage

Manual Transfer Flows

For applications requiring manual control over the transfer process, the SDK provides complete access to underlying bridge functions. Each chain requires specific handling:

// Basic manual flow pattern
const txHash = await sourceClient.initTransfer(transferMessage);
const proof = await getProof(txHash); // VAA for Solana, EVM proof for Ethereum 
await destinationClient.finalizeTransfer(tokenId, recipient, proof);

Complete Examples: See the e2e/ directory for working end-to-end transfer examples, including Solana→NEAR, Ethereum→NEAR, and NEAR→Ethereum flows with full error handling.

Warning

NEAR Wallet Integration Notes: When using browser-based NEAR wallets through Wallet Selector, transactions involve page redirects. The current SDK doesn't fully support this flow - applications need to handle redirect returns and transaction hash parsing separately. For production applications, consider using near-api-js with a direct key approach or implement custom redirect handling.

Token Operations

Deploying Tokens

Token deployment follows a multi-step process depending on source and destination chains:

// Basic token deployment pattern
await sourceClient.logMetadata(tokenAddress);
// ... wait for proof/signature generation ...
const { tokenAddress } = await destinationClient.deployToken(proof, metadata);
// ... binding step if deploying FROM NEAR ...

Key Requirements:

  • NEAR→Foreign: 4 steps (logMetadata → wait → deployToken → bindToken)
  • Foreign→NEAR: 3 steps (logMetadata → wait → deployToken)
  • All cross-chain deployments require the token to first exist on NEAR

Complete Guide: See docs/token-deployment.md for detailed deployment instructions with full code examples for all supported chain combinations.

Error Handling

The SDK provides detailed error messages for common failure scenarios:

try {
  const result = await omniTransfer(wallet, transferMessage);
} catch (error) {
  if (error.message.includes("Insufficient balance")) {
    // Handle balance errors
  } else if (error.message.includes("No VAA found")) {
    // VAA not ready yet - implement retry logic
  } else if (error.message.includes("Token already exists")) {
    // Token deployment conflicts
  }
  // ... handle other error types
}

Note: For VAA operations, implement retry logic as VAAs may take 30-60 seconds to become available. For comprehensive error handling patterns, see the examples in e2e/ test files.

Chain Support

Each supported chain has specific requirements:

NEAR

  • Account must exist and be initialized
  • Sufficient NEAR for storage and gas
  • Token must be registered with account
  • Supports both near-api-js and Wallet Selector

Ethereum/EVM

  • Sufficient ETH/native token for gas
  • Token must be approved for bridge
  • Valid ERC20 token contract

Solana

  • Sufficient SOL for rent and fees
  • Associated token accounts must exist
  • SPL token program requirements

Currently supported chains:

  • Ethereum (ETH)
  • NEAR
  • Solana (SOL)
  • Arbitrum (ARB)
  • Base

Build and Test

# Install dependencies
bun install

# Build
bun run build

# Run tests
bun run test

# Type checking
bun run typecheck

# Linting
bun run lint

License

MIT

About

TypeScript SDK for seamless cross-chain token transfers using the Omni Bridge protocol

Resources

License

Stars

Watchers

Forks

Packages

No packages published