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

# Ripio Bridge

> Move wFiat stablecoins between chains with the Ripio Bridge: a burn-and-mint contract you integrate with a single call. Addresses, quickstart, function reference, events and status API.

The Ripio Bridge moves wFiat stablecoins between chains with a **burn-and-mint** model: tokens are burned on the source chain and minted on the destination chain by the bridge operator. Integrating takes a single contract call, with no SDK required.

> [!NOTE]
>
> The bridge is a smart contract and Ripio does not intermediate in bridge transactions. To bridge from a browser instead of code, use [bridge.ripio.com](https://bridge.ripio.com).

## How it works

**1. Deposit on the source chain**

You call `depositForBridge()` on the source chain. The token amount, minus the route's fixed fee, is burned and a `BridgeDepositInitiated` event is emitted.

**2. Finality**

The bridge operator observes the event and waits for source-chain finality.

**3. Mint on the destination chain**

The operator mints the bridged amount to your recipient on the destination chain and emits `BridgeMintFulfilled`. Minting is idempotent: exactly one mint per deposit.

The `BridgeDeposit` contract is deployed at the same address on every supported chain and is verified on every explorer. Source code: [BridgeDeposit.sol on GitHub](https://github.com/ripio/latam-stables/blob/main/src/BridgeDeposit.sol).

## Addresses

### BridgeDeposit

`0x465e642387d3d73a57CDc1368fFA53A800bA5D47` on every chain:

| Chain | Chain ID | Explorer |
| - | :-: | - |
| Ethereum | 1 | [View contract](https://etherscan.io/address/0x465e642387d3d73a57CDc1368fFA53A800bA5D47) |
| Base | 8453 | [View contract](https://basescan.org/address/0x465e642387d3d73a57CDc1368fFA53A800bA5D47) |
| World Chain | 480 | [View contract](https://worldscan.org/address/0x465e642387d3d73a57CDc1368fFA53A800bA5D47) |
| BNB Smart Chain | 56 | [View contract](https://bscscan.com/address/0x465e642387d3d73a57CDc1368fFA53A800bA5D47) |
| Polygon | 137 | [View contract](https://polygonscan.com/address/0x465e642387d3d73a57CDc1368fFA53A800bA5D47) |
| Gnosis | 100 | [View contract](https://gnosisscan.io/address/0x465e642387d3d73a57CDc1368fFA53A800bA5D47) |
| Celo | 42220 | [View contract](https://celoscan.io/address/0x465e642387d3d73a57CDc1368fFA53A800bA5D47) |
| HyperEVM | 999 | [View contract](https://hyperevmscan.io/address/0x465e642387d3d73a57CDc1368fFA53A800bA5D47) |
| Arc | 5042 | [View contract](https://explorer.arc.io/address/0x465e642387d3d73a57CDc1368fFA53A800bA5D47) |

### Stablecoins

Each token uses the same address on every chain that supports it, and all of them have 18 decimals.

| Token | Address | Chains |
| - | - | - |
| wARS | `0x0DC4F92879B7670e5f4e4e6e3c801D229129D90D` | All |
| wBRL | `0xD76f5Faf6888e24D9F04Bf92a0c8B921FE4390e0` | All |
| wMXN | `0x337E7456B420bD3481e7FA61fA9850343d610d34` | All except HyperEVM |
| wPEN | `0x4F34c8b3b5FB6D98Da888F0feA543d4d9C9F2eBE` | All except HyperEVM |
| wCLP | `0x61D450a098b6a7f69fC4b98CE68198fe59768651` | All except HyperEVM |
| wCOP | `0x8a1D45e102e886510e891d2Ec656a708991e2D76` | All except HyperEVM |

> [!NOTE]
>
> HyperEVM only supports wARS and wBRL on the bridge so far. Check [`routeConfigs`](#1-check-the-route-and-its-fee) before assuming a token and chain pair is live.

## Quickstart

The examples below use [viem](https://viem.sh/), but any EVM tooling works.

### 0. Constants and ABI

```ts constants.ts theme={null}
// BridgeDeposit — same address on every supported chain
const BRIDGE_DEPOSIT = '0x465e642387d3d73a57CDc1368fFA53A800bA5D47';

// Supported chain ids
const CHAINS = {
  ethereum: 1,
  base: 8453,
  worldchain: 480,
  bsc: 56,
  polygon: 137,
  gnosis: 100,
  celo: 42220,
  hyperevm: 999,
  arc: 5042,
};

// Stablecoins — same address on every supported chain, all 18 decimals
const TOKENS = {
  wARS: '0x0DC4F92879B7670e5f4e4e6e3c801D229129D90D',
  wBRL: '0xD76f5Faf6888e24D9F04Bf92a0c8B921FE4390e0',
  wMXN: '0x337E7456B420bD3481e7FA61fA9850343d610d34',
  wPEN: '0x4F34c8b3b5FB6D98Da888F0feA543d4d9C9F2eBE',
  wCLP: '0x61D450a098b6a7f69fC4b98CE68198fe59768651',
  wCOP: '0x8a1D45e102e886510e891d2Ec656a708991e2D76',
};
```

```ts abi.ts theme={null}
import { parseAbi } from 'viem';

// Minimal ABI — enough for a full integration.
// Full ABI: verified contract on any block explorer, or the source on GitHub.
const BRIDGE_ABI = parseAbi([
  'function depositForBridge(address token, uint256 amount, uint256 destChainId, address destRecipient, bytes32 clientDepositId) returns (uint256 depositId)',
  'function routeConfigs(address token, uint256 destChainId) view returns (bool enabled, uint256 fixedFee)',
  'function remainingMintCapacity(address token) view returns (uint256 remaining, uint256 dailyMaxMint, uint256 mintedToday)',
  'event BridgeDepositInitiated(uint256 indexed depositId, address indexed token, address indexed from, uint256 amount, uint256 destChainId, address destRecipient, bytes32 clientDepositId)',
  'event BridgeMintFulfilled(address indexed token, address indexed to, uint256 amount, uint256 sourceChainId, bytes32 sourceTxHash, uint256 indexed sourceDepositId)',
]);

const ERC20_ABI = parseAbi([
  'function approve(address spender, uint256 amount) returns (bool)',
  'function allowance(address owner, address spender) view returns (uint256)',
]);
```

### 1. Check the route and its fee

Every route (token and destination chain) must be enabled, and carries a fixed fee that is deducted from the deposited amount. Check it before depositing:

```ts check-route.ts theme={null}
import { createPublicClient, http, formatUnits } from 'viem';
import { mainnet } from 'viem/chains';

const publicClient = createPublicClient({ chain: mainnet, transport: http() });

// Check the wARS route from Ethereum (1) to Base (8453)
const [enabled, fixedFee] = await publicClient.readContract({
  address: BRIDGE_DEPOSIT,
  abi: BRIDGE_ABI,
  functionName: 'routeConfigs',
  args: [TOKENS.wARS, 8453n],
});

if (!enabled) throw new Error('Route is not enabled');
console.log(`Fixed fee: ${formatUnits(fixedFee, 18)} wARS`);
```

You can also see the enabled routes and their current fees, read live on-chain, at [bridge.ripio.com/developers](https://bridge.ripio.com/developers).

### 2. Approve and deposit

The caller must first approve the `BridgeDeposit` contract for at least `amount`: the contract burns through `burnFrom` and pulls the fee through `transferFrom`.

```ts deposit.ts theme={null}
import { keccak256, encodePacked, parseUnits, parseEventLogs, pad } from 'viem';

const amount = parseUnits('1000', 18); // total, inclusive of the route's fixed fee

// 1. Approve the BridgeDeposit contract for at least `amount`
//    (the contract pulls via burnFrom + transferFrom)
const approveHash = await walletClient.writeContract({
  address: TOKENS.wARS,
  abi: ERC20_ABI,
  functionName: 'approve',
  args: [BRIDGE_DEPOSIT, amount],
});
await publicClient.waitForTransactionReceipt({ hash: approveHash });

// 2. Optional: your own id for off-chain correlation.
//    Echoed in BridgeDepositInitiated. Use pad('0x0', { size: 32 }) to skip.
const clientDepositId = keccak256(encodePacked(
  ['address', 'uint256', 'uint256'],
  [account.address, BigInt(Date.now()), BigInt(myInternalOrderId)],
));

// 3. Initiate the bridge — burns on the source chain
const depositHash = await walletClient.writeContract({
  address: BRIDGE_DEPOSIT,
  abi: BRIDGE_ABI,
  functionName: 'depositForBridge',
  args: [
    TOKENS.wARS,   // token
    amount,        // total amount (fee is deducted from it)
    8453n,         // destination chain id (Base)
    recipient,     // recipient on destination — can differ from sender
    clientDepositId,
  ],
});

// 4. Extract the depositId from the BridgeDepositInitiated event
const receipt = await publicClient.waitForTransactionReceipt({ hash: depositHash });
const [initiated] = parseEventLogs({
  abi: BRIDGE_ABI,
  eventName: 'BridgeDepositInitiated',
  logs: receipt.logs,
});
console.log('depositId:', initiated.args.depositId);
```

### 3. Watch for fulfillment on the destination chain

```ts watch.ts theme={null}
import { createPublicClient, http } from 'viem';
import { base } from 'viem/chains';

// Watch on the DESTINATION chain
const destClient = createPublicClient({ chain: base, transport: http() });

const unwatch = destClient.watchContractEvent({
  address: BRIDGE_DEPOSIT,
  abi: BRIDGE_ABI,
  eventName: 'BridgeMintFulfilled',
  args: { to: recipient },
  onLogs: (logs) => {
    for (const log of logs) {
      // Idempotent: exactly one mint per (sourceChainId, sourceDepositId)
      console.log('Minted', log.args.amount, 'for deposit', log.args.sourceDepositId);
    }
  },
});
```

### 4. Check mint capacity before large transfers

Minting is subject to a daily cap per token, per chain. Check the capacity on the **destination** chain before large transfers: deposits above the remaining capacity are queued until the cap resets.

```ts capacity.ts theme={null}
const [remaining, dailyMaxMint, mintedToday] = await destClient.readContract({
  address: BRIDGE_DEPOSIT,
  abi: BRIDGE_ABI,
  functionName: 'remainingMintCapacity',
  args: [TOKENS.wARS],
});

if (amount > remaining) {
  console.warn('Transfer exceeds remaining daily capacity — it will be queued');
}
```

## Function reference

### depositForBridge

```solidity theme={null}
function depositForBridge(
    address token,           // stable to bridge
    uint256 amount,          // total amount, inclusive of the route's fixed fee
    uint256 destChainId,     // destination chain id
    address destRecipient,   // recipient on destination (can differ from sender)
    bytes32 clientDepositId  // optional, your own id for off-chain correlation
) returns (uint256 depositId)
```

| Parameter | Description |
| - | - |
| `token` | Address of the stablecoin to bridge (see the [token table](#stablecoins)). |
| `amount` | Total amount to pull from the caller, inclusive of the route's fixed fee. The recipient receives `amount − fixedFee`, so `amount` must exceed the fee. |
| `destChainId` | Destination chain ID. The `(token, destChainId)` route must be enabled. |
| `destRecipient` | Recipient on the destination chain. It can differ from the sender. |
| `clientDepositId` | Optional `bytes32` of your choosing, echoed in `BridgeDepositInitiated` for off-chain correlation. Pass `bytes32(0)` if unused. |

**Requirements**

* The ERC-20 allowance for the `BridgeDeposit` contract must be greater than or equal to `amount`.
* The `(token, destChainId)` route must be enabled. Check it with `routeConfigs`.
* Minting on the destination chain is subject to a daily cap. Check `remainingMintCapacity(token)` on the destination chain: deposits above the remaining capacity are queued until the cap resets.

### routeConfigs

```solidity theme={null}
function routeConfigs(address token, uint256 destChainId)
    view returns (bool enabled, uint256 fixedFee)
```

Returns whether the route from the current chain to `destChainId` is enabled for `token`, and its fixed fee in token units (18 decimals).

### remainingMintCapacity

```solidity theme={null}
function remainingMintCapacity(address token)
    view returns (uint256 remaining, uint256 dailyMaxMint, uint256 mintedToday)
```

Returns the remaining mint capacity for `token` on the current chain, the daily maximum and the amount minted today. Capacity resets daily.

## Events

### BridgeDepositInitiated

Emitted on the **source** chain.

| Field | Indexed | Description |
| - | :-: | - |
| `depositId` | Yes | Sequential ID assigned by the contract |
| `token` | Yes | Bridged stablecoin |
| `from` | Yes | Depositor |
| `amount` | No | Total amount, inclusive of the fee |
| `destChainId` | No | Destination chain ID |
| `destRecipient` | No | Recipient on the destination chain |
| `clientDepositId` | No | Caller-supplied correlation ID |

### BridgeMintFulfilled

Emitted on the **destination** chain.

| Field | Indexed | Description |
| - | :-: | - |
| `token` | Yes | Minted stablecoin |
| `to` | Yes | Recipient |
| `amount` | No | Amount minted (deposit amount minus fee) |
| `sourceChainId` | No | Chain where the deposit was made |
| `sourceTxHash` | No | Deposit transaction hash |
| `sourceDepositId` | Yes | The `depositId` from the source chain |

Fulfillment is idempotent: exactly one mint per `(sourceChainId, sourceDepositId)` pair.

## Tracking and status API

For off-chain correlation, generate a unique `clientDepositId` per transfer, for example `keccak256(abi.encodePacked(sender, timestamp, yourInternalId))`, and match it against the `BridgeDepositInitiated` event.

You can also poll the public status API with the deposit transaction hash:

```bash theme={null}
# Look up a bridge operation by its source transaction hash
curl "https://bridge.ripio.com/api/operations/{sourceTxHash}?chainId=1"

# List operations for an address (add &pending=true for in-flight only)
curl "https://bridge.ripio.com/api/operations?address=0xYourAddress&limit=20"
```

```json GET /api/operations/{txHash} — 200 theme={null}
{
  "operation": {
    "id": "…",
    "source_chain_id": 1,
    "source_tx_hash": "0x…",
    "dest_chain_id": 8453,
    "dest_tx_hash": "0x…",
    "deposit_id": "42",
    "token_symbol": "wARS",
    "token_address": "0x0DC4F92879B7670e5f4e4e6e3c801D229129D90D",
    "from_address": "0x…",
    "dest_recipient": "0x…",
    "amount_in": "1000000000000000000000",
    "fee_amount": "…",
    "amount_out": "…",
    "status": "COMPLETED",
    "error_reason": null,
    "created_at": "2026-07-21T12:00:00.000Z",
    "updated_at": "2026-07-21T12:15:00.000Z"
  }
}
```

Amounts are returned as raw integer strings with 18 decimals. The `status` field follows this lifecycle:

| Status | Meaning |
| - | - |
| `DETECTED` | Deposit transaction observed on the source chain |
| `PENDING_FINALITY` | Waiting for source-chain confirmations |
| `READY_FOR_MINT` | Finality reached, mint being prepared |
| `QUEUED_DAILY_LIMIT` | Amount exceeds the remaining daily mint capacity; queued until the cap resets |
| `MINTING` | Mint transaction submitted on the destination chain |
| `COMPLETED` | Tokens minted to the destination recipient |
| `FAILED` | Operation failed; see `error_reason` |

## Questions?

Write to [b2b@ripio.com](mailto:b2b@ripio.com) and the team will walk you through a test integration.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.