Appearance
Mainnet Deployment Practice
Comprehensive runbook for deploying and upgrading Vela protocol programs on Solana mainnet without losing program identity, drifting config, or breaking downstream consumers.
This page exists because the biggest operational risk for vela-protocol is not ordinary code shipping. It is program identity drift:
- losing the program keypair and silently creating a new program ID
- publishing SDK/docs/apps against the wrong mainnet address
- rotating one program (
vela-transfer-hook) without updating the other (vela-protocol) - confusing the program keypair with the upgrade authority wallet
For Vela, mainnet deployment is a ceremony, not a casual CLI step.
Scope
This checklist applies to:
vela_protocolmain programvela_transfer_hooktransfer hook program- any future Vela program deployed in the same operational model
This page covers:
- key custody
- build and deploy preparation
- first mainnet deployment
- later upgrades
- downstream propagation into SDK/docs/apps
- recovery expectations
Non-Negotiable Rules
- Mainnet program keypairs are generated once and treated as permanent identities.
- Program keypairs are never stored only in
target/deploy/. - Mainnet deploys are never performed from an unprepared laptop session with ad hoc keys.
declare_id!(),Anchor.toml, and checked-in program-ID manifests must match the intended mainnet public keys before deploy.vela_protocolandvela_transfer_hookare separate programs with separate identities and must be tracked independently.- Upgrade authority custody must be explicitly planned and documented before launch.
- No mainnet deploy is complete until downstream repos are updated and verified.
Critical Concepts
Program Keypair vs Upgrade Authority
These are not the same thing.
Program keypair
- Defines the program's public key, which becomes the program ID.
- If this keypair changes, the program ID changes.
- If this keypair is lost before a deploy flow that relies on it, you cannot recreate the same program ID.
Upgrade authority
- Controls whether the deployed upgradeable program can be upgraded later.
- Usually a wallet, multisig, or governance-controlled authority.
- Can remain intact even if you no longer have a convenient local copy of the deploy keypair.
Operational takeaway
You must protect both:
- the program keypair, because it anchors identity
- the upgrade authority, because it anchors control
EVM Mental Model
This section exists for engineers coming from EVM, because Solana program identity behaves differently from Ethereum contract deployment.
What feels familiar
- there is still a deployer/operator wallet
- there is still an admin-style authority for later upgrades
- there is still a deployment ceremony where code is built, published, and then referenced by SDKs and apps
What is different
In EVM, contract addresses are typically derived from:
- deployer address + nonce, or
CREATE2inputs
In Solana upgradeable programs, the program's identity is tied to a program keypair.
That means:
- your normal wallet from
solana-keygen pubkeyis not the program ID - the program ID comes from the program keypair JSON
- if a different program keypair is used, a different program ID is produced
The two identities to keep separate
1. Program keypair
- file like
vela_protocol-keypair.json - defines the program address
- should be thought of as the identity anchor for the deployed program
2. Wallet / deployer / upgrade authority
- your normal Solana wallet
- pays for deployment transactions
- may also hold upgrade authority
- is not the same thing as the program keypair
Practical mapping for EVM developers
| EVM concept | Solana concept | Notes |
|---|---|---|
| Deployer EOA | Operator wallet / upgrade authority wallet | Pays for deploys, may control upgrades |
| Contract address | Program ID | Public address other systems integrate with |
| Address derivation from deployer + nonce | Program ID from program keypair | Different keypair means different program ID |
| Proxy admin / owner | Upgrade authority | Controls upgrades for upgradeable programs |
Important operational consequence
If you come from EVM, the easiest mistake is assuming:
"my wallet determines the deployed program address."
For Vela on Solana, that is not true.
The safer mental model is:
- wallet key = who is allowed to deploy or upgrade
- program keypair = what address the program lives at
Why builds can surprise people
Some Solana/Anchor workflows will create deploy keypairs automatically if they do not already exist in the expected location.
That means a build or deploy flow can accidentally do this:
- fail to find the original program keypair
- generate a fresh one
- build or deploy against a new program identity
This is why Vela treats program keypairs as permanent, backed-up artifacts instead of disposable build output.
Program Inventory
Maintain a tracked table like this before mainnet launch:
| Program | Purpose | Mainnet Program ID | Program Keypair Location | Upgrade Authority | Status |
|---|---|---|---|---|---|
vela_protocol | Billing primitive | TBD | Secure storage | TBD | Pre-launch |
vela_transfer_hook | Token-2022 enforcement hook | TBD | Secure storage | TBD | Pre-launch |
This table should live in private ops docs and be updated after every mainnet ceremony.
Key Custody Practice
Required storage layout
Keep three copies of each mainnet program keypair:
Working copy
- Secure operator machine or controlled deployment workstation
- Used only for build/deploy preparation
Encrypted cloud backup
- Example: 1Password Secure Document or encrypted archive in private cloud storage
- Must be encrypted before upload if stored outside a secret manager
Offline backup
- Encrypted USB or hardware-backed offline archive
- Stored separately from the working machine
Required files
At minimum:
vela_protocol-keypair.jsonvela_transfer_hook-keypair.json
Do not do this
- do not commit keypairs to git
- do not leave them only in
target/deploy/ - do not keep only one copy
- do not store raw, unencrypted keypair JSON in a random cloud folder
- do not assume a past deploy machine will always remain available
Suggested Storage Convention
Local operator path:
sh
~/.config/velapay/keys/mainnet/vela_protocol-keypair.json
~/.config/velapay/keys/mainnet/vela_transfer_hook-keypair.jsonOptional environment override for scripts:
sh
VELA_PROGRAM_KEY_DIR=/secure/path/to/mainnet-keysThe exact path is less important than the discipline:
- stable
- documented
- backed up
- not disposable
Pre-Mainnet Checklist
Complete all of these before generating final mainnet keys or deploying anything.
Protocol readiness
- all protocol features intended for initial launch are frozen
- account layouts are reviewed for upgrade compatibility
- transfer-hook account dependencies are reviewed
ExtraAccountMetaListcapacity is reviewed for future needs- failure modes are documented and fail-closed behavior is confirmed
Testing readiness
- Rust tests pass
- TypeScript integration tests pass
- devnet deploy path has been exercised end to end
- upgrade rehearsal on devnet has been performed at least once
- SDK and docs are synced to the latest devnet/protocol shape
Operational readiness
- designated deploy operator is known
- upgrade authority holder is known
- recovery path is documented
- downstream repo owners know the post-deploy propagation steps
- rollback expectations are documented
Key readiness
- final mainnet program keypairs are generated intentionally
- public keys are recorded in private ops notes
- all three backups exist
- restore drill has been performed at least once
Mainnet ID Freeze Process
Before first deploy, freeze the intended mainnet IDs.
- Generate final mainnet program keypairs once.
- Record their public keys.
- Update:
declare_id!()Anchor.toml- protocol-owned program ID manifest
- Run repo-local checks to ensure code and config match.
- Back up the keypairs before proceeding.
Do not begin deploy prep if any of those are still ambiguous.
First Mainnet Deployment Ceremony
Treat first deployment as a checklist-driven ceremony.
1. Prepare the environment
- use a clean, trusted machine session
- confirm Solana CLI, Anchor, Rust, Bun, and Arcium versions
- confirm target cluster is mainnet, not devnet
- confirm wallet being used for upgrade authority steps is the intended wallet
2. Restore the correct mainnet program keypairs
- copy the saved keypairs into the workspace deploy location
- verify derived addresses match the intended mainnet program IDs
3. Verify checked-in source matches the intended IDs
Confirm:
programs/vela-protocol/src/lib.rsprograms/vela-transfer-hook/src/lib.rsAnchor.tomlconfig/program-ids.jsonor equivalent manifest
4. Build artifacts
- run Arcium build if required
- run Anchor build
- verify output bytecode corresponds to the intended program IDs
5. Deploy in the intended order
Recommended order:
vela_transfer_hookvela_protocol
Reason:
- the main program may reference the hook ID or depend on hook behavior
- deploying the hook first reduces identity mismatch risk during first launch
6. Verify on-chain state immediately
Check:
- deployed program IDs
- upgrade authority
- executable state
- IDL publication/upgrade if used
- hook-related account expectations
7. Record ceremony output
Write down:
- exact deploy date/time
- operator
- machine used
- git commit SHA
- deployed program IDs
- upgrade authority
- verification commands/results
No mainnet deploy should rely on memory.
Upgrade Ceremony (Post-Launch)
Mainnet upgrades should follow the same discipline, but they are not identical to first deploys.
Before upgrade
- confirm the existing deployed program ID
- confirm the current upgrade authority
- confirm the new build is based on the same intended program identity
- verify no unintended
declare_id!()drift occurred - confirm downstream repos that will need updates if IDLs or behavior changed
During upgrade
- restore the same saved program keypairs used for the canonical identity
- build from a clean, tagged, or otherwise controlled commit
- use the safe upgrade flow, not an ad hoc
anchor deploy - if using buffer-based upgrade flow, record buffer address and final upgrade transaction
After upgrade
- verify on-chain program still has the expected program ID
- verify upgrade authority was not changed unintentionally
- refresh IDL if required
- run downstream smoke checks
Downstream Propagation Checklist
Mainnet deployment is not done when the on-chain upgrade succeeds. It is done when all downstream consumers are aligned.
Update and verify:
vela-sdk- checked-in IDLs
- program ID constants/manifests
- tests referencing concrete program IDs
vela-docs- mainnet reference pages
- quickstart examples
- explorer links
vela-admin- protocol constants/config
- environment/config variables
vela-dashboard- generated constants or runtime config
- any service or worker that builds transactions, validates accounts, or links to explorer pages
For every downstream repo, answer:
- does it reference the protocol program ID?
- does it reference the transfer hook program ID?
- does it embed an IDL that changed?
- does it link to explorer pages or operational docs using the old value?
Post-Deploy Verification Checklist
Run all of these after mainnet deploy/upgrade:
- verify
vela_protocolprogram ID on chain - verify
vela_transfer_hookprogram ID on chain - verify upgrade authority on both
- verify any hook-specific config or extra account meta setup
- verify SDK still constructs transactions with the intended IDs
- verify docs build with updated references
- verify admin/dashboard builds still pass
- verify at least one dry-run or smoke flow on mainnet infrastructure assumptions
Suggested smoke surface:
- protocol account fetch
- plan read path
- mandate address derivation
- transfer-hook-aware instruction construction
Incident Scenarios
Scenario: program keypair lost, no deploy yet
Impact:
- must generate a new keypair
- mainnet program ID changes before launch
Action:
- update manifests, source IDs, SDK/docs/constants
- restart the checklist with the new canonical IDs
Scenario: program keypair lost after deploy, upgrade authority still intact
Impact:
- existing deployed program may still be upgradeable
- identity recreation from scratch becomes riskier
Action:
- do not improvise
- document current on-chain authority state
- confirm whether the planned upgrade flow truly requires the saved program keypair
- restore from backup immediately
Scenario: wrong program ID published downstream
Impact:
- clients and operators may point at the wrong program
Action:
- stop publish/release propagation
- correct SDK/docs/app constants
- rebuild and verify all consumer repos
- publish a clear ops note internally
Scenario: transfer hook updated, protocol references stale hook ID
Impact:
- pull execution can fail or behave inconsistently
Action:
- update protocol-owned constants and manifests
- rebuild protocol
- refresh SDK IDLs/constants
- verify docs/admin/dashboard alignment
Things We Must Never Do on Mainnet
- never treat
target/as the source of truth for identity - never generate “temporary” mainnet keypairs
- never run raw deploy commands without checking active cluster and intended wallet
- never upgrade one of the two programs and assume the other repo surfaces do not need review
- never ship SDK/docs/apps before program IDs and IDLs are reconciled
- never leave upgrade authority custody undocumented
Minimal Mainnet Runbook
This is the condensed version operators should memorize:
- Restore the correct saved mainnet program keypairs.
- Verify program IDs from those keypairs.
- Verify
declare_id!(),Anchor.toml, and manifest match. - Build from a controlled commit.
- Deploy/upgrade in the intended order.
- Verify on-chain IDs and upgrade authority.
- Update SDK/docs/apps.
- Record the ceremony in ops notes.
Vela-Specific Recommendations
For Vela, the most important practical controls are:
- keep
vela_protocolandvela_transfer_hookkeypairs backed up separately and clearly labeled - maintain a protocol-owned canonical manifest for mainnet IDs
- use guarded build/deploy scripts, not one-off commands
- make downstream repo propagation part of the deploy checklist, not an afterthought
- rehearse the full ceremony on devnet first
If the team does those five things consistently, mainnet deployment risk drops substantially.