Skip to main content

Overview

Bridging from Base with Privacy Cash is a three-step process:
  1. Quote — Request a bridge quote and a one-time Base deposit address from the relayer.
  2. Private Withdrawal — Execute a Privacy Cash withdrawal where the recipient is the relayer’s deposit address.
  3. Notify — Tell the relayer your transaction hash so it can release funds on the destination chain.
The bridge API endpoint for Base is: https://evm.privacycash.org/bridge

Supported Output Chains

Output ChainTokens
SolanaSOL, USDT, USDC
EthereumETH, USDC, USDT, DAI
BNB ChainBNB, USDC, USDT
PolygonPOL, USDC, USDT
BitcoinBTC
The input is always ETH on Base.

Prerequisites

npm install privacycash-evm ethers --save

Implementation

import { withdraw, RENT_FEE, FEE_RATE } from 'privacycash-evm'

const BRIDGE_URL = 'https://evm.privacycash.org/bridge'
const MINIMUM_BRIDGE_AMOUNT = 0.005 // ETH

/**
 * Calculate how much ETH the relayer will actually receive after
 * Privacy Cash withdrawal fees are deducted from the user's balance.
 */
function calculateWithdrawableAmount(totalAmount: number): number {
    const flatFee = RENT_FEE                              // 0.00025 ETH
    const rateFee = (totalAmount * FEE_RATE) / 10000      // 0.35%
    return totalAmount - flatFee - rateFee
}

async function runBridge(address: string, signature: string) {

    const totalWithdrawAmount = 0.1   // ETH you will deduct from your private balance
    const recipientAddress   = '0xRECIPIENT_ADDRESS'  // destination address on output chain

    if (totalWithdrawAmount < MINIMUM_BRIDGE_AMOUNT) {
        throw new Error(`Minimum bridge amount is ${MINIMUM_BRIDGE_AMOUNT} ETH`)
    }

    // Net amount the relayer receives (after Privacy Cash fees)
    const withdrawableAmount = calculateWithdrawableAmount(totalWithdrawAmount)

    const params = {
        inputChain: 'base',
        outputChain: 'ethereum',           // see supported chains above
        inputTokenName: 'eth',             // always 'eth' for Base
        outputTokenName: 'eth',            // token on the destination chain
        inputTokenAmount: withdrawableAmount.toFixed(8),
        refundAddress: address,            // your Base address for refunds
        recipientAddress,                  // destination address
        quoteWaitingTimeMs: 3000,          // recommended delay for best routing
    }

    // STEP 1: Get quote and relayer deposit address
    const quoteResponse = await fetch(BRIDGE_URL, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ ...params, step: 'quote' }),
    })

    const quoteData = await quoteResponse.json()
    if (!quoteData.success) throw new Error(quoteData.error || 'Failed to get quote')

    const depositAddress: string = quoteData.quote.depositAddress
    console.log('Relayer deposit address:', depositAddress)
    console.log('Estimated output:', quoteData.quote.amountOutFormatted)

    // STEP 2: Withdraw to the relayer's deposit address on Base
    const txHash = await withdraw({
        withdrawAmountInput: totalWithdrawAmount,
        recipient: depositAddress,           // relayer's one-time Base address
        keyBasePath: '/circuit',
        signature,
        address,
    })

    console.log('Withdrawal tx:', txHash)

    // STEP 3: Notify the relayer of the transaction hash
    const notifyResponse = await fetch(BRIDGE_URL, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
            txHash,
            depositAddress,
            step: 'send_tx',
        }),
    })

    const notifyData = await notifyResponse.json()
    if (notifyData.success) {
        console.log('Bridge successfully initiated!')
    } else {
        console.error('Relayer notification failed:', notifyData.error)
    }
}

Key Considerations

Fee Calculation

Two types of fees are deducted from withdrawAmountInput:
  1. Privacy Cash flat feeRENT_FEE (0.00025 ETH)
  2. Privacy Cash rate feeFEE_RATE (0.35% of withdrawal amount)
Pass the net amount (withdrawableAmount) to the quote API so the relayer knows exactly how much ETH it will receive.

Address Validation

Validate the recipient address format before calling the quote API:
  • EVM chains (Ethereum, BNB, Polygon): 0x + 40 hex characters
  • Solana: Base58 string (32–44 characters)
  • Bitcoin: Bech32 (bc1...) or legacy format

Minimum Amount

0.005 ETH

Quote Freshness

Quotes expire quickly due to market price movement. Re-fetch the quote if more than ~5 seconds have passed before submitting the withdrawal.