system/squads-upgrade-authority-migration.md
ARCHIVE-ONLY MIGRATION RECORD. This captured the 2026-05-23 Squads
migration work before the current mainnet program existed. Current authority,
signer, deployment, and upgrade rules live in
turf-vault/docs/CURRENT_DEPLOYMENT.md; key-rotation procedure lives in
turf-vault/docs/KEY_ROTATION.md.STATUS (2026-05-23): DEVNET COMPLETE ✓ — MAINNET STILL PENDING (no mainnet program yet).
Devnet upgrade authority for turf-vault
Dx8u…GaCTis the Squads V4 vault
BW13kgfiG2koFn3WRkte21NW9TFygsD1ge2fNJdjH6kC(multisig PDA
7nRuVw3VZFC6z85tYVDitPnaUHZCkqLpJRSTBNtPmtZB, 2-of-3 Alex Bot / Alex /
Mason). Migration was done programmatically via the Squads V4 SDK — see
turf-vault/scripts/squad-upgrade.jsfor the reusable upgrade tool and
turf-vault/docs/CURRENT_DEPLOYMENT.mdfor the current upgrade rule. Since the
devnet migration, multiple upgrades have shipped through this path
(turf-vault v0.13.0 → v0.14.0 → v0.15.0), so the workflow is now
rehearsed and reusable.Related shipped work on the turf-monster side:
- MANAGED_WALLET_ENCRYPTION_KEY (OPSEC-015) deployed to prod v80; reencrypt ran clean.
- turf-monster verifiesEXPECTED_IDL_HASHat boot + duringassets:precompile(OPSEC-014).Remaining work (the mainnet migration) is still pending because
there is no mainnet program yet — see Step 4 below. The steps in this doc
apply verbatim once the mainnet deploy is ready.Carried-over caveat: operating the Squad with Alex Bot + Mason keys
both in 1Password makes the 2-of-3 single-trust-domain until the human
signers hold keys in separate domains.When to read this: You're about to move
turf-vault's program upgrade authority from a single keypair to a Squads multisig. Do this BEFORE mainnet launch.
turf-vault already has a transaction-level 2-of-3 multisig — settlement, force-close, and signer rotation all require two distinct signers from VaultState.signers[]. Good.
But the program upgrade authority is still a single keypair (~/.config/solana/id.json). Whoever holds that one key can ship a malicious program upgrade with zero cosign. That's the single biggest risk surface left on the program.
This migration moves upgrade authority to a Squads multisig with the same 2-of-3 quorum, closing the gap. After migration, an upgrade requires the same 2-of-3 cosign as a treasury op.
~/.config/solana/id.json) is in your possession7Hy8GmJWPMdt6bx3VG4BLFnpNX9TBwkPt87W6bkHgr2J (devnet)Dated migration snapshot: Verify current program IDs, Squad vaults, and
signer addresses inturf-vault/docs/CURRENT_DEPLOYMENT.mdbefore executing
any command from this runbook. Resolve private keys through 1Password item
names, not copied addresses in this document.
# Install Squads CLI (if not already)
npm install -g @sqds/sdk
# Or use the web UI at https://app.squads.so
# Create multisig with 2-of-3 threshold + same signers as VaultState
# (web UI is easier for the first time)
Via web UI (https://app.squads.so):
1. Connect Phantom as Alex (or Alex Bot if you have its keypair handy).
2. "Create a Squad" → 2 of 3 threshold.
3. Add members:
- Alex Bot: F6f8h5yynbnkgWvU5abQx3RJxJpe8EoQmeFBuNKdKzhZ
- Alex: 7ZDJp7FUHhuceAqcW9CHe81hCiaMTjgWAXfprBM59Tcr
- Mason: CytJS23p1zCM2wvUUngiDePtbMB484ebD7bK4nDqWjrR
4. Confirm and note the Squad vault PDA (this will be the new upgrade authority).
Verify the Squad vault PDA by clicking through to the multisig page. Copy the vault address. Call it $SQUAD_VAULT.
Don't skip this. Practice the entire flow on devnet so you have muscle memory before doing it on mainnet.
# Set devnet
solana config set --url devnet
# Verify current upgrade authority (should be single keypair)
solana program show 7Hy8GmJWPMdt6bx3VG4BLFnpNX9TBwkPt87W6bkHgr2J
# Look for "Authority: <single-key>"
# Transfer upgrade authority to the Squad vault
solana program set-upgrade-authority \
7Hy8GmJWPMdt6bx3VG4BLFnpNX9TBwkPt87W6bkHgr2J \
--new-upgrade-authority $SQUAD_VAULT \
--keypair ~/.config/solana/id.json
# Verify
solana program show 7Hy8GmJWPMdt6bx3VG4BLFnpNX9TBwkPt87W6bkHgr2J
# Should show "Authority: $SQUAD_VAULT"
While still on devnet, do a no-op upgrade to confirm the cosign flow works:
msg! log line in lib.rs).anchor build.# anchor deploy normally tries to invoke set_upgrade — that fails now
# because the authority is the Squad vault. Use Squads CLI/UI to wrap:
solana program write-buffer target/deploy/turf_vault.so
# Note the buffer address — call it $BUFFER_ADDR
# In Squads web UI:
# 1. New proposal → "Program upgrade"
# 2. Program ID: 7Hy8GmJWPMdt6bx3VG4BLFnpNX9TBwkPt87W6bkHgr2J
# 3. Buffer: $BUFFER_ADDR
# 4. Submit (this signs as cosigner #1)
# 5. Have signer #2 open the Squad page, review, sign
# 6. Once threshold met, anyone can "Execute" to land the upgrade
Verify the upgrade landed:
```bash
solana program show 7Hy8GmJWPMdt6bx3VG4BLFnpNX9TBwkPt87W6bkHgr2J
If anything went wrong, you still have the buffer — close it to recover rent:
bash
solana program close $BUFFER_ADDR
After devnet rehearsal succeeds:
bash
solana config set --url mainnet-beta
solana program set-upgrade-authority \
<MAINNET_PROGRAM_ID> \
--new-upgrade-authority $MAINNET_SQUAD_VAULT \
--keypair ~/.config/solana/id.json
~/.config/solana/id.json on every machine that has it, except as a sealed offline backup. That keypair is now powerless on the program but still holds SOL for fees — store it as cold backup.If the migration breaks something — e.g. the Squad vault address was wrong — there's only one path back:
- The new upgrade authority (the Squad vault) signs a set-upgrade-authority IX back to the old key.
- Requires 2-of-3 cosign through Squads.
- If somehow Squad is unreachable (lost signers, wallet bug), the program is immutable forever. That's actually OK for an audited program; if compromise is suspected, redeploy under a new program ID and migrate user balances via force_close_vault → re-init.
To minimize rollback risk: confirm the Squad vault address is correct THREE TIMES before running set-upgrade-authority. Print it. Compare. Have a second person verify.
After migration, run through this checklist before declaring done:
solana program show <program_id> → Authority: <Squad vault PDA>anchor view or Rails Solana::Vault.signers)Every future upgrade goes through Squads:
solana program write-buffer target/deploy/turf_vault.so # any signer can do this
# → submit upgrade IX via Squad UI → cosigner approves → execute
Update turf-vault/docs/CURRENT_DEPLOYMENT.md and turf-vault/README.md after any authority change. Do not update turf-vault/CLAUDE.md; it is migration context only.
We emailed a one-tap sign-in link to . It expires shortly and can only be used once.
No email? Check spam, or close this and try again.