> ## Documentation Index
> Fetch the complete documentation index at: https://privacycash.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Bridge

> Bridge from EVM Privacy Cash pools to other chains

## Overview

Bridging from an EVM Privacy Cash pool is a three-step process:

1. **Quote** — Request a bridge quote and a one-time 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 EVM bridge API endpoint is: `https://evm.privacycash.org/bridge`

***

## Supported Output Chains

| Output Chain | Tokens               |
| ------------ | -------------------- |
| Solana       | SOL, USDT, USDC      |
| Ethereum     | ETH, USDC, USDT, DAI |
| BNB Chain    | BNB, USDC, USDT      |
| Polygon      | POL, USDC, USDT      |
| Bitcoin      | BTC                  |

Supported input pools are Base ETH/USDC and Ethereum ETH/USDT.

***

## Prerequisites

```bash theme={null}
npm install privacycash-evm ethers --save
```

***

## Implementation

The example below bridges ETH. For ERC-20 inputs, set `inputTokenName` and `token` to the supported token for the selected network: `usdc` on Base or `usdt` on Ethereum.

```typescript theme={null}
import { BASE_NETWORK, ETH_NETWORK, withdraw } from 'privacycash-evm'

const BRIDGE_URL = 'https://evm.privacycash.org/bridge'
const MINIMUM_BRIDGE_AMOUNT = 0.005 // ETH
const RENT_FEE = 0.00025
const FEE_RATE = 35 // basis points, 0.35%

/**
 * 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 network = ETH_NETWORK // or BASE_NETWORK
    const inputChain = network.chainKey === 'eth' ? 'ethereum' : 'base'
    const inputTokenName = 'eth' as const

    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,
        outputChain: 'ethereum',           // see supported chains above
        inputTokenName,
        outputTokenName: 'eth',            // token on the destination chain
        inputTokenAmount: withdrawableAmount.toFixed(8),
        refundAddress: address,            // your EVM 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 the selected EVM network
    const txHash = await withdraw({
        withdrawAmountInput: totalWithdrawAmount,
        recipient: depositAddress,           // relayer's one-time EVM address
        keyBasePath: '/circuit',
        signature,
        address,
        token: inputTokenName,
        network,
    })

    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 fee** — `RENT_FEE` (0.00025 ETH)
2. **Privacy Cash rate fee** — `FEE_RATE` (0.35% of withdrawal amount)

Pass the *net* amount (`withdrawableAmount`) to the quote API so the relayer knows exactly how much input token 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

ETH input uses a **0.005 ETH** minimum. Stable-token inputs should use the relayer minimum returned by the quote flow.

### 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.
