Skip to content

Cloud Run Multichain Backend Rollout

这页属于高级接入参考,适合需要自建统一多链 backend、回扫链上事件和运维部署链路的团队。

当前架构已经改成:

  • 一个 Cloud Run backend 服务
  • 进程内同时管理 Base / Arbitrum / BSC 运行时
  • Alchemy webhook 按链打到 /webhooks/alchemy/:chainId
  • 不再有 control-plane / executor 分拆

Step 1: Enable required GCP APIs

bash
gcloud services enable \
  run.googleapis.com \
  cloudbuild.googleapis.com \
  artifactregistry.googleapis.com \
  secretmanager.googleapis.com \
  firestore.googleapis.com \
  cloudscheduler.googleapis.com \
  --project zseniyedokmiutdambo

Step 2: Prepare secrets

统一 backend 需要两个核心 secret:

  1. chain-runtime-configs
  2. listener-internal-token

示例 CHAIN_RUNTIME_CONFIGS

json
{
  "8453": {
    "rpcUrl": "https://base-mainnet.g.alchemy.com/v2/<api-key>",
    "paymentRouterAddress": "0x838B5b928952900d940d0c49d71505712EB9e3cd",
    "confirmationsRequired": 6,
    "startBlock": 44678467,
    "backfillChunkSize": 500,
    "rpcTimeoutMs": 10000,
    "alchemySigningKey": "<base-signing-key>",
    "treasuryAddress": "0x2d5bab6551eb6d0d5604b5d5141479c8927d70cc",
    "treasuryPrivateKey": "0x<treasury-private-key>"
  },
  "42161": {
    "rpcUrl": "https://arb-mainnet.g.alchemy.com/v2/<api-key>",
    "paymentRouterAddress": "0xdbb11494dfC7B966d05B4D24f0AeC4BD78d4E4a7",
    "confirmationsRequired": 6,
    "startBlock": 453109190,
    "backfillChunkSize": 500,
    "rpcTimeoutMs": 10000,
    "alchemySigningKey": "<arbitrum-signing-key>",
    "treasuryAddress": "0x2d5bab6551eb6d0d5604b5d5141479c8927d70cc",
    "treasuryPrivateKey": "0x<treasury-private-key>"
  },
  "56": {
    "rpcUrl": "https://bnb-mainnet.g.alchemy.com/v2/<api-key>",
    "paymentRouterAddress": "0x36943AB43Bbb785a3208a6eB363F4B4805518CAF",
    "confirmationsRequired": 6,
    "startBlock": 92877672,
    "backfillChunkSize": 500,
    "rpcTimeoutMs": 10000,
    "alchemySigningKey": "<bsc-signing-key>",
    "treasuryAddress": "0x2d5bab6551eb6d0d5604b5d5141479c8927d70cc",
    "treasuryPrivateKey": "0x<treasury-private-key>"
  }
}

创建 secret:

bash
cat chain-runtime-configs.json | gcloud secrets create chain-runtime-configs \
  --data-file=- --project zseniyedokmiutdambo

echo -n "YOUR_INTERNAL_BACKFILL_TOKEN" | gcloud secrets create listener-internal-token \
  --data-file=- --project zseniyedokmiutdambo

如果 secret 已存在,使用 gcloud secrets versions add

Step 3: Create Firestore database

如果使用 Firestore 驱动:

bash
gcloud firestore databases create \
  --location=us-central1 \
  --type=firestore-native \
  --project=zseniyedokmiutdambo

Step 4: Create runtime service account

bash
gcloud iam service-accounts create payment-listener-sa \
  --display-name="Payment Listener Service Account" \
  --project=zseniyedokmiutdambo

gcloud projects add-iam-policy-binding zseniyedokmiutdambo \
  --member="serviceAccount:[email protected]" \
  --role="roles/datastore.user"

gcloud projects add-iam-policy-binding zseniyedokmiutdambo \
  --member="serviceAccount:[email protected]" \
  --role="roles/secretmanager.secretAccessor"

Step 5: Deploy the unified backend

bash
gcloud run deploy payment-listener \
  --source=backend \
  --project=zseniyedokmiutdambo \
  --region=us-central1 \
  --allow-unauthenticated \
  --service-account=payment-listener-sa@zseniyedokmiutdambo.iam.gserviceaccount.com \
  --set-env-vars=STORE_DRIVER=firestore,CHECKOUT_APP_BASE_URL=https://checkout.tariapay.com,CORS_ALLOWED_ORIGINS=https://dash.tariapay.com,FIRESTORE_COLLECTION_PREFIX=payment_listener \
  --set-secrets=CHAIN_RUNTIME_CONFIGS=chain-runtime-configs:latest,INTERNAL_AUTH_TOKEN=listener-internal-token:latest

这一步只部署一个 backend URL,所有链都由它统一处理。

Step 6: Configure Alchemy webhooks

  • 在 Alchemy dashboard 为每条链各建一个 custom webhook。
  • 目标 URL:
    • Base: https://<cloud-run-url>/webhooks/alchemy/8453
    • Arbitrum: https://<cloud-run-url>/webhooks/alchemy/42161
    • BSC: https://<cloud-run-url>/webhooks/alchemy/56
  • 把过滤条件限制为对应 PAYMENT_ROUTER_ADDRESS 上的 PaymentReceived 日志。
  • 拿到 webhook signing key 后,更新到 CHAIN_RUNTIME_CONFIGS 对应链的 alchemySigningKey

Step 7: Backfill and verify

首次部署后按链执行 backfill:

bash
curl -X POST "https://<cloud-run-url>/internal/backfill" \
  -H "Authorization: Bearer <INTERNAL_AUTH_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"chainId":8453,"fromBlock":44678467}'

健康检查:

bash
curl "https://<cloud-run-url>/health"

状态查询:

bash
curl "https://<cloud-run-url>/public/payment-status?merchant=<merchant-address>&orderId=<order-id-bytes32>"

概览查询:

bash
curl "https://<cloud-run-url>/public/overview"

Step 8: Optional scheduled backfill

bash
gcloud scheduler jobs create http payment-listener-backfill-base \
  --project=zseniyedokmiutdambo \
  --location=us-central1 \
  --schedule="*/10 * * * *" \
  --uri="https://<cloud-run-url>/internal/backfill" \
  --http-method=POST \
  --headers="Authorization=Bearer <INTERNAL_AUTH_TOKEN>,Content-Type=application/json" \
  --message-body='{"chainId":8453}'

如果还要给 Arbitrum 或 BSC 定时回扫,就为各自链再建一个 job。