From 8857727d5837d3672d96e7bfa616c7e30fa750d8 Mon Sep 17 00:00:00 2001 From: Morenikeoa Date: Fri, 26 Jun 2026 23:31:30 +0100 Subject: [PATCH] fix(abi): update stale v12.19 ACCOUNTS_RESOLVE_MARKET + ACCOUNTS_CONVERT_RELEASED_PNL specs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both account specs still documented their v12.19 4-account layouts even though their paired encoders were confirmed rewritten for v17: - ACCOUNTS_RESOLVE_MARKET still listed [admin(s+w), slab(w), clock, oracle] (src/percolator.rs:9748), but encodeResolveMarket's own doc says "v17 wire: tag(1) only... BREAKING vs v12.x ... the mode byte has been REMOVED" — the spec was never updated to match, unlike every other v17-rewritten spec in this file (each carries an explicit "v17 wire account layout" comment). - ACCOUNTS_CONVERT_RELEASED_PNL still listed [user(s+w), slab(w), clock, oracle] (src/percolator.rs:10636), but encodeConvertReleasedPnl's own doc says "BREAKING vs v12.x: userIdx(u16) removed... v17 portfolios are identified by account key alone" and points directly back to this constant ("Accounts: see ACCOUNTS_CONVERT_RELEASED_PNL") — but the spec was never updated to add the account-key-identified portfolio its own paired encoder's doc describes. Both fixes are evidence-based inferences, not confirmed v17 wrapper reads (no percolator-prog source is available in this repo to verify directly): - ResolveMarket: every one of the 13 other "v17 wire account layout" specs in this file drops clock/oracle as standalone accounts with no exception. The closest structural analog, ACCOUNTS_RESTART_ASSET_ORACLE — also admin-gated, market-level, no-token-movement — is exactly [authority(signer), market(w)]. Inferred as [admin(s+w), market(w)]. - ConvertReleasedPnl: owner-initiated, moves no real tokens — the exact same category as ACCOUNTS_INIT_USER (InitPortfolio) and ACCOUNTS_CLOSE_ACCOUNT (ClosePortfolio), both confirmed v17-rewritten to the identical 3-account shape [owner(signer,w), market(w), portfolio(w)]. Inferred as the same shape. Both inferences are flagged explicitly in their code comments and should be verified against an actual v17 handle_resolve_market / handle_convert_released_pnl decode (devnet dry-run or program source) before being relied on in production. Leaving the old, definitely- stale 4-account specs in place was not a safer default — both encoders no longer emit payloads that match what the v12.19 account counts were paired with, so the old specs were already known wrong, just wrong in a less-examined way. Added regression tests for both asserting no standalone clock/oracle accounts and the new shapes. Confirmed both fail against the prior 4-account specs and pass against this fix. Full suite: 853 passed | 31 skipped (882 -> 884, +2 new tests). --- src/abi/accounts.ts | 57 ++++++++++++++++++++++++++++++++++--------- test/accounts.test.ts | 28 +++++++++++++++++++++ 2 files changed, 73 insertions(+), 12 deletions(-) diff --git a/src/abi/accounts.ts b/src/abi/accounts.ts index ac8ab17..3000e50 100644 --- a/src/abi/accounts.ts +++ b/src/abi/accounts.ts @@ -382,15 +382,29 @@ export const ACCOUNTS_SET_ORACLE_PRICE_CAP: readonly AccountSpec[] = [ ] as const; /** - * ResolveMarket: 4 accounts. - * v12.19 wrapper at src/percolator.rs:9748 calls accounts::expect_len(4). - * Layout: [admin(s+w), slab(w), clock, oracle]. + * ResolveMarket (tag 19): 2 accounts (inferred — see confidence note below). + * + * The v12.19 4-account layout this constant previously documented + * ([admin(s+w), slab(w), clock, oracle], src/percolator.rs:9748) is stale: its + * paired encoder `encodeResolveMarket` was confirmed rewritten for v17 + * (instructions.ts) — "v17 wire: tag(1) only... BREAKING vs v12.x ... the mode + * byte has been REMOVED" — but this account spec was never updated to match, + * unlike every other v17-rewritten spec in this file. + * + * INFERENCE, not a confirmed v17 wrapper read (no percolator-prog source is + * available in this repo to verify directly): every one of the 13 other specs + * in this file carrying a "v17 wire account layout" comment explicitly drops + * `clock` and `oracle` as standalone accounts with no exception (e.g. + * ACCOUNTS_TRADE_NOCPI: "v12 stale accounts removed: lp, clock, oracle"; + * ACCOUNTS_CLOSE_PORTFOLIO: "...clock, oracle"). The closest structural analog, + * ACCOUNTS_RESTART_ASSET_ORACLE — also an admin-gated, market-level, + * no-token-movement instruction — is exactly [authority(signer), market(w)]. + * Before relying on this in production, verify against an actual v17 + * `handle_resolve_market` decode (devnet dry-run or program source). */ export const ACCOUNTS_RESOLVE_MARKET: readonly AccountSpec[] = [ { name: "admin", signer: true, writable: true }, - { name: "slab", signer: false, writable: true }, - { name: "clock", signer: false, writable: false }, - { name: "oracle", signer: false, writable: false }, + { name: "market", signer: false, writable: true }, ] as const; /** @@ -496,14 +510,33 @@ export const ACCOUNTS_DEPOSIT_FEE_CREDITS: readonly AccountSpec[] = [ ] as const; /** - * ConvertReleasedPnl (tag 28): 4 accounts. Owner only. - * Wrapper: src/percolator.rs:10636. + * ConvertReleasedPnl (tag 28): 3 accounts (inferred — see confidence note below). + * Owner only. No token movement (internal PnL-bucket conversion within the + * same portfolio). + * + * The v12.19 4-account layout this constant previously documented + * ([user(s+w), slab(w), clock, oracle], src/percolator.rs:10636) is stale. + * Its paired encoder, `encodeConvertReleasedPnl`, was confirmed rewritten for + * v17 (instructions.ts): "BREAKING vs v12.x: userIdx(u16) removed... v17 + * portfolios are identified by account key alone" — and that same comment + * points back to this exact constant ("Accounts: see + * ACCOUNTS_CONVERT_RELEASED_PNL"), but this spec was never updated to add the + * account-key-identified portfolio the encoder's own doc describes. + * + * INFERENCE, not a confirmed v17 wrapper read (no percolator-prog source is + * available in this repo to verify directly). Basis: ConvertReleasedPnl is + * owner-initiated and moves no real tokens, the exact same category as + * ACCOUNTS_INIT_USER (InitPortfolio) and ACCOUNTS_CLOSE_ACCOUNT + * (ClosePortfolio) — both confirmed v17-rewritten to the identical 3-account + * shape [owner(signer,w), market(w), portfolio(w)], with v12 clock/oracle/userIdx + * dropped for the same "account-key, not index" reason this encoder's doc cites. + * Before relying on this in production, verify against an actual v17 + * `handle_convert_released_pnl` decode (devnet dry-run or program source). */ export const ACCOUNTS_CONVERT_RELEASED_PNL: readonly AccountSpec[] = [ - { name: "user", signer: true, writable: true }, - { name: "slab", signer: false, writable: true }, - { name: "clock", signer: false, writable: false }, - { name: "oracle", signer: false, writable: false }, + { name: "owner", signer: true, writable: true }, + { name: "market", signer: false, writable: true }, + { name: "portfolio", signer: false, writable: true }, ] as const; /** diff --git a/test/accounts.test.ts b/test/accounts.test.ts index 9ea338b..168ee38 100644 --- a/test/accounts.test.ts +++ b/test/accounts.test.ts @@ -18,6 +18,7 @@ import { ACCOUNTS_UPDATE_CONFIG, ACCOUNTS_SET_MAINTENANCE_FEE, ACCOUNTS_RESOLVE_MARKET, + ACCOUNTS_CONVERT_RELEASED_PNL, ACCOUNTS_WITHDRAW_INSURANCE, ACCOUNTS_WITHDRAW_INSURANCE_LIMITED_LIVE, ACCOUNTS_WITHDRAW_INSURANCE_LIMITED_RESOLVED, @@ -264,6 +265,33 @@ describe("Signer / writable invariants", () => { } }); + it("ACCOUNTS_RESOLVE_MARKET matches its v17-rewritten encoder, not the stale v12.19 layout", () => { + // encodeResolveMarket was confirmed rewritten for v17 (tag-only, no mode byte). + // Every other v17-rewritten spec in this file drops standalone clock/oracle + // accounts with no exception — this spec must not still carry them. + expect(ACCOUNTS_RESOLVE_MARKET).toHaveLength(2); + expect(ACCOUNTS_RESOLVE_MARKET.find((a) => a.name === "clock")).toBeUndefined(); + expect(ACCOUNTS_RESOLVE_MARKET.find((a) => a.name === "oracle")).toBeUndefined(); + expect(ACCOUNTS_RESOLVE_MARKET[0]).toMatchObject({ name: "admin", signer: true, writable: true }); + const marketSlab = ACCOUNTS_RESOLVE_MARKET.find((a) => a.name === "slab" || a.name === "market"); + expect(marketSlab, "market/slab account missing").toBeDefined(); + expect(marketSlab!.writable).toBe(true); + }); + + it("ACCOUNTS_CONVERT_RELEASED_PNL matches its v17-rewritten encoder, not the stale v12.19 layout", () => { + // encodeConvertReleasedPnl's own doc says "v17 portfolios are identified by + // account key alone" (userIdx removed) and points back to this constant — + // it must include a portfolio account, not the old userIdx-era clock/oracle pair. + expect(ACCOUNTS_CONVERT_RELEASED_PNL).toHaveLength(3); + expect(ACCOUNTS_CONVERT_RELEASED_PNL.find((a) => a.name === "clock")).toBeUndefined(); + expect(ACCOUNTS_CONVERT_RELEASED_PNL.find((a) => a.name === "oracle")).toBeUndefined(); + expect(ACCOUNTS_CONVERT_RELEASED_PNL.find((a) => a.name === "portfolio")).toBeDefined(); + expect(ACCOUNTS_CONVERT_RELEASED_PNL[0]).toMatchObject({ name: "owner", signer: true, writable: true }); + const marketSlab2 = ACCOUNTS_CONVERT_RELEASED_PNL.find((a) => a.name === "slab" || a.name === "market"); + expect(marketSlab2, "market/slab account missing").toBeDefined(); + expect(marketSlab2!.writable).toBe(true); + }); + }); // ============================================================================