Appearance
v1.7 Protocol Modularity
Shipped: 2026-04-15 | Phases: 5 (40–44) | Plans: 29 | Git: 72 commits | Audit: 49/49 requirements passed
The infrastructure investment milestone. v1.7 didn't ship user-facing features — it refactored vela-protocol and vela-sdk to be extensible for v1.8 streaming payments, plan upgrades, and multi-token support without breaking changes. It proved that versioned accounts are cheap insurance, and versioning retroactively is expensive.
Why This Milestone Existed
v1.0 didn't reserve space on accounts. v1.8 needed streaming + upgrades + multi-token, all of which required new fields on existing account types. Without versioning, adding those fields would break every deployed mandate on devnet (and eventually mainnet).
v1.7 was the investment in future-proofing: add version bytes, reserved space, and a migration path so that v1.8 and beyond can extend accounts without breaking changes.
What Shipped
Phase 40: Versioned Accounts + PDA Refactor
The foundational account restructuring.
- Versioned accounts —
version: u8+_reserved: [u8; 64]on every core account- Costs ~64 bytes/account
- Saves a future migration phase
- Cheap insurance validated by v1.7's own existence
- Plan-independent mandate PDAs — Reseeded from plan-dependent to
mandate, subscriber, merchant, mandate_index- Mandates are no longer tied to a specific plan
- Enables plan switching and upgrades without PDA migration
- Mandate lifecycle —
update_mandate/close_mandateinstructions for mutable mandate state - Mutable plans —
update_plan/update_usage_planfor plan modification after creation - Per-merchant credentials —
init_merchant_credentialbootstrap instruction- Decoupled credentials from global state
- Each merchant has their own credential PDA
- Migration instructions —
migrate_mandate/migrate_planfor V1→V2 in-place upgrades- Same-binary support for both account layouts
- Zero downtime during migration window
- Can run lazily on first touch
- Stable explicit error codes — Consistent error numbering for all protocol errors
- 101+ regression tests — All passing after the account refactor
Phase 41: Token Registry + Upgradeable Transfer Hook
Multi-token support and hook upgradeability.
- TokenConfig PDA registry — Per-mint billing configuration
- Replaced single
wrapped_usdc_mintwith a registry of supported mints - Each mint has its own billing rail, decimals, and oracle configuration
- Replaced single
- Dynamic hook resolution — Transfer hook resolved from
ProtocolConfig.transfer_hook_program_idat runtime- Constant fallback for bootstrapping
- Hook program can be upgraded without SDK redeployment
- 8-slot ExtraAccountMetaList — Expanded from previous slot count for future account references
- BPF Loader Upgradeable deployment — Hook program deployed via upgradeable loader for seamless upgrades
- Multi-mint hook validation — Dedicated LiteSVM tests for multi-mint transfer scenarios
Phase 42: SDK Decoupling
Centralized SDK architecture.
PDAFactory— Single source of truth for all PDA derivation- V1 + V2 methods for backward compatibility
- Deprecated re-exports for gradual migration
- Eliminated "wrong PDA" bugs once all builders went through the factory
- V2 account types — Auto-detecting deserializers for V1/V2 dual-read
- Same SDK binary supports both account layouts
- Graceful migration without SDK version bifurcation
- Lazy config cache —
VelaClient.getProtocolConfig()+refreshConfig()- Fetches protocol config once, caches for subsequent calls
- Manual refresh for forced updates
- SEED_PREFIX constants — For the Rust test harness, eliminating bare string literals across both client and protocol test code
Phase 43: SDK Sync + Verification (Gap Closure)
Closing the integration drift from Phase 42.
- Refreshed IDLs — Synced
vela-sdk/idl/*.jsonto V2 protocol contractvela-sdk/idl/vela_protocol.jsonstructurally identical tovela-protocol/target/idl/vela_protocol.json
- V2 PDA migration in runtime builders — Repointed
subscribe,cancel,execute-pull,preflightto V2 mandate seeds - Missing SDK builders — Shipped
initMerchantCredential,initTokenConfig,updateTokenConfig - Integration tests green —
tests/integration/client.test.ts11/11 pass, 256/256 SDK tests pass overall
Phase 44: Traceability Cleanup (Gap Closure)
Documentation and traceability alignment.
- Phase 40 summary frontmatter backfill — Added VER-05, MND-07, TEST-01, TEST-06 entries
- REQUIREMENTS.md 49/49 satisfied — All checkboxes flipped with traceability coverage
- ROADMAP scope corrected — v1.7 header now declares Phases 40–44 with scope notes
What Worked
Reserved-Space + Version-Byte Pattern
Simple version: u8 + _reserved: [u8; 64] on every account turned the "how do we add fields without breaking deployed mandates" problem into a non-event. The entire v1.7 milestone existed because v1.0 didn't do this. The lesson: apply the pattern forward to every new account.
Compatibility Loaders for V1/V2 Dual-Read
Same-binary support for both account layouts (rather than a hard cutover) meant zero downtime for the migration window. The migrate_* instructions can run lazily on first touch, so there's no migration deadline pressure.
PDAFactory as Single Source of Truth
Once Phase 43 forced every runtime builder through PDAFactory.mandate(), the entire class of "SDK builds wrong PDA" bugs disappeared. Centralized derivation is always worth the indirection.
What Was Inefficient
Phase 42 Shipped Without Sync Verification
All 9 SDK requirements (SDK-01..08 + TEST-07) were marked complete in 42-SUMMARY.md without a phase verification step. The audit caught this as orphaned requirements with broken runtime wiring:
- Stale IDL (not synced from protocol)
- V1 PDA calls in runtime builders
- Missing instruction builders (initMerchantCredential, initTokenConfig)
This forced the entire Phase 43 gap-closure cycle. Root cause: the verifier was skipped because PDA unit tests passed — but unit tests don't catch IDL drift or runtime path coverage gaps.
Two Gap-Closure Phases for One Milestone
Phase 43 closed the integration drift. Phase 44 closed the traceability drift left over from Phase 40. Both were necessary, but both were avoidable with stricter end-of-phase verification.
MILESTONES.md Auto-Generated Bullets Were Noisy
The CLI extracted "1. [Rule 1 - Bug]…", "Traceability table:", "One-liner:" as accomplishments from plan summaries. Required manual cleanup during milestone close.
Patterns Established
Gap-Closure Phase Pattern
When verification reveals integration drift, spin a dedicated gap-closure phase rather than retro-amending the original. Keeps the audit trail honest and gives the gap closure its own success criteria + verification. Validated twice in v1.7 (Phases 43 and 44).
Dynamic Program ID Resolution from On-Chain Config
Reading ProtocolConfig.transfer_hook_program_id at runtime (with constant fallback) lets the hook program be upgraded without SDK redeployment. Apply same pattern to any future protocol↔external-program reference.
Reserved Space on Every New Account
Default to _reserved: [u8; 64] on every Anchor account from now on. The cost is minimal, and the alternative (a future v1.7-equivalent migration phase) is expensive.
Key Lessons
- Unit tests pass ≠ integration works. Phase 42 had passing PDA unit tests AND broken runtime wiring. Future SDK phases must include at least one end-to-end integration test against a fresh IDL before claiming requirements complete.
- IDL freshness is a deployment concern, not a build concern. Bundle the IDL in
vela-sdk/idl/fromvela-protocol/target/idl/as a verified copy step in the build. Don't trust that "the IDL is up to date because the build passed." - Frontmatter traceability fields aren't optional. Phase 40's missing
requirements-completedentries were the root cause of Phase 44 existing at all. Plan summaries must list every requirement they close, not just narrative deliverables. - Versioned accounts are cheap; versioning retroactively is expensive. v1.7 only existed because v1.0 didn't reserve space. Apply the lesson forward.
Audit Results
| Area | Score | Notes |
|---|---|---|
| Requirements | 49/49 | Phase 43 owns SDK requirements; Phase 44 backfills Phase 40 partials |
| Phases verified | 5/5 | Phases 40, 41, 42 (via Phase 43), 43, 44 |
| Integration | 8/8 | All handoffs verified PASS |
| E2E flows | 6/6 | Bootstrap/create, subscribe, pull, cancel, preflight, TokenConfig admin |
Status: passed — first clean pass without tech debt or gap exceptions.
Cost Observations
- Two gap-closure phases (43, 44) added ~30% overhead vs the original 40–42 scope
- Both gap-closure phases were directly attributable to skipping verifier on Phase 42
- Phase 44 was docs-only — no runnable code, exempted from Nyquist coverage