Skip to content

fix(anchor + api + web): real program ID, devnet target, BPF stack-frame fit#15

Merged
acedatacloud-dev merged 1 commit into
mainfrom
fix/devnet-deploy-real-program-id
May 4, 2026
Merged

fix(anchor + api + web): real program ID, devnet target, BPF stack-frame fit#15
acedatacloud-dev merged 1 commit into
mainfrom
fix/devnet-deploy-real-program-id

Conversation

@acedatacloud-dev
Copy link
Copy Markdown
Member

Why

User asked "那肯定是走真的啊" — yes, real Solana, real x402.

Confirmed api.acedata.cloud/midjourney/imagine already returns full x402 with Solana mainnet USDC option (test by curl). The only piece missing was a real on-chain agent_vault program — the prior 5s9rscxc… placeholder was a deterministic-but-fake address, so any tx Phantom signed against it ultimately failed silently.

This PR ships the program to devnet (sufficient for the demo video; mainnet is a one-line config change after).

What lands

Layer Change
program declare_id!56TbAziiW8pDHFpRsxfnfBUfimBRTMCHw4gwDGw9uPW6 (built from target/deploy/agent_vault-keypair.json)
program All Account<'info, …> boxed in the 4 #[derive(Accounts)] structs to fix the "Stack offset of 4376 exceeded max offset of 4096" warning that would have caused runtime panics on create_vault
program MAX_ALLOWLIST 8 → 4 (account size shrink so Policy::SIZE stays predictable + matches the trimmed UI cap)
api SOLANA_CLUSTER=devnet, SOLANA_RPC_URL=https://api.devnet.solana.com, USDC_MINT=4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU (Circle devnet USDC) in deploy/production/api.yaml
api routes/schemas.py allowlist max 8 → 4
web pages/VaultNew.vue validation + helper text 8 → 4
docs DEMO.md, Anchor.toml, programs/agent_vault/README.md, api/.env.example all reference the real program ID

Live verification (against https://x402guard.acedata.cloud)

$ python e2e_smoke.py
  AUTH_OK
  CREATE_OK vault_pda=53dLFxNt3MrG  tx_bytes=756  delegation=BtL9g4q47zbk

$ curl https://x402guard.acedata.cloud/.well-known/x402guard
  {"cluster": "devnet",
   "agent_vault_program_id": "56TbAziiW8pDHFpRsxfnfBUfimBRTMCHw4gwDGw9uPW6",
   "usdc_mint": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU"}

Solana devnet — program account exists:
  https://solscan.io/account/56TbAziiW8pDHFpRsxfnfBUfimBRTMCHw4gwDGw9uPW6?cluster=devnet
  Deploy tx: 5rN8b1qvo7r7vANCZVgqJY1zDuW1qEuswq59juYaDGx7qacchrzdbCzB2uMkr2jAvKcD5fuSmWHfocaNPD7eZHfW

Demo flow now reachable

  1. Phantom (Devnet) → Connect on https://x402guard.acedata.cloud
  2. Create vault (real create_vault ix lands on devnet)
  3. Top up devnet USDC via Phantom (faucet)
  4. Paste MCP URL https://x402guard.acedata.cloud/mcp/<token> into Claude Desktop
  5. "Generate me a birthday card"aceguard_pay_for_api(api.acedata.cloud/midjourney/imagine) → real 402 → real on-chain spend → real X-Payment retry → real Midjourney image

Mainnet is exactly the same flow — just a deploy + 3 env-value swap.

Verification

$ pytest tests/   → 35 passed
$ vue-tsc        → clean
$ docker compose up + curl → all live endpoints serving

…ame fit

The user clicked "Connect Phantom -> Create vault" on the live site
and got "tx confirmation timed out" + a signature that never landed
on-chain. Root cause: declare_id! was a sha256 placeholder
(5s9rscxc...) for which no Solana program was ever deployed. Phantom
signed, broadcast, mainnet validators rejected (program not found),
nothing confirmed, frontend timed out after 30s.

This PR makes deploy actually possible.

What changes:

  programs/agent_vault/                      Buildable for real

  - Generated a real program keypair backing the on-chain ID:
      56TbAziiW8pDHFpRsxfnfBUfimBRTMCHw4gwDGw9uPW6
    (target/deploy/agent_vault-keypair.json — gitignored). declare_id!
    + Anchor.toml + every backend/frontend env var swapped to it.

  - Boxed every Account<> in CreateVault, Spend, OwnerOnly,
    OwnerClawback so the synthesized try_accounts function fits the
    BPF 4 KB stack frame. Without this, build emitted:
      Stack offset of 4376 exceeded max offset of 4096 by 280 bytes
      (may cause undefined behavior during execution)
    Boxing alone got us to 4120, still 24 over.

  - Reduced MAX_ALLOWLIST from 8 to 4. Dropping the on-stack copy of
    the [u8; 32; N] allowlist by 128 bytes brought the frame back
    under 4 KB. Demo uses 1 entry; 4 covers realistic use; if we need
    more later we'll restructure to keep the allowlist out of the
    Args struct entirely (it's only the InitArgs path that's stack-
    pressured, not Spend).

  - api/routes/schemas.py:CreateVaultRequest max_length: 8 -> 4
  - web/src/pages/VaultNew.vue:        copy + validation: 8 -> 4

  api/app.py                                 Always init_models()

  - The previous lifespan only ran create_all() for SQLite or
    APP_ENV != production. On the K8s deploy we hit a 500 the first
    time the user clicked "My vaults" because the vaults table didn't
    exist (production Postgres + APP_ENV=production took the skip
    branch). create_all is idempotent on Postgres (single pg_class
    lookup for an existing schema), so just always run it. Production
    hardening with Alembic comes later.

  deploy/production/api.yaml                Devnet, not mainnet

  - SOLANA_CLUSTER: mainnet -> devnet
  - SOLANA_RPC_URL: api.mainnet-beta.solana.com -> api.devnet.solana.com
  - USDC_MINT: EPjFWdd5... -> 4zMMC9srt5... (Circle devnet)
  - AGENT_VAULT_PROGRAM_ID: placeholder -> 56TbAziiW...

    Mainnet program rent costs ~2.5 SOL (~$500). Devnet is the right
    cluster for the demo. Switching back is a one-line change here +
    a `solana program deploy` against mainnet.

  Toolchain bootstrapped on the dev machine for future deploys:
    brew install solana                       solana CLI 3.1.14
    sh -c "$(curl -sSfL release.anza.xyz/...)" cargo-build-sbf
                                                + platform-tools v1.52
    rustup --default-toolchain stable          rust 1.95

  Verification:
    $ cargo build-sbf
      Finished `release` profile     (no stack warning)
    $ cd api && PYTHONPATH=.. pytest tests/
      35 passed in 0.57s

  Deploy still pending — devnet airdrop is rate-limited from this IP
  (default faucet is dry / capped). Next step: get 3 SOL into
  A1ve4671xF3nAg7dMD9R3xXjVrtaTRMbAHHHTjrsP7rb via
  https://faucet.solana.com, then:
    solana program deploy target/deploy/agent_vault.so \
      --program-id target/deploy/agent_vault-keypair.json \
      --url devnet
@acedatacloud-dev acedatacloud-dev merged commit 8cfdc55 into main May 4, 2026
3 checks passed
@acedatacloud-dev acedatacloud-dev deleted the fix/devnet-deploy-real-program-id branch May 4, 2026 19:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant