npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@tapforce/pod-bridge-sdk

v2.2.1

Published

SDK for interacting with Bridges between pod and other chains

Readme

Pod Bridge SDK

TypeScript SDK for bridging tokens between POD and EVM chains (e.g., ETH Mainnet).

Architecture

ETH -> Pod: Deposit on ETH, AUTO-CLAIM on Pod (no claim TX needed)
Pod -> ETH: Withdraw on Pod, claim on ETH with proof from pod_getBridgeClaimProof RPC

Key points:

  • ERC20 and native token bridging supported
  • Token addresses differ between chains (e.g., USDC on ETH maps to native 0xEeee...EEeE on Pod)
  • Use ETH-side decimals for amounts (e.g., 1e6 for 1 USDC, not 1e18)
  • Pod transactions require EIP-1559 (type 2) gas params, not legacy gasPrice

Features

  • Bridge Deposits: Deposit ERC20 or native tokens to the bridge (with optional CLOB integration)
  • Claim with Proof: Claim on ETH using pod_getBridgeClaimProof RPC
  • Track Bridge Requests: Query deposits sent/received by any address
  • Claim Status Tracking: Monitor claim status and finality
  • Transaction Building: Generate unsigned transactions ready for signing

Installation

npm install @tapforce/pod-bridge-sdk
# or
yarn add @tapforce/pod-bridge-sdk
# or
pnpm add @tapforce/pod-bridge-sdk

Quick Start

import {
  SourceChainToPodActionClient,
  PodToSourceChainActionClient,
  PodBridgeTrackerClient,
  getBridgeClaimProof,
  SOURCE_CHAIN_BRIDGE_ABI,
  POD_BRIDGE_ABI,
} from '@tapforce/pod-bridge-sdk';

Configuration

For Action Clients (creating transactions)

import { PodBridgeActionsClientConfig } from '@tapforce/pod-bridge-sdk';

const actionConfig: PodBridgeActionsClientConfig = {
  sourceChain: {
    contractAddress: '0x...' // BridgeDepositWithdraw on ETH
  },
  pod: {
    contractAddress: '0x0000000000000000000000000000000000B41D9E' // BridgeMintBurn on Pod
  }
};

For Tracker Client (querying events)

import { PodBridgeConfig } from '@tapforce/pod-bridge-sdk';
import { ethers } from 'ethers';

const trackerConfig: PodBridgeConfig = {
  sourceChain: {
    provider: new ethers.JsonRpcProvider('https://eth-mainnet.rpc.example'),
    contractAddress: '0x...',
    deploymentBlock: 12345678 // Optional: avoids indexing empty blocks
  },
  pod: {
    provider: new ethers.JsonRpcProvider('https://rpc.pod.network'),
    contractAddress: '0x0000000000000000000000000000000000B41D9E',
    deploymentBlock: 0
  }
};

Usage

ETH -> Pod (Auto-claim)

Deposits on ETH are automatically claimed on Pod after block finalization.

const client = new SourceChainToPodActionClient(actionConfig);

// Simple deposit (bridge only)
const depositTx = client.deposit({
  token: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC on ETH
  amount: ethers.parseUnits('1', 6),  // 1 USDC (use ETH-side decimals)
  destinationWalletAddress: '0x...',
  from: '0x...',
  // permit: '0x...' // Optional: ERC20 permit bytes
});

// CLOB deposit — bridge and deposit to orderbook in one TX:
// const clobTx = client.deposit({
//   token: '0xdAC17F958D2ee523a2206206994597C13D831ec7', // USDT on ETH
//   amount: ethers.parseUnits('1', 6),
//   destinationWalletAddress: '0x...',
//   callContract: '0x000000000000000000000000000000000000C10B', // CLOB orderbook
//   reserveBalance: ethers.parseUnits('0.5', 6), // Keep 0.5, forward 0.5 to CLOB
//   from: '0x...',
// });

// Don't forget to approve the bridge contract first for ERC20 tokens
const tx = await signer.sendTransaction(depositTx);
const receipt = await tx.wait();

// No claim needed - balance auto-credited on Pod after finalization

Pod -> ETH (Claim with proof)

Withdrawals on Pod require claiming on ETH with a proof from pod_getBridgeClaimProof.

import {
  PodToSourceChainActionClient,
  getBridgeClaimProof,
  ClaimProofData,
} from '@tapforce/pod-bridge-sdk';

const client = new PodToSourceChainActionClient(actionConfig);

// Step 1: Withdraw on Pod (specify target chain ID)
const withdrawTx = client.withdraw({
  token: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', // Native token on Pod
  amount: ethers.parseUnits('1', 6),  // Target chain units (1 USDC = 1e6)
  destinationWalletAddress: '0x...',
  chainId: 1,  // Target chain ID (e.g. 1 for ETH mainnet)
  from: '0x...',
});

// Pod requires EIP-1559 gas params (all zeros for free transactions)
const tx = await podSigner.sendTransaction({
  ...withdrawTx,
  maxFeePerGas: 0n,
  maxPriorityFeePerGas: 0n,
  gasLimit: 0n,
});

// Step 2: Get claim proof from Pod RPC
const { proof, auxTxSuffix } = await getBridgeClaimProof(podProvider, tx.hash);

// Step 3: Claim on ETH
const claimData: ClaimProofData = {
  ethTokenAddress: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC on ETH
  amount: ethers.parseUnits('1', 6),  // Must match withdrawn amount
  to: '0x...',
  proof,
  auxTxSuffix,
};

const claimTx = client.claim({ claimData, from: '0x...' });
const claim = await ethSigner.sendTransaction(claimTx);

Tracking Deposits

const tracker = new PodBridgeTrackerClient(trackerConfig);

// Get all deposits for an address
const deposits = await tracker.getAllDepositsFor('0x...');

for (const deposit of deposits) {
  console.log('Request ID:', deposit.requestId);
  console.log('Direction:', deposit.deposit.chain === 'sourceChain' ? 'ETH -> Pod' : 'Pod -> ETH');
  console.log('Token:', deposit.deposit.token);
  console.log('Amount:', deposit.deposit.amount);
  console.log('Timestamp:', new Date(deposit.deposit.timestamp * 1000).toISOString());
  console.log('Status:', deposit.isClaimed ? 'Claimed' : (deposit.isClaimable ? 'Claimable' : 'Pending'));
}

// Get deposits sent/received by address
const sent = await tracker.getDepositsSentBy('0x...');
const received = await tracker.getDepositsReceivedBy('0x...');

// Check if deposit can be claimed
const canClaim = await tracker.canBeClaimed(deposit);

// Batch check processed status
const statuses = await tracker.areRequestsProcessed(deposits);

API Reference

SourceChainToPodActionClient

For ETH -> Pod deposits (auto-claim on Pod).

deposit(args: {
  token: string;
  amount: string | bigint;
  destinationWalletAddress: string;
  callContract?: string;           // Contract to call on Pod after deposit (default: address(0))
  reserveBalance?: string | bigint; // Amount to reserve when using callContract (default: 0)
  from?: string;
  permit?: string;                 // Optional ERC20 permit bytes (default: '0x')
}): UnsignedTransaction

PodToSourceChainActionClient

For Pod -> ETH withdrawals and claims.

// Withdraw tokens on Pod
withdraw(args: {
  token: string;                    // Use 0xEeee...EEeE for native token
  amount: string | bigint;          // Target chain units (e.g. 1e6 for USDC)
  destinationWalletAddress: string;
  chainId: number | bigint;         // Target chain ID for claiming
  from?: string;
}): UnsignedTransaction

// Claim on ETH with proof
claim(args: {
  claimData: ClaimProofData;
  from?: string;
}): UnsignedTransaction

getBridgeClaimProof

Helper to call pod_getBridgeClaimProof RPC and format the result.

import { getBridgeClaimProof } from '@tapforce/pod-bridge-sdk';

const { proof, committeeEpoch, auxTxSuffix } = await getBridgeClaimProof(
  podProvider,      // ethers.JsonRpcProvider connected to Pod RPC
  depositTxHash     // TX hash of the deposit on Pod
);

PodBridgeTrackerClient

getDepositsSentBy(address: string, fromBlock?: number): Promise<BridgeRequest[]>
getDepositsReceivedBy(address: string, fromBlock?: number): Promise<BridgeRequest[]>
getAllDepositsFor(address: string, fromBlock?: number): Promise<BridgeRequestWithType[]>
canBeClaimed(deposit: BridgeRequest): Promise<boolean>
areRequestsProcessed(deposits: BridgeRequest[]): Promise<boolean[]>

Types

ClaimProofData

interface ClaimProofData {
  ethTokenAddress: string;  // Token address on ETH (different from Pod)
  amount: string | bigint;  // Must match deposited amount
  to: string;               // Recipient address
  proof: string;            // Hex bytes from pod_getBridgeClaimProof
  auxTxSuffix: string;      // Hex bytes from pod_getBridgeClaimProof
}

BridgeRequest

interface BridgeRequest {
  requestId: string;

  deposit: {
    chain: 'sourceChain' | 'pod';
    txHash: string;
    depositor: string;
    destination: string;
    token: string;
    amount: string;
    callContract?: string;   // Contract called after deposit (address(0) for simple bridge) — ETH only
    reserveBalance?: string; // Amount reserved when using callContract ('0' for simple bridge) — ETH only
    targetChainId?: number;  // Target chain ID for claiming (Pod→ETH direction)
    chainId: number;
    blockNumber: number;
    timestamp: number;       // Unix timestamp (seconds)
  };

  claim?: {
    chain: 'sourceChain' | 'pod';
    txHash: string;
    claimer: string;
    chainId: number;
    blockNumber: number;
    timestamp: number;
  };

  isClaimed: boolean;
  isClaimable: boolean;
}

Events

The bridge contracts emit different events per chain:

// ETH (Source Chain)
event Deposit(uint256 indexed id, address indexed from, address indexed to, address token, uint256 amount, address callContract, uint256 reserveBalance);
event Claim(bytes32 indexed txHash, address token, address mirrorToken, uint256 amount, address indexed to);

// Pod
event Withdraw(bytes32 indexed id, address indexed from, address indexed to, address token, uint256 amount, uint256 chainId);

ABIs

The SDK exports separate ABIs for each chain:

  • SOURCE_CHAIN_BRIDGE_ABI - ETH bridge (6-param deposit with callContract/reserveBalance/permit, claim with proof)
  • POD_BRIDGE_ABI - Pod bridge (withdraw with chainId, Withdraw events with bytes32 id)
  • BRIDGE_ABI - Alias for SOURCE_CHAIN_BRIDGE_ABI

Pod-specific Notes

  • Pod system contract address: 0x0000000000000000000000000000000000B41D9E
  • Pod transactions are free: use maxFeePerGas: 0, maxPriorityFeePerGas: 0, gasLimit: 0
  • Must use EIP-1559 (type 2) transactions, not legacy gasPrice
  • Pod does NOT need value set for native token deposits - the system contract handles balance internally
  • Pod returns blockNumber as a Unix timestamp in receipts

Development

npm run build   # Build
npm run clean   # Clean

Dependencies

  • ethers: ^6.15.0

License

ISC

Repository