diff --git a/.github/workflows/parity-gate.yml b/.github/workflows/parity-gate.yml index 8d36c3a..7e7cd73 100644 --- a/.github/workflows/parity-gate.yml +++ b/.github/workflows/parity-gate.yml @@ -45,6 +45,23 @@ jobs: repository: ${{ github.repository_owner }}/percolator-prog path: percolator-prog + # #375: percolator-prog compiles the engine through `percolator = { path = + # "../percolator" }`, so WITHOUT this checkout its fixture cannot build at + # all — `cargo run` dies with "failed to get `percolator` as a dependency of + # package `percolator-prog`" before a single tag is compared. That was the + # second of the two reasons the prog target never ran; the first was the + # fixture binary not existing. + # + # Deliberately NOT pinned. The engine is a path dependency compiled INTO the + # wrapper rather than a separate deployed program, so its main IS what the + # wrapper ships — the same reasoning percolator-prog's own ci.yml gives for + # leaving the engine unpinned while pinning the sibling programs. + - name: Checkout percolator (engine — path dependency of percolator-prog) + uses: actions/checkout@v4 + with: + repository: ${{ github.repository_owner }}/percolator + path: percolator + - name: Checkout percolator-stake uses: actions/checkout@v4 with: diff --git a/specs/stake-parity.json b/specs/stake-parity.json index 0ecb262..987d501 100644 --- a/specs/stake-parity.json +++ b/specs/stake-parity.json @@ -35,6 +35,26 @@ "name": "UpdateConfig", "tag": 4 }, + { + "name": "ProposeAdmin", + "tag": 5 + }, + { + "name": "AcceptAdmin", + "tag": 6 + }, + { + "name": "ProposeCooldownIncrease", + "tag": 7 + }, + { + "name": "CommitCooldownIncrease", + "tag": 8 + }, + { + "name": "CancelCooldownIncrease", + "tag": 9 + }, { "name": "ReturnInsurance", "tag": 10 @@ -62,15 +82,50 @@ { "name": "SetMarketResolved", "tag": 18 + }, + { + "name": "BindInsuranceAuthority", + "tag": 19 + }, + { + "name": "RotateInsuranceAuthority", + "tag": 20 + }, + { + "name": "BurnAssetAdmin", + "tag": 21 + }, + { + "name": "RotateInsuranceOperator", + "tag": 22 + }, + { + "name": "RecoverFlushedInsurance", + "tag": 23 + }, + { + "name": "AdminResolveMarket", + "tag": 24 + }, + { + "name": "AdminUpdateFeeSplit", + "tag": 25 + }, + { + "name": "AdminUpdateMaintenanceFeePerSlot", + "tag": 26 + }, + { + "name": "AdminUpdateBackingFeePolicy", + "tag": 27 + }, + { + "name": "AdminUpdateTradeFeePolicy", + "tag": 28 } ], "program": "percolator-stake", "removed_tags": [ - 5, - 6, - 7, - 8, - 9, 11, 17 ], diff --git a/specs/wrapper-tags.json b/specs/wrapper-tags.json index 326571b..a1029b0 100644 --- a/specs/wrapper-tags.json +++ b/specs/wrapper-tags.json @@ -23,7 +23,6 @@ 71 ], "program": "percolator-prog", - "version": "v17", "tags": [ { "name": "InitMarket", "tag": 0 }, { "name": "InitPortfolio", "tag": 1 }, @@ -84,6 +83,19 @@ { "name": "ExecuteRedemption", "tag": 77 }, { "name": "LpVaultCrankFees", "tag": 78 }, { "name": "SetLpVaultPaused", "tag": 79 }, - { "name": "CloseLpVault", "tag": 80 } - ] + { "name": "CloseLpVault", "tag": 80 }, + { "name": "CancelRedemption", "tag": 81 }, + { "name": "UnwrapEscrowedPortfolio", "tag": 82 }, + { "name": "InitMatcherCtx", "tag": 83 }, + { "name": "WithdrawProtocolFee", "tag": 84 }, + { "name": "SetProtocolFeeAuthority", "tag": 85 }, + { "name": "UpdateFeeSplit", "tag": 86 }, + { "name": "WithdrawInsuranceReserveToStake", "tag": 87 }, + { "name": "UpdateMaintenanceFeePerSlot", "tag": 88 }, + { "name": "ExpireBackingBucket", "tag": 89 }, + { "name": "WithdrawCreatorFee", "tag": 90 }, + { "name": "RebalanceLpVaultBacking", "tag": 91 }, + { "name": "UpdateInsuranceWithdrawPolicy", "tag": 92 } + ], + "version": "v17" } diff --git a/src/abi/instructions.ts b/src/abi/instructions.ts index 7d0701f..c219808 100644 --- a/src/abi/instructions.ts +++ b/src/abi/instructions.ts @@ -205,6 +205,24 @@ export const IX_TAG = { * Wire: tag(1) = 1 byte. */ CloseLpVault: 80, + /** + * CancelRedemption (tag 81) — withdraw a pending LP redemption request before it + * is executed, returning the shares to the holder. + * Wire: tag(1) = 1 byte. + * + * GH#375: this and UnwrapEscrowedPortfolio(82) were the only two v17 wrapper + * instructions with NO entry here. Tags 81 and 82 were represented solely by the + * deprecated v12 names below, both annotated "Not in v17" — which is false. The + * Parity Gate exists to catch exactly this and could not: its percolator-prog + * target had never once run. + */ + CancelRedemption: 81, + /** + * UnwrapEscrowedPortfolio (tag 82) — burn a Position NFT and return the escrowed + * portfolio to `new_owner`. + * Wire: tag(1) + new_owner(32) = 33 bytes. + */ + UnwrapEscrowedPortfolio: 82, // ── Legacy aliases retained for source-compat (do NOT assign new tags) ──── /** @deprecated v12.x alias. Use DepositToLpVault(75) in v17. */ LpVaultDeposit: 75, @@ -289,9 +307,9 @@ export const IX_TAG = { SetOiCapMultiplier: 79, /** @deprecated v12.x tag 80. COLLIDES with v17 CloseLpVault(80). Do NOT use. */ SetDisputeParams: 80, - /** @deprecated v12.x tag 81. Not in v17. */ + /** @deprecated v12.x tag 81. COLLIDES with v17 CancelRedemption(81). Do NOT use. */ SetLpCollateralParams: 81, - /** @deprecated v12.x tag 82. Not in v17. */ + /** @deprecated v12.x tag 82. COLLIDES with v17 UnwrapEscrowedPortfolio(82). Do NOT use. */ AcceptAdmin: 82, /** * InitMatcherCtx (tag 83) — bootstrap a matcher context by CPIing to the matcher program. diff --git a/test/parity-fixtures.test.ts b/test/parity-fixtures.test.ts index 455ee62..85fd9ec 100644 --- a/test/parity-fixtures.test.ts +++ b/test/parity-fixtures.test.ts @@ -100,6 +100,26 @@ describe("Rust parity fixtures", () => { LpVaultCrankFees: IX_TAG.LpVaultCrankFees, SetLpVaultPaused: IX_TAG.SetLpVaultPaused, CloseLpVault: IX_TAG.CloseLpVault, + // GH#375: tags 81-92 were absent from the committed spec, so this map never + // needed them and the gap was invisible. IX_TAG already had 83-92; only + // CancelRedemption(81) and UnwrapEscrowedPortfolio(82) were genuinely + // missing from the SDK and are added in src/abi/instructions.ts. + // + // 84/85/86/87/90/91/92 are the protocol-fee, creator-fee and + // insurance-to-stake surface — the money-movement instructions — which is + // what makes this worth more than tidiness. + CancelRedemption: IX_TAG.CancelRedemption, + UnwrapEscrowedPortfolio: IX_TAG.UnwrapEscrowedPortfolio, + InitMatcherCtx: IX_TAG.InitMatcherCtx, + WithdrawProtocolFee: IX_TAG.WithdrawProtocolFee, + SetProtocolFeeAuthority: IX_TAG.SetProtocolFeeAuthority, + UpdateFeeSplit: IX_TAG.UpdateFeeSplit, + WithdrawInsuranceReserveToStake: IX_TAG.WithdrawInsuranceReserveToStake, + UpdateMaintenanceFeePerSlot: IX_TAG.UpdateMaintenanceFeePerSlot, + ExpireBackingBucket: IX_TAG.ExpireBackingBucket, + WithdrawCreatorFee: IX_TAG.WithdrawCreatorFee, + RebalanceLpVaultBacking: IX_TAG.RebalanceLpVaultBacking, + UpdateInsuranceWithdrawPolicy: IX_TAG.UpdateInsuranceWithdrawPolicy, }; for (const entry of fixture.tags) { @@ -137,6 +157,31 @@ describe("Rust parity fixtures", () => { AdminSetTrancheConfig: STAKE_IX.AdminSetTrancheConfig, DepositJunior: STAKE_IX.DepositJunior, SetMarketResolved: STAKE_IX.SetMarketResolved, + // GH#375: the fifteen below were missing from this map, from the committed + // spec, and from `removed_tags` — which actively asserted 5-9 were REMOVED. + // All fifteen are live in percolator-stake and always have been (identical + // at 474079f, d0c6ecb and main): they are the admin-transfer, + // cooldown-governance, insurance-authority and fee-policy surface. + // STAKE_IX already carried every one — only this curated subset and the spec + // disagreed, and they agreed with each OTHER, so nothing ever flagged it. + ProposeAdmin: STAKE_IX.ProposeAdmin, + AcceptAdmin: STAKE_IX.AcceptAdmin, + ProposeCooldownIncrease: STAKE_IX.ProposeCooldownIncrease, + CommitCooldownIncrease: STAKE_IX.CommitCooldownIncrease, + CancelCooldownIncrease: STAKE_IX.CancelCooldownIncrease, + BindInsuranceAuthority: STAKE_IX.BindInsuranceAuthority, + RotateInsuranceAuthority: STAKE_IX.RotateInsuranceAuthority, + BurnAssetAdmin: STAKE_IX.BurnAssetAdmin, + RotateInsuranceOperator: STAKE_IX.RotateInsuranceOperator, + RecoverFlushedInsurance: STAKE_IX.RecoverFlushedInsurance, + // Tag 24 is `AdminResolveMarket` in the PROGRAM. In STAKE_IX that name is a + // deprecated percolator-vault alias for tag 9, and the tag-24 entry is + // `AdminResolveMarketCpi` — so this pair is deliberately not name-matched. + AdminResolveMarket: STAKE_IX.AdminResolveMarketCpi, + AdminUpdateFeeSplit: STAKE_IX.AdminUpdateFeeSplit, + AdminUpdateMaintenanceFeePerSlot: STAKE_IX.AdminUpdateMaintenanceFeePerSlot, + AdminUpdateBackingFeePolicy: STAKE_IX.AdminUpdateBackingFeePolicy, + AdminUpdateTradeFeePolicy: STAKE_IX.AdminUpdateTradeFeePolicy, }; // The fixture mirrors percolator-stake SOURCE (scripts/update-parity-fixtures.mjs @@ -167,7 +212,10 @@ describe("Rust parity fixtures", () => { expect(sdkTags[entry.name]).toBe(entry.tag); } - expect(fixture.removed_tags).toEqual([5, 6, 7, 8, 9, 11, 17]); + // GH#375: was [5, 6, 7, 8, 9, 11, 17]. Tags 5-9 are ProposeAdmin, + // AcceptAdmin and the three cooldown-governance instructions, live in + // every ref. Only 11 and 17 are genuinely unallocated. + expect(fixture.removed_tags).toEqual([11, 17]); }); it("PositionNft layout matches percolator-nft", () => {