Skip to content

Mock Bridge

The Mock Bridge is a test deposit relayer that verifies user EIP-712 signatures and submits Kaizen:Deposit transactions to Kaizen Core.

Overview

In production, a bridge relayer would:

  1. Watch L1 deposit events
  2. Submit Deposit transactions to Kaizen Core with the L1 tx hash

The mock bridge simulates this by:

  1. Accepting signed deposit requests from users
  2. Generating mock external tx hashes
  3. Submitting Deposit transactions to Kaizen Core

Running

# Start on default port (3000)
pnpm run --filter @kaizen-core/mock-bridge dev
 
# Custom port
pnpm run --filter @kaizen-core/mock-bridge dev -- --port 3002
 
# With custom RPC
pnpm run --filter @kaizen-core/mock-bridge dev -- --rpc-url http://localhost:8545

CLI Options

OptionDescriptionDefault
-p, --port <port>HTTP server port3000
-r, --rpc-url <url>Kaizen Core RPC URLhttp://localhost:8545
-k, --private-key <key>Bridge relayer private key (0x...)From env

Environment Variables

VariableDescription
KAIZEN_RPC_URLKaizen Core RPC URL
BRIDGE_PRIVATE_KEYBridge relayer wallet private key

API Reference

GET /health

Health check endpoint.

Response
{
  "status": "healthy",
  "rpc": true,
  "bridge": "0x...",
  "timestamp": 1700000000000
}

GET /info

Bridge info.

Response
{
  "name": "Kaizen Bridge (Test)",
  "version": "0.1.0",
  "bridge": "0x...",
  "rpcUrl": "http://localhost:8545"
}

GET /typed-data

Get EIP-712 typed data for signing deposits.

Response
{
  "domain": {
    "name": "Kaizen Bridge",
    "version": "1",
    "chainId": 1
  },
  "types": {
    "Kaizen:Deposit": [
      { "name": "user", "type": "address" },
      { "name": "amount", "type": "uint256" },
      { "name": "nonce", "type": "uint256" },
      { "name": "deadline", "type": "uint256" }
    ]
  },
  "primaryType": "Kaizen:Deposit"
}

POST /deposit

Process a signed deposit request.

Request Body
{
  "user": "0x...",
  "amount": "1000000000",
  "nonce": "1",
  "deadline": 1700000060000,
  "signature": "0x..."
}
FieldTypeDescription
userstringUser address to credit
amountstringDeposit amount (6 decimals for USDC)
noncestringUnique nonce to prevent replay attacks
deadlinenumberRequest deadline (Unix timestamp in ms)
signaturestringEIP-712 signature (65 bytes hex)
Response (Success)
{
  "success": true,
  "txHash": "0x..."
}
Response (Error)
{
  "success": false,
  "error": "Deposit request expired"
}

Deposit Flow

Bridge Deposit Flow

EIP-712 Signing Example

import { signTypedData } from "viem/accounts";
 
// 1. Get typed data from bridge
const response = await fetch("http://localhost:3000/typed-data");
const { domain, types, primaryType } = await response.json();
 
// 2. Build deposit message
const message = {
  user: walletAddress,
  amount: 1000000000n, // 1000 USDC
  nonce: 1n,
  deadline: BigInt(Date.now() + 5 * 60 * 1000), // 5 min
};
 
// 3. Sign with wallet
const signature = await signTypedData({
  domain,
  types,
  primaryType,
  message,
});
 
// 4. Submit to bridge
const result = await fetch("http://localhost:3000/deposit", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    user: walletAddress,
    amount: message.amount.toString(),
    nonce: message.nonce.toString(),
    deadline: Number(message.deadline),
    signature,
  }),
});

Security Notes

Transaction Type

The bridge submits Kaizen:Deposit transactions to Core:

struct DepositTx {
    user: Address,           // User receiving funds
    amount: u64,             // Deposit amount
    external_tx_hash: B256,  // L1 tx hash (mock in test)
}

EIP-712 Type: Kaizen:Deposit(uint64 timestamp,address from,address user,uint64 amount,bytes32 externalTxHash)

Permission: Relayer only