08-migration-from-internal-wallet
Migration from internal wallet
Move existing Agent Play deployments from Redis balanceUsd / lazy $70 seed to x402 + Solana without breaking world state or audit history.
See also: Platform ops · Payment catalog · Legacy payments doc
What is being replaced
| Component | Internal (legacy) | x402 target |
|---|---|---|
| Balance source | Redis player:wallet JSON |
On-chain USDC |
| Initial grant | $70 lazy seed |
None (user funds wallet) |
| Purchase debit | balanceUsd -= price |
Facilitator verify |
| Talk billing | Debit viewer wallet | x402 per tick |
| Agent reward | powerUps on agent wallet |
USDC to operator |
| PU bundles | redeemWalletBundle |
Removed or off-chain loyalty later |
AQL SET WALLET |
Admin credit | Deprecated |
Preserved: purchase audit list shape (extended), sold item semantics, SSE fanout, journey/interaction logs.
Migration phases
gantt
title Payments migration
dateFormat YYYY-MM
section Mode
internal only :done, p0, 2026-01, 2026-03
dual :active, p1, 2026-04, 2026-06
x402 default : p2, 2026-07, 2026-08
remove internal code : p3, 2026-09, 2026-09
| Phase | AGENT_PLAY_PAYMENTS_MODE |
User-visible |
|---|---|---|
| 0 | internal |
Current production |
| 1 | dual |
Link wallet; new purchases use x402; hide $70 HUD |
| 2 | x402 |
All priced RPCs require proof; no lazy seed |
| 3 | x402 + code removal |
Delete internal wallet paths |
Phase 0 → 1 (dual)
Server
- Deploy settlement profile APIs +
PaymentGatewithdualflag. - Amenity
purchase: if proof present → x402 path; else 402 (not internal debit). - Keep
GET .../walletfor read-only legacy balance display (optional banner “migrating”).
UI
- Ship wallet link panel.
- Buy flow uses x402 client when
paymentsMode != internal. - Show both balances during dual (optional, time-boxed).
Data
- No automatic conversion of
balanceUsdto USDC. - Optional one-time script: platform airdrop devnet USDC to beta users.
Communication
- Email / docs: link Solana wallet before date X
- Demo hosts: stay on
internaluntil ready
Phase 1 → 2 (x402 only)
- Set
AGENT_PLAY_PAYMENTS_MODE=x402on production hosts. - Remove lazy seed code path in
getPlayerWallet. - Disable
redeemWalletBundle→ 410 Gone or explicit error. - Talk billing: internal debit removed; x402 ticks only.
- Remove power-up earn on purchase.
Redis cleanup (optional)
- Archive keys
agent-play:*:player:*:walletto cold storage - Do not delete purchase lists — extend with settlement fields
Phase 2 → 3 (code removal)
Remove or gate behind compile flag:
PlayerWalletSchema.balanceUsdproduction usagecreateInitialPlayerWalletlazy seedsetPlayerWalletBalanceexcept break-glass platform toolWALLET_BUNDLE_OFFERScatalogcomputeTalkAgentPowerUpsEarnedinternal credit path
Keep schemas parseable for historical JSON (read old wallets as legacy).
Purchase record compatibility
During dual, records may have:
priceUsdonly (legacy internal purchase before cutover)settlementblock (x402 purchases)
Parsers use Zod .optional() on settlement.
Inventory UI:
- Legacy rows: show “Internal wallet” chip
- x402 rows: explorer link
AQL and scripts
| Artifact | Action |
|---|---|
scripts/seed-amenities.aql |
Note x402; no $70 assumption |
SET WALLET in playground |
Validator warning in dual; error in x402 |
| Docs | Banner on payments-wallets-and-talk-billing.md |
Rollback plan
If x402 rollout fails mid-phase:
- Set
AGENT_PLAY_PAYMENTS_MODE=internal(env only) - Redeploy previous UI bundle if needed
- Items sold via x402 remain sold (irreversible) — reconcile manually
- Post-incident: fix facilitator or client before retry
Do not rollback Redis purchase records.
Testing migration
| Test | Phase |
|---|---|
| Internal purchase still works | 0 |
| 402 without wallet link | 1 |
| x402 purchase + sold state | 1 |
| Legacy balance read-only | 1 |
| No internal debit on purchase | 2 |
| Talk x402 only | 2 |
Production checklist
- Stakeholders accept no USD → USDC conversion for old balances
- Cutover date communicated
- Dual mode soak test ≥ 2 weeks on staging
- Rollback env var tested
- Purchase history export taken before phase 2