Deposit to Mint (Wrap)
How external assets (BTC, ETH, USDC) are bridged onto JIL L1 as wrapper tokens (jBTC, jETH, jUSDC). Standard on-chain deposit, validator-gated mint via 14-of-20 multi-validator attestation (70% BFT), balance visible in Web Wallet. Asset wrapping is optional - users may hold native assets directly.
Supported Wrapper Tokens
| JIL Asset | Original | Chain | Contract | Decimals |
|---|---|---|---|---|
| jBTC | WBTC | Ethereum | 0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599 |
8 |
| jETH | ETH | Ethereum | native (0x0000...0000) | 18 |
| jUSDC | USDC | Ethereum | 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 |
6 |
Deposit to JIL L1 balance with 14-of-20 validator attestation
User deposits on the external chain, the bridge chain watcher detects the event, confirmations are tracked, validators independently attest the deposit, and only after reaching the 14-of-20 attestation threshold (70% BFT) are wrapper tokens minted on JIL L1. No single key can mint unilaterally. Asset wrapping is optional - users who prefer to hold native assets are not required to bridge.
User Deposits on External Chain
User sends BTC, ETH, or USDC to the JIL bridge contract address on Ethereum (or supported L2). The deposit is a standard on-chain transfer - no special tooling required.
Bridge Chain Watcher Detects Deposit
The chain watcher monitors event logs on the source chain. When a deposit to the bridge contract is detected, it records the deposit via the bridge-relayer API. POST /v1/deposit
Confirmation Tracking
Watcher sends per-block confirmation updates until the chain-specific threshold is met. ETH: 12 confirmations (~2.4 min). BTC: 6 confirmations (~60 min). Arbitrum: 1 confirmation (~250ms). POST /v1/deposit/:id/confirmations
Multi-Validator Attestation
Each validator independently verifies the deposit on the source chain, computes a deterministic deposit hash, signs it with their Ed25519 key, and submits an attestation. POST /v1/deposit/:id/attest. Minting is validator-gated and blocked until the 14-of-20 BFT threshold (70%) is reached. No single key can mint unilaterally. When ZK bridge proofs are enabled, a Groth16 zero-knowledge proof is generated alongside validator attestations, providing cryptographic verification that the deposit commitment is valid without revealing the depositor's identity or amount.
Attestation Threshold Met - Auto-Mint
Once 14-of-20 validators attest the deposit, the bridge-relayer signs a PaymentTx from bridge_authority to the user. Proof-of-reserves is verified before minting proceeds. The ledger records the wrapper token in the user's balance. No single key can mint unilaterally.
User Sees Wrapper Balance
The user's jBTC/jETH/jUSDC balance is now visible in the Web Wallet. Balance is queried from the ledger via wallet API. GET /state/accounts/{account_id}/balances
Bridge Authority Account Pattern
- The JIL L1 ledger (jil5600-core) only supports PaymentTx - no native mint or burn opcodes.
- "Minting" = Payment from bridge_authority to user account (Ed25519-signed by bridge key), validator-gated by 14-of-20 multi-validator attestation. No single key can mint unilaterally.
- "Burning" = Payment from user to bridge_authority (passkey-signed by user).
- The bridge_authority account is pre-funded with the max supply of each wrapper asset at bootstrap.
- Multi-validator attestation gate: Validators independently verify deposits on-chain, sign a deterministic deposit hash, and submit attestations. Minting only proceeds after the 14-of-20 threshold (70% BFT) is reached.
- Circuit breakers: Bridge can be paused (admin or auto-triggered), daily outflow caps per asset, proof-of-reserves enforced on both minting and withdrawals.
- Optional wrapping: Asset wrapping is optional. Users may hold and transact with native assets on JIL L1 without bridging. Wrapping is available for users who want to bring external assets on-chain.
- No Rust L1 engine changes were required to support wrapper tokens.
Time to finality varies significantly by source chain
Database Tables
bridge_deposits
id UUID PRIMARY KEY nonce BIGINT NOT NULL source_chain TEXT NOT NULL -- e.g. "eth", "btc" depositor TEXT NOT NULL -- external address token TEXT NOT NULL -- original token address amount NUMERIC NOT NULL recipient TEXT NOT NULL -- JIL L1 account ID tx_hash TEXT NOT NULL -- source chain tx hash block_number BIGINT NOT NULL status TEXT NOT NULL -- pending | confirmed | minted | failed confirmations INT DEFAULT 0 jil_mint_tx_hash TEXT -- L1 PaymentTx hash after mint wrapper_asset TEXT NOT NULL -- jBTC | jETH | jUSDC
bridge_wrapper_tokens
id TEXT PRIMARY KEY -- e.g. "jbtc-eth-wbtc" jil_asset TEXT NOT NULL -- jBTC | jETH | jUSDC original_chain TEXT NOT NULL -- eth original_token TEXT NOT NULL -- contract address decimals INT NOT NULL total_minted NUMERIC DEFAULT 0 total_burned NUMERIC DEFAULT 0
bridge_checkpoints
chain TEXT PRIMARY KEY -- e.g. "eth", "btc" last_block BIGINT NOT NULL -- last processed block number
Key Endpoints
| Service | Endpoint | Method | Purpose |
|---|---|---|---|
| bridge-relayer | /v1/deposit | POST | Record new deposit from chain watcher |
| bridge-relayer | /v1/deposit/:id/confirmations | POST | Update confirmation count; triggers auto-mint at threshold |
| bridge-relayer | /v1/deposit/:id/mint | POST | Manually trigger mint for a confirmed deposit (operator) |
| bridge-relayer | /v1/wrapper-tokens | GET | List registered wrapper tokens with mint/burn totals |
| bridge-relayer | /v1/reserves | GET | Proof-of-reserves: minted vs deposited per asset |
| wallet-api | /wallet/wrapped-assets | GET | User-facing: list available wrapper tokens |
| wallet-api | /wallet/wrap/quote | POST | User-facing: get deposit address + confirmation estimates |
Environment Variables
| Variable | Service | Purpose |
|---|---|---|
BRIDGE_AUTHORITY_ACCOUNT |
bridge-relayer, wallet-api | L1 account ID for mint/burn payments (default: bridge_authority) |
BRIDGE_AUTHORITY_KEY_B64U |
bridge-relayer | Ed25519 private key (base64url, PKCS8 DER) for signing mint PaymentTx |
LEDGER_SERVICE_URL |
bridge-relayer | Ledger API base URL (default: http://ledger-service:8081) |
JIL_NETWORK_ID |
bridge-relayer | Network ID for tx challenge string (mainnet: jil-mainnet-1) |
JIL_ENABLE_DEV_ENDPOINTS |
bridge-relayer | Set 1 to enable auto-fund via faucet (dev only) |
BRIDGE_RELAYER_URL |
wallet-api | Bridge-relayer API base URL (default: http://bridge-relayer:8150) |
Key Source Files
Wrapper Token Migration
services/bridge-relayer/migrations/002_wrapper_tokens.sql - Migration: wrapper token table + seed data (jBTC, jETH, jUSDC)
Bridge Relayer
services/bridge-relayer/src/index.ts - Wrapper registry, auto-mint logic, bridge authority, API endpoints
Wallet Wrap/Unwrap
services/wallet-api/src/routes/wallet.ts - User-facing wrap/unwrap endpoints
Kafka Events
services/wallet-api/src/services/kafka.ts - UNWRAP_SUBMITTED event type for Kafka
Deposit on Ethereum. Validator-Gated Mint on JIL L1.
Optionally bridge BTC, ETH, or USDC onto JIL L1 as wrapper tokens with 14-of-20 validator attestation, proof-of-reserves enforcement, and Ed25519-signed minting. No single key can mint unilaterally.