solana-client-tools: add a payload budget and a checked encoder for Squads vaults - #409
Conversation
bgm-malbeclabs
left a comment
There was a problem hiding this comment.
Reviewed the derivations by hand and ran the crate tests (17 squads tests pass) and cargo clippy --all-targets (clean).
What checks out: all five const _: () = assert!(...) blocks add up, and the Squads v4 account lists they encode are right (VaultTransactionCreate 5 accounts, ProposalCreate 5, ProposalVote 3, VaultTransactionExecute 4). The one byte per instruction charge is a correct upper bound, since Squads writes instruction data length as SmallVec<u16, u8> against legacy shortvec, and every other length prefix over-charges rather than under-charges. The claim that create binds before execute holds: create allows 24 zero-data account keys against execute's 27, and execute does not grow with instruction count, so the execute check really is unreachable. No callers are left on the removed print_vault_transaction and encode_vault_transaction.
No correctness bug found. Two nits below, neither a blocker.
…quads vaults (malbeclabs/doublezero-offchain#409) Closes #4184 ## Summary - Add `vault_transaction_payload_budget`, reporting the bytes a payload of a given instruction count may serialize to, for a caller that grows a single instruction until it stops fitting - Add `try_encode_vault_transaction`, which measures the payload and refuses one that cannot work. `print_vault_transaction` becomes `try_print_vault_transaction` and routes through it - Derive the reserve as const arithmetic rather than in a comment, one term per line, from the `vault_transaction_create` envelope plus the compute budget pair, `proposal_create`, and `proposal_approve` the Squads app bundles into that same transaction. Compile-time assertions pin each block's subtotal and the 384 total, so a changed term fails the build instead of leaving a stale literal. A comment records the three app behaviors the derivation assumes away and what each costs - Refuse a payload naming a signer other than the vault, and one carrying more than 48 instructions. Both import and collect approvals before failing at execute, unlike an oversized payload, which fails at import - Check the `vault_transaction_execute` transaction as well, at 329 bytes plus 33 per payload account key. The issue specifies 277, which omits the compute budget pair the app bundles there too - Record the conventions this change was written under in `CLAUDE.md`, covering numeric literals, prose in comments and documentation, the `try_` prefix, and where workspace dependency features belong ## Testing - Hand-computed payload lengths at 3, 127 and 128 instruction-data bytes, spanning the legacy length prefix boundary - A payload landing exactly on the budget and one byte over it, at one instruction and at two - The wrapper Squads builds around a budget-sized payload, assembled and measured at 1,229 bytes of the 1,232 available - The widest payload the budget accepts, at 24 account keys and 1,121 bytes to execute - Refusals for an empty payload, a foreign signer, and 49 instructions - A downstream caller's vault print path against devnet, run before and after the change, byte-identical
Closes malbeclabs/doublezero#4184
Summary
vault_transaction_payload_budget, reporting the bytes a payload of a given instruction count may serialize to, for a caller that grows a single instruction until it stops fittingtry_encode_vault_transaction, which measures the payload and refuses one that cannot work.print_vault_transactionbecomestry_print_vault_transactionand routes through itvault_transaction_createenvelope plus the compute budget pair,proposal_create, andproposal_approvethe Squads app bundles into that same transaction. Compile-time assertions pin each block's subtotal and the 384 total, so a changed term fails the build instead of leaving a stale literal. A comment records the three app behaviors the derivation assumes away and what each costsvault_transaction_executetransaction as well, at 329 bytes plus 33 per payload account key. The issue specifies 277, which omits the compute budget pair the app bundles there tooCLAUDE.md, covering numeric literals, prose in comments and documentation, thetry_prefix, and where workspace dependency features belongTesting