Skip to content

Multi-chain support with automatic chain detection and routing #7

@AnkanMisra

Description

@AnkanMisra

Summary

Enable payment acceptance from multiple L2 chains (Base, Arbitrum, Optimism, Polygon) with dynamic chain selection and unified verification.

Motivation

Currently, MicroAI Paygate only supports Base (Chain ID 8453). As L2 adoption grows, users may prefer paying from their primary chain. Supporting multiple chains:

  • Reduces friction - Users don't need to bridge funds
  • Increases adoption - Access wider user base
  • Future-proofs - Easy to add new chains

Proposed Architecture

flowchart TB
    subgraph Client[Client Layer]
        WEB[Web Frontend]
        AGENT[Agent Bot]
    end

    subgraph Gateway[Multi-Chain Gateway]
        GW[Gateway Service]
        
        subgraph Registry[Chain Registry]
            BASE[Base - 8453]
            ARB[Arbitrum - 42161]
            OP[Optimism - 10]
            POLY[Polygon - 137]
        end
    end

    subgraph Verifier[Verification Layer]
        VER[Verifier Service]
    end

    WEB --> GW
    AGENT --> GW
    GW --> Registry
    GW <--> VER
    
    BASE -.-> VER
    ARB -.-> VER
    OP -.-> VER
    POLY -.-> VER
Loading

Request Flow

sequenceDiagram
    participant C as Client
    participant G as Gateway
    participant V as Verifier

    C->>G: POST with X-402-ChainId: 42161
    G->>G: Validate chainId in registry
    G->>V: Verify with Arbitrum domain
    V-->>G: is_valid
    G-->>C: 200 OK
Loading

Supported Chains (Phase 1)

Chain ID USDC Address Explorer
Base 8453 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 basescan.org
Arbitrum 42161 0xaf88d065e77c8cC2239327C5EDb3A432268e5831 arbiscan.io
Optimism 10 0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85 optimistic.etherscan.io
Polygon 137 0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359 polygonscan.com

Implementation Details

Chain Configuration

Create config/chains.json:

{
  "chains": [
    {
      "id": 8453,
      "name": "Base",
      "enabled": true,
      "rpcUrl": "${BASE_RPC_URL}",
      "usdc": {
        "address": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
        "decimals": 6
      },
      "blockTime": 2,
      "explorer": "https://basescan.org"
    },
    {
      "id": 42161,
      "name": "Arbitrum",
      "enabled": true,
      "rpcUrl": "${ARBITRUM_RPC_URL}",
      "usdc": {
        "address": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
        "decimals": 6
      },
      "blockTime": 0.25,
      "explorer": "https://arbiscan.io"
    }
  ]
}

Updated 402 Response

{
  "error": "Payment Required",
  "paymentContext": {
    "recipient": "0x...",
    "amount": "0.001",
    "token": "USDC",
    "nonce": "uuid"
  },
  "supportedChains": [
    { "id": 8453, "name": "Base", "recommended": true },
    { "id": 42161, "name": "Arbitrum" },
    { "id": 10, "name": "Optimism" },
    { "id": 137, "name": "Polygon" }
  ]
}

New Request Headers

Header Description Example
X-402-ChainId Chain used for payment 42161
X-402-Signature EIP-712 signature 0x...
X-402-Nonce Payment nonce uuid

EIP-712 Domain Updates

The domain separator must include the correct chainId:

const domain = {
  name: "MicroAI Paygate",
  version: "1",
  chainId: selectedChainId,  // Dynamic based on user selection
  verifyingContract: ethers.ZeroAddress,
};

Verifier Updates (Rust)

// Parse chainId from request and validate against allowed chains
fn verify_signature(
    Json(payload): Json<VerifyRequest>,
) -> (StatusCode, Json<VerifyResponse>) {
    let chain_id = payload.context.chain_id;
    
    // Validate chain is supported
    if !SUPPORTED_CHAINS.contains(&chain_id) {
        return (StatusCode::BAD_REQUEST, Json(VerifyResponse {
            is_valid: false,
            error: Some("Unsupported chain".to_string()),
            ..Default::default()
        }));
    }
    
    // Build domain with correct chainId
    let domain = build_domain(chain_id);
    // ... rest of verification
}

Acceptance Criteria

Backend

  • Create chain configuration system (config/chains.json)
  • Update 402 response to include supportedChains[]
  • Add X-402-ChainId header parsing in Gateway
  • Validate chainId against supported list
  • Update EIP-712 domain construction to use request chainId
  • Add per-chain USDC address resolution
  • Implement chain-specific RPC routing (for on-chain verification)

Frontend

  • Add chain selector dropdown in UI
  • Display supported chains from 402 response
  • Auto-detect user's current chain from wallet
  • Prompt chain switch if needed
  • Include chainId in signed data

Testing & Docs

  • Add unit tests for each supported chain
  • E2E tests with multi-chain scenarios
  • Update README with supported chains
  • Document chain addition process

Frontend Chain Selector UX

┌─────────────────────────────────────────────┐
│  Select Payment Chain                       │
├─────────────────────────────────────────────┤
│  ◉ Base (Recommended)         ~$0.001 fee   │
│  ○ Arbitrum                   ~$0.002 fee   │
│  ○ Optimism                   ~$0.001 fee   │
│  ○ Polygon                    ~$0.0001 fee  │
└─────────────────────────────────────────────┘

Future Considerations

  • Dynamic pricing per chain (gas cost differences)
  • Chain health monitoring (disable chains with issues)
  • Priority chains for faster confirmation
  • Cross-chain recipient address management

PR Requirements

⚠️ All PRs must include tests. PRs without adequate test coverage will not be merged.

  • Unit tests for chain configuration loading
  • Unit tests for EIP-712 domain construction per chain
  • Unit tests for Rust verifier chain validation
  • Integration tests for multi-chain signature verification
  • Frontend tests for chain selector component
  • Tests must pass: go test -v ./..., cargo test, and bun test

Metadata

Metadata

Assignees

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions