Skip to content

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 accountsversion: 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 lifecycleupdate_mandate / close_mandate instructions for mutable mandate state
  • Mutable plansupdate_plan / update_usage_plan for plan modification after creation
  • Per-merchant credentialsinit_merchant_credential bootstrap instruction
    • Decoupled credentials from global state
    • Each merchant has their own credential PDA
  • Migration instructionsmigrate_mandate / migrate_plan for 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_mint with a registry of supported mints
    • Each mint has its own billing rail, decimals, and oracle configuration
  • Dynamic hook resolution — Transfer hook resolved from ProtocolConfig.transfer_hook_program_id at 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 cacheVelaClient.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/*.json to V2 protocol contract
    • vela-sdk/idl/vela_protocol.json structurally identical to vela-protocol/target/idl/vela_protocol.json
  • V2 PDA migration in runtime builders — Repointed subscribe, cancel, execute-pull, preflight to V2 mandate seeds
  • Missing SDK builders — Shipped initMerchantCredential, initTokenConfig, updateTokenConfig
  • Integration tests greentests/integration/client.test.ts 11/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

  1. 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.
  2. IDL freshness is a deployment concern, not a build concern. Bundle the IDL in vela-sdk/idl/ from vela-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."
  3. Frontmatter traceability fields aren't optional. Phase 40's missing requirements-completed entries were the root cause of Phase 44 existing at all. Plan summaries must list every requirement they close, not just narrative deliverables.
  4. 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

AreaScoreNotes
Requirements49/49Phase 43 owns SDK requirements; Phase 44 backfills Phase 40 partials
Phases verified5/5Phases 40, 41, 42 (via Phase 43), 43, 44
Integration8/8All handoffs verified PASS
E2E flows6/6Bootstrap/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

Internal knowledge base for the Vela Labs workspace.