Repository navigation
feat(svm): retire V4 deposit and fill entrypoints - #1562
Conversation
f230641 to
cb5a25f
Compare
droplet-rl
left a comment
There was a problem hiding this comment.
Reviewed against reinis/acp-222-retire-legacy-fill-callbacks. The retirement itself looks correct and well-scoped — no correctness blockers found. Findings below are cleanup, doc-sync, and one accuracy correction to the validation summary.
What I verified locally
- Discriminators are right. All four literals in
compatibility.rsandSvmSpoke.SlowFillRetirement.tsmatchsha256("global:<name>")[..8]exactly (deposit,deposit_now,unsafe_deposit,fill_relay).InstructionFallbackNotFoundis indeed 101 /0x65. - Rust tests match the claim.
cargo test -p svm-spoke --lib→ 18 passed;--features test→ 22 passed. - IDL delta. I generated the raw IDL on both branches (
cargo test --features idl-build -- __anchor_private_print_idl). Exactly the four instructions are removed; all 22 retained instructions are unchanged. See the caveat on types below. - No dangling references. No remaining in-repo caller of
deposit/depositNow/unsafeDeposit/fillRelay/loadFillRelayParams/createFillRelayParamsInstructions. Bundle/refund suites fund vaults viamintTo, so nothing depended ondepositfor seeding. simpleFakeRelayerRepayment.tsrewrite is correct.createAssociatedTokenAccountIdempotentInstruction(signer, vault, statePda, inputToken)faithfully replaces the oldinit_if_neededvault, and the transfer/decimals wiring is right.- Vault provisioning still exists via
create_token_accounts/createVault.ts, so dropping the lastinit_if_neededdeposit path doesn't strand new tokens. - Prettier clean on all changed TS;
git diff --checkclean.
Main things to fix
-
Six new compiler warnings on a previously clean base.
cargo check -p svm-spoke --libemits 0 dead-code/unused-import warnings on the base branch and 6 on this head (identical under--features testand--features idl-build).yarn lint-rustrunscargo clippyin CI, so these will be visible in every subsequent PR in the stack. Five are the intentionally-deferred dead branches, butunused import: state::*(lib.rs:39) is a one-line fix that isn't part of the deferred-simplification story. -
The IDL claim is slightly off. The PR says "exactly the four intended instructions removed; retained instructions, account definitions, and event schemas unchanged." The generated IDL also drops the
FillRelayParamsaccount definition and theRelayDatatype (both become unreachable).RelayDatamatters downstream:V5FillJitembeds a Borsh-encodedRelayData, so relayers building V5 fills now have to hand-encode it (which is exactly whatSvmSpoke.V5Fill.ts's localencodeRelaydoes). Worth calling out in the migration/deployment notes rather than leaving it as a silent artifact change. -
test/svm-gateway/README.md:109-115is now stale and wasn't updated, contradicting the repo's "keep docs updated in the same change" rule. Details inline.
Coverage trade
Replacing ~2,200 lines of V4 suite with V5 dispatch/IDL/rejection tests plus the new shared-validation cases in SvmSpoke.V5Source.ts is a reasonable swap — quote/deadline/output-token/exclusivity and the three exclusivity modes are the load-bearing _deposit logic and are now exercised through Gateway. Genuinely lost and probably fine to lose: CPI-guard deposit/fill, native-SOL deposit, recipient-ATA-creation-on-fill (V5 requires a pre-existing recipient ATA by design), and max-fills-per-tx. Worth a conscious ack that none of those are wanted on the V5 path.
On the reported Cannot close another caller's instruction params failure: that test uses connection.requestAirdrop + a bare setTimeout(1000), which is the classic source of "Attempt to debit an account but found no record of a prior credit" — so your "unrelated setup failure" read is plausible. Still worth one clean rerun to confirm, since this PR removes the only other consumers of the instruction-params buffer and therefore changes validator timing in that suite.
|
Addressed the “Coverage trade” feedback in 11ac800. Ported the applicable V4 regressions to V5: guarded Token-2022 source/fill funding through the real Gateway, native SOL deposits using new/existing wrapped accounts, explicit new-vault and recipient-ATA provisioning, and two distinct external fills with account creation in one buffered transaction. The tests check balances, delegation, events, fill status and rent; a submitted transaction whose last fill fails proves transaction-wide rollback. Added account/mint/authority and approval negatives, post-exclusivity fills, and execution through retained public Codama builders. The coverage inventory maps the deleted cases to named V5 tests and identifies retired interface semantics. Two corrections to the old coverage: the recipient-ATA test explicitly created the account before filling in the same transaction, and the “Max fills” test exercised two fills rather than establishing a maximum. We retained that two-fill case as a composition/rollback regression. Current Madrid/Jussi execution handles each order leg as a separate Gateway transaction; the test shares one destination commitment. A maximum-fill benchmark is deferred until a concrete relayer batching design exists. The concrete one/two-fill transactions measured 441/448 bytes and 105,999/212,753 CU. Validation: 26 focused codec/source/fill/retirement tests passed against a freshly rebuilt Spoke, the final generated-adapter builder change passed its focused rerun, and the complete pinned real-Gateway/swap suite passed all 25 tests. Strict affected-suite/consumer TypeScript checks, formatting, and pre-commit checks passed. The earlier ordinary full-suite setup failure/rerun request remains a separate follow-up (R11). Sent from Reinis Martinsons's Codex CLI Agent using gpt-6-astra 🤖 |
|
Addressed the full-suite rerun request with current CI evidence; no fixture change was needed. The verified SVM job for head The original local result remains 119 passed / 1 setup failure, followed by a successful focused retry. This later clean full run supplies the requested confirmation; it does not establish that the existing airdrop-and-sleep fixture can never flake. Separately, EVM CI reports 667 passed / 1 failed because the Hyperliquid RPC rejects fork block Sent from Reinis Martinsons's Codex CLI Agent using gpt-6-astra 🤖 |
droplet-rl
left a comment
There was a problem hiding this comment.
Re-reviewed the 10 new commits. Every point from my previous round is addressed, several more thoroughly than I asked for. Approving; remaining notes are nits.
Verified by building and running, not just reading
Compiler warnings — fixed. cargo check -p svm-spoke --lib now emits zero dead-code/unused-import warnings under default, --features test, and --features idl-build, matching the base branch. The #[allow(dead_code)] + TODO(V5 simplification) markers on DepositId::Next / FillStatusInput::Legacy are the right call — they keep the branch alive as a regression fence while making the deferral explicit. cargo test -p svm-spoke --lib → 17 passed; --features test → 21 passed (down from 18/22 only because validate_legacy_fill_message and its test went with V5FillOnly).
The IDL type-injection mechanism is sound — I verified it byte-for-byte. I generated the base branch's Anchor-macro IDL and the new export_v5_types output, applied the reviver's path-stripping, and diffed:
RelayData identical (base anchor-macro vs head exported): True
So public clients will carry exactly the RelayData schema consumers had before. I also confirmed the normalized output matches Anchor's IDL conventions (snake_case fields, short PascalCase type names, defined.name resolved to RelayData), matching the 0.1.0 spec used by the checked-in idls/*.json. And I confirmed adding the [[bin]] target doesn't break anchor idl build's stdout parsing — cargo test --features idl-build still emits exactly one --- IDL begin program --- block, with the extra bin's empty test harness landing after the markers.
Layering three independent checks on the codec — Rust golden (serialize(&jit) == wire.fillJit, serialize(&jit.relay_data) == jit_bytes[..len-40]), TS V5Codecs against the same cross-VM fixture, and V5Fill's encodeJit now routed through the shipped getV5FillJitEncoder() against the live program — is stronger than what the deleted V4 tests had. The hand-rolled encodeRelay is gone, so the test and the published client can't drift.
The error renumbering is correct and correctly justified. I fetched d8da3000 (confirmed = tag v5.0.12-beta.1) and diffed its error.rs against the doc: the "Before release" column matches the deployed baseline exactly, CommonError is genuinely unchanged (16 variants, identical order), and the new 7000–7016 SvmError mapping matches the actual enum variant-for-variant. Removing interior InvalidRelayHash shifts 16 codes, but since the whole enum is already moving 6000→7000 in this release, consumers must remap regardless — and re-baselining on the deployed release rather than intermediate stack PRs is the right framing. Preserving CommonError 6003/6005 as reserved slow-fill slots and pinning them in custom_error_ranges_are_stable is exactly the distinction that matters.
Also confirmed: V4_COVERAGE.md's baseline 0d776a08 is the actual merge-base; all three anchor idl build sites are inside the two scripts that call includeV5IdlTypes.ts, with correct ordering (the mock_gateway build after it only writes its own IDL); Codama role decoding in the new generated-builder test (role >= 2 signer, role % 2 === 1 writable) is right; V5Fill's beforeEach fully resets relay/recipient/recipientToken, so the new mutation-heavy tests don't leak; no broken markdown links introduced (the 4 that exist are pre-existing in script/mintburn/README.md); V5_ADAPTER_SPEC.md is back to zero lines over 120; prettier and git diff --check clean.
V4_COVERAGE.md is a genuinely useful artifact — a per-case traceability matrix that separates ported behavioral guarantees from deliberately retired interfaces, and says plainly that the two-fill case "establishes that this concrete transaction fits, not a universal maximum." That honesty is worth more than the coverage itself.
Nits (none blocking)
The one I'd most like fixed is the cache-key gap — it's the only item that could silently produce a wrong published artifact later.
f8c831b to
6c9f429
Compare
droplet-rl
left a comment
There was a problem hiding this comment.
Re-reviewed the five new commits. Each maps to one of my nits, and the IDL export went considerably past what I suggested. Approving — no open items.
Verified by building and running
Complete V5 wire surface is now published, and the merge is provably clean. I ran the updated exporter and simulated the full includeV5IdlTypes.ts merge against a freshly generated macro IDL:
conflicts: 0
added: RelayData, AcrossDepositInput, AcrossDepositJitParams, AcrossDepositParams,
V5AdapterInput, V5DepositModificationRules, V5FillInput, V5FillJit, V5InputAmountMode
unresolved defined refs: none
Nine types, zero collisions with the 9 Anchor-discovered ones, and every defined reference resolves inside the merged IDL. That substantiates the description's claim that SDK-side Codama generation needs no injection — the published IDL is self-contained. The enum shapes are correct Anchor form (V5AdapterInput tuple variants, V5InputAmountMode's named-field InputVaultBalance { bips }), and the Rust doc comments carry through, so the published IDL now documents the frozen DepositV1 = 0 / FillV1 = 1 discriminants and the fixed-width signature layout.
The new depositInputLiteral fixture is byte-correct. I diffed it against depositInput: first divergence at offset 261, 01 + 1626 (bips 9750 LE) versus 00, then the identical 20-byte authority f39fd6e5…b92266 and two bool bytes — a 2-byte length delta exactly matching the dropped u16. Pinned on both sides (serialize(&literal) == literal_bytes in Rust, codec round-trip in V5Codecs).
Every hand-rolled encoder in the mock-Gateway suite is gone. encodeDeposit, signJit, and encodeFill now route through getV5AdapterInputEncoder / getAcrossDepositJitParamsEncoder / getV5FillJitEncoder, so the whole V5 wire surface is exercised by the shipped client against the live program. Combined with the Rust golden fixtures and the V5Codecs tag assertions (expected[0] === 0 / === 1, "without an account discriminator"), there's no longer a parallel encoder that can drift. This is better than the pre-retirement state, where the V4 tests had their own hand-rolled paths.
Cache key fix is correct and complete. scripts/svm/buildHelpers/** now covers includeV5IdlTypes.ts, both build scripts, and the client generators; export_v5_types.rs stays covered by programs/**/*.rs.
Baseline snapshot is verifiable. All four permalinks resolve at 0d776a08 (sizes 34610 / 39370 / 7349 / 8664), and cb5a25fe is confirmed as the commit that deleted exactly those four files — so "their contents match the files deleted in the retirement commit" checks out. Pinning to a fixed snapshot with an explicit "remains the baseline when the PR base moves or the stack is rebased" instruction resolves the staleness concern properly.
Execution-lane disclosure is stronger than I asked for. Beyond the per-row CI/Manual/Mixed column, the preamble states plainly that "guarantees whose replacements run only in RealGateway therefore lost automated PR regression coverage when the V4 suites were removed" and that "a green ordinary SVM or vector check alone does not validate those guarantees." That's the honest framing.
Also re-confirmed: zero dead-code/unused-import warnings (default and --features test); 17 / 21 Rust tests pass; anchor idl build's stdout parsing still yields exactly one IDL block with the extra [[bin]] present; prettier and git diff --check clean; V5_ADAPTER_SPEC.md and V4_COVERAGE.md at zero over-length non-table lines; no new broken markdown links (the 4 that exist are pre-existing in script/mintburn/README.md); the only surviving references to removed symbols are the negative assertions that pin their absence.
The SLOW_FILL_RETIREMENT.md rewording correctly scopes the stability promise to CommonError's reserved 6003/6005 slots and points at the mapping for the renumbered SVM range.
One trivial cosmetic nit inline — genuinely optional, not worth another round on its own.
|
@droplet-rl , please recheck as decided also to remove |
|
Rechecked the The breakTwo test files disagreed about the generated client:
I confirmed the IDL now emits 21 instructions with Everything else verified
The off-chain formula in the spec is exactly right. Also noticed you addressed the With that one line fixed I'm still approving. My formal approval from the previous round stands; I couldn't re-submit it as a review here because this trigger came in as a conversation comment rather than a review request. |
c41783c to
168eeac
Compare
0d776a0 to
a7c1af0
Compare
097fcc1 to
c0bccd8
Compare
a7c1af0 to
cc197c0
Compare
c0bccd8 to
5a788e3
Compare
cc197c0 to
de953f7
Compare
Signed-off-by: Reinis Martinsons <reinis@umaproject.org>
Signed-off-by: Reinis Martinsons <reinis@umaproject.org>
Signed-off-by: Reinis Martinsons <reinis@umaproject.org>
Signed-off-by: Reinis Martinsons <reinis@umaproject.org>
Signed-off-by: Reinis Martinsons <reinis@umaproject.org>
Signed-off-by: Reinis Martinsons <reinis@umaproject.org>
Signed-off-by: Reinis Martinsons <reinis@umaproject.org>
Signed-off-by: Reinis Martinsons <reinis@umaproject.org>
Signed-off-by: Reinis Martinsons <reinis@umaproject.org>
Signed-off-by: Reinis Martinsons <reinis@umaproject.org>
Signed-off-by: Reinis Martinsons <reinis@umaproject.org>
Signed-off-by: Reinis Martinsons <reinis@umaproject.org>
Signed-off-by: Reinis Martinsons <reinis@umaproject.org>
Signed-off-by: Reinis Martinsons <reinis@umaproject.org>
Signed-off-by: Reinis Martinsons <reinis@umaproject.org>
Signed-off-by: Reinis Martinsons <reinis@umaproject.org>
Signed-off-by: Reinis Martinsons <reinis@umaproject.org>
get_unsafe_deposit_id is retired, so the generated client no longer exports getGetUnsafeDepositIdInstruction. V5Codecs still asserted it is a function, contradicting the absence check in SlowFillRetirement and failing the ordinary SVM suite. The negative assertion there already pins the retirement. Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Reinis Martinsons <reinis@umaproject.org>
Signed-off-by: Reinis Martinsons <reinis@umaproject.org>
Signed-off-by: Reinis Martinsons <reinis@umaproject.org>
Signed-off-by: Reinis Martinsons <reinis@umaproject.org>
Signed-off-by: Reinis Martinsons <reinis@umaproject.org>
Signed-off-by: Reinis Martinsons <reinis@umaproject.org>
Signed-off-by: Reinis Martinsons <reinis@umaproject.org>
Signed-off-by: Reinis Martinsons <reinis@umaproject.org>
Signed-off-by: Reinis Martinsons <reinis@umaproject.org>
f74ec61 to
e7b52c9
Compare
Solana deposits and fills now enter only through
adapter_execute_across_v5. Removedeposit,deposit_now,unsafe_deposit,fill_relay, and the legacy read-onlyget_unsafe_deposit_idfrom the program, IDL, and generated clients; historical selectors fail withInstructionFallbackNotFound(101), including empty-message and buffered fills.Remove the corresponding handlers/account contexts, obsolete tests, V4 example scripts, and fill-parameter builders. Add dispatch/IDL/client rejection checks, historical account decoding and expiry rent reclaim, and shared source-validation cases exercised through V5. The synthetic refund example funds the vault directly with an SPL transfer.
Expose all three V5 payload roots and their dependencies in the published IDL:
V5AdapterInputfor tagged committed deposit/fill input,AcrossDepositJitParamsfor signed source modifications, andV5FillJitfor relay/repayment JIT. RetainRelayDataand its codecs. These are discriminator-free Borsh payloads; remove the retiredFillRelayParamsaccount/type/codecs, whose eight-byte account discriminator is not part of the V5 JIT format. Production and test IDL generation include the schemas directly from Rust'sIdlBuildderives without adding a callable instruction. SDK-side Codama generation can consume the complete published IDL without schema injection. The intended boundary is for contracts to publish IDL and the SDK to generate/export production clients; the existing contracts client exports remain until that separate migration makes local generation development-only. Public codec bytes match Rust fixtures for both committed-input variants, both deposit amount modes, fixed-width source signatures, and fill JIT; source/fill tests use those generated encoders. The shared SVM artifact cache also hashesscripts/svm/buildHelpers/**, so IDL/client-generation tooling changes invalidate cached PR and publication artifacts (and verified test binaries).Remove the V4-only
web3-v1subpath exportsgetDepositSeedHash,getDepositPda,getDepositNowSeedHash,getDepositNowPda,getFillRelayDelegateSeedHash,getFillRelayDelegatePda,DepositSeedData, andDepositNowSeedData, alongside the already retiredloadFillRelayParamsandcreateFillRelayParamsInstructions.Keep the chain/cluster utilities, relay hashing, refund and generic instruction-buffer helpers. Migration notes
list the breaking exports and direct consumers to the V5 adapter's delegate rules.
Port applicable deleted V4 regressions to V5: CPI-guarded Token-2022 funding through the pinned Gateway's one-shot
delegate route, wrapped native SOL with new/existing accounts, explicit Spoke-vault and recipient-ATA provisioning,
and two distinct external fills in one buffered v0 transaction with an ALT. Assert funding/allowance/token/status/rent
accounting and atomic rollback when the last fill fails. Add missing-approval, mint/account/authority negatives and
post-exclusivity fill coverage. Exercise retained public Codama builders and the public V5 JIT codec. The
coverage inventory maps deleted cases to named tests and identifies retired
interface semantics. Each row labels CI, manual, or mixed execution and attributes the guarantees accordingly.
The real-Gateway suite is run locally and is not part of PR CI; guarantees whose replacements only run there
have narrower CI regression coverage than the deleted V4 tests. CI hash-vector checks do not exercise real Gateway
execution. The two-fill case tests composition and atomic rollback under one shared destination commitment.
Current Madrid/Jussi execution submits one order leg per Gateway transaction; a maximum-fill benchmark is deferred
until a concrete relayer batching design exists.
The shared
_depositand_fillbodies, V5 adapter behavior, retained account layouts, and event schemas are unchanged. Remove orphaned V4 helpers; retain the two shared legacy branches with narrowly scoped warning allowances and explicit follow-up removal notes. Remove four unused V4 errors and their orphaned message-validation helpers. Preserve all deployed CommonError assignments, including the two slow-fill slots; the undeployed SVM range becomes 7000–7016. The migration table compares against deployedv5.0.12-beta.1(d8da3000), not intermediate stack values. Admin/root messaging, refunds/claims, and cleanup entrypoints remain available. Remove the obsolete deposit-ID helper and its empty account context: historical IDs remain computable off-chain, and V5 uses a separate Gateway-bound derivation. Document and test that V5 deposits leave the legacy deposit counter unchanged. Use.accountsPartialfor explicit auto-resolvable accounts in source/fill tests and the refund example,removing the latter's builder casts while preserving account values and account resolution. Type the shared
parameter helper against production methods without requiring an exact test IDL, so both production scripts
and test clients typecheck together.
Stacked on #1551, targeting
reinis/acp-222-retire-legacy-fill-callbacks. Land after the remaining V5 stack. Further shared-core simplification is deferred.Validation:
Legacy ID helper removal: 17 production / 21 test-feature Rust tests passed, as did verified production/test builds with no stack-limit diagnostics. All 3 retirement compatibility tests passed against the verified test binary on a fresh validator, including the removed selector and historical rent reclaim. Package and retirement-test TypeScript checks passed. Relative to
7b203ac0, the regenerated production IDL changes only by removingget_unsafe_deposit_id; its generated client file and exports are absent.Rust unit tests: 17 production / 21 with the test feature. Standalone
svm_spokeSBF build passes with platform-tools v1.52.Production/test IDLs and clients regenerated. The IDL delta removes the four V4 deposit/fill instructions, the legacy deposit-ID helper, and the
FillRelayParamsaccount/type, and exports all three V5 payload roots and their dependencies.RelayData, retained instructions/account definitions, and event schemas are unchanged. Payload schemas match between production and test IDLs, all references resolve, and repeated schema inclusion produces identical bytes.6 public-codec/export tests passed, covering both committed-input variants, both deposit amount modes, source JIT's fixed signature, and fill JIT against Rust fixtures. Built package exports include all nine root encoder/decoder/codec factories. The independent Gateway hash-vector test passed.
30 codec/source/fill/retirement tests passed on a local Solana 2.1.21 validator with Anchor 0.31.1 and a fresh SBF build, using generated input and JIT encoders. The separate pinned real-Gateway/swap suite passed 25 tests, including guarded funding, native SOL, account provisioning, and buffered two-fill rollback. The real-Gateway suite is manual validation, not PR CI.
Package TypeScript and explicit strict checks passed for the V5 source/fill, codec and retirement suites, schema-generation script, production refund script, and Bundle/RefundClaims helper callers. Formatting,
git diff --check, and pre-commit checks passed.Cache invalidation checked across all three workflow callers. Isolated helper-only edits change the new content hash while leaving the old hash unchanged; generation helpers are now included in the shared cache inputs.
An earlier full verified SVM CI run at
11ac800a5cf63f5255f193e4792fdc691e3a1b56passed 124 tests, 0 failed, including all six instruction-params cases. This confirmed the earlier local account-initialization failure did not require a fixture change; the result is historical evidence for that commit, not a claim about the current head.The EVM test job at that earlier commit reported 667 passed / 1 failed:
SponsoredCCTPDstPeripheryTest.setUp()could not create its Hyperliquid fork because the RPC rejected block46778852(invalid block height). Current-head CI status is reported by the PR checks.Sent from Reinis Martinsons's Codex CLI Agent using gpt-6-astra 🤖