From 68a95ab0d8fcfc0877b1d7d90563c2ea0d3df38d Mon Sep 17 00:00:00 2001 From: Kaze <230549489+kaze-cow@users.noreply.github.com> Date: Tue, 28 Jul 2026 17:19:50 +0900 Subject: [PATCH 01/43] add settlement IDL --- programs/settlement/idl/cow_settlement.json | 430 ++++++++++++++++++++ 1 file changed, 430 insertions(+) create mode 100644 programs/settlement/idl/cow_settlement.json diff --git a/programs/settlement/idl/cow_settlement.json b/programs/settlement/idl/cow_settlement.json new file mode 100644 index 0000000..e9ca134 --- /dev/null +++ b/programs/settlement/idl/cow_settlement.json @@ -0,0 +1,430 @@ +{ + "address": "MooohhPEAAHwAwEozL7JPEmnDvaahuUpccYN4Yb8ccK", + "metadata": { + "name": "cow_settlement", + "version": "0.1.0", + "spec": "0.1.0", + "description": "CoW Protocol settlement program. HAND-WRITTEN IDL: this program is a native/Pinocchio program, not built with the Anchor framework, so this file was authored manually to describe its wire format as closely as the Anchor IDL grammar allows. See the per-instruction/type docs for spots where the on-chain format cannot be fully expressed (non-standard 1-byte instruction discriminators, and BeginSettle's dynamically-shaped tail)." + }, + "instructions": [ + { + "name": "initialize", + "docs": [ + "Creates the singleton settlement state PDA. Succeeds only once.", + "Non-standard discriminator: this program uses a single instruction-selector byte (see SettlementInstruction in the Rust source), not Anchor's usual 8-byte sighash. The `discriminator` below reflects the real on-chain bytes." + ], + "discriminator": [3], + "accounts": [ + { + "name": "payer", + "writable": true, + "signer": true, + "docs": [ + "Funds the state PDA's rent and pays the transaction fee." + ] + }, + { + "name": "state_pda", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [115, 101, 116, 116, 108, 101, 109, 101, 110, 116] + } + ] + }, + "docs": [ + "Canonical PDA seeded by the literal string \"settlement\"." + ] + }, + { + "name": "system_program", + "address": "11111111111111111111111111111111" + } + ], + "args": [] + }, + { + "name": "create_buffer", + "docs": [ + "Creates one or more per-token buffer PDAs (SPL token accounts) in a single instruction.", + "IDL MODELING NOTE: the real instruction accepts an unbounded number of (buffer_pda, mint) pairs as remaining accounts, one pair per buffer, with at least one pair required (CreateBuffer rejects zero buffers). Anchor's IDL grammar has no 'repeated group' construct, so this file only declares the guaranteed index-0 template (buffer_pda_0/mint_0). This instruction is solver/internal tooling only, not part of the public client surface, so buffers beyond the first are intentionally left unmodeled here: callers needing more than one buffer per transaction append the extra (buffer_pda, mint) account-meta pairs by hand after building the base instruction.", + "Each buffer_pda_i must be the canonical PDA for seeds [\"settlement\", mint_i, \"buffer\"]." + ], + "discriminator": [4], + "accounts": [ + { + "name": "payer", + "writable": true, + "signer": true + }, + { + "name": "system_program", + "address": "11111111111111111111111111111111" + }, + { + "name": "token_program", + "address": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + { + "name": "buffer_pda_0", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [115, 101, 116, 116, 108, 101, 109, 101, 110, 116] + }, + { + "kind": "account", + "path": "mint_0" + }, + { + "kind": "const", + "value": [98, 117, 102, 102, 101, 114] + } + ] + }, + "docs": [ + "Guaranteed present: CreateBuffer rejects an instruction with zero buffers." + ] + }, + { + "name": "mint_0", + "docs": [ + "Guaranteed present: CreateBuffer rejects an instruction with zero buffers." + ] + } + ], + "args": [] + }, + { + "name": "create_order", + "docs": [ + "Allocates a per-order PDA and writes the initial OrderAccount body.", + "order_pda's canonical seeds are [\"settlement\", sha256(intent_bytes), \"order\"]. This is not expressible as a static `pda` entry because the middle seed is a hash of the entire `intent` argument, not a plain field/account reference, which is outside what the Anchor PDA-seed grammar (const / arg / account) can describe." + ], + "discriminator": [2], + "accounts": [ + { + "name": "owner", + "signer": true, + "docs": [ + "Must match intent.owner; authenticates the order." + ] + }, + { + "name": "created_by", + "writable": true, + "signer": true, + "docs": [ + "Funds the new order PDA's rent." + ] + }, + { + "name": "order_pda", + "writable": true, + "docs": [ + "See the seed-derivation note above; cannot be auto-derived by IDL-driven tooling." + ] + }, + { + "name": "system_program", + "address": "11111111111111111111111111111111" + } + ], + "args": [ + { + "name": "intent", + "type": { + "defined": { + "name": "OrderIntent" + } + } + } + ] + }, + { + "name": "begin_settle", + "docs": [ + "Pulls funds for a batch of orders. Must be paired in the same transaction with a FinalizeSettle at `finalize_ix_index`.", + "IDL LIMITATION: only the fixed-size prefix (finalize_ix_index) is represented as a typed argument. After it, the real wire format is `[order_count: u8][bump; order_count][transfer_count; order_count][amount: u64 BE; sum(transfer_count)]` \u2014 a hand-packed layout with no Borsh length prefixes and a trailing array whose length depends on the sum of an earlier array. This has no representation in the Anchor/Borsh/IDL type grammar (no vec/array type can express 'shared count governs several sibling arrays' or 'length = sum of another field'), so it is intentionally left out of `args` rather than mislabeled as `bytes` (which would imply a Borsh Vec length prefix that isn't actually present and would make a generic decoder misparse it). Anchor/Solscan-style tooling will only decode the discriminator and finalize_ix_index for this instruction; the remainder needs bespoke client logic.", + "Per-order accounts follow the 3 shared accounts below as a repeated remaining-accounts group: [order_pda (readonly), sell_token_account (writable), destination (writable) x transfer_count], sorted by ascending order_pda address." + ], + "discriminator": [0], + "accounts": [ + { + "name": "instructions_sysvar", + "address": "Sysvar1nstructions1111111111111111111111111" + }, + { + "name": "state_pda", + "docs": [ + "Must be the canonical state PDA; signs each pull as the user's SPL delegate." + ] + }, + { + "name": "token_program", + "address": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + } + ], + "args": [ + { + "name": "finalize_ix_index", + "type": "u16", + "docs": [ + "Index of the paired FinalizeSettle in this transaction. Little-endian, matching standard Borsh/Anchor u16 decoding." + ] + } + ] + }, + { + "name": "finalize_settle", + "docs": [ + "Validates that a BeginSettle at `begin_ix_index` exists and points back at this instruction. Must not be called via CPI.", + "Non-standard discriminator, see the note on `initialize`." + ], + "discriminator": [1], + "accounts": [ + { + "name": "instructions_sysvar", + "address": "Sysvar1nstructions1111111111111111111111111" + } + ], + "args": [ + { + "name": "begin_ix_index", + "type": "u16", + "docs": [ + "Index of the paired BeginSettle in this transaction. Little-endian, matching standard Borsh/Anchor u16 decoding." + ] + } + ] + } + ], + "accounts": [ + { + "name": "OrderAccount", + "discriminator": [128] + }, + { + "name": "SettlementState", + "discriminator": [129] + } + ], + "types": [ + { + "name": "OrderAccount", + "docs": [ + "Body of an order PDA, created by create_order. 200 bytes total: 1-byte discriminator + 199 bytes of fields below." + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "cancelled", + "type": "bool" + }, + { + "name": "amount_withdrawn", + "type": "u64" + }, + { + "name": "amount_received", + "type": "u64" + }, + { + "name": "created_by", + "type": "pubkey" + }, + { + "name": "intent", + "type": { + "defined": { + "name": "OrderIntent" + } + } + } + ] + } + }, + { + "name": "SettlementState", + "docs": [ + "Body of the singleton settlement state PDA. Carries no fields beyond the 1-byte discriminator; its existence and address are what matter." + ], + "type": { + "kind": "struct", + "fields": [] + } + }, + { + "name": "OrderIntent", + "docs": [ + "Canonical 150-byte order intent. Also the exact bytes hashed (SHA-256) to produce the order UID used in the order PDA's seeds, and the exact wire format of create_order's `intent` argument. Field order and encoding here are load-bearing: they must match this program's Rust definition exactly." + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "owner", + "type": "pubkey" + }, + { + "name": "buy_token_account", + "type": "pubkey" + }, + { + "name": "sell_token_account", + "type": "pubkey" + }, + { + "name": "sell_amount", + "type": "u64" + }, + { + "name": "buy_amount", + "type": "u64" + }, + { + "name": "valid_to", + "type": "u32" + }, + { + "name": "kind", + "type": { + "defined": { + "name": "OrderKind" + } + } + }, + { + "name": "partially_fillable", + "type": "bool" + }, + { + "name": "app_data", + "type": { + "array": [ + "u8", + 32 + ] + } + } + ] + } + }, + { + "name": "OrderKind", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Sell" + }, + { + "name": "Buy" + } + ] + } + } + ], + "errors": [ + { + "code": 0, + "name": "FinalizeBeforeInitialize", + "msg": "The FinalizeSettle included as input to BeginSettle isn't before the actual BeginSettle index." + }, + { + "code": 1, + "name": "BeginFinalizePairOverlap", + "msg": "Another BeginSettle/FinalizeSettle of this program appears strictly between this pair's bounds, nesting or overlapping two settlements." + }, + { + "code": 2, + "name": "MissingCounterpartInstruction", + "msg": "The counterpart index points past the end of the transaction's instruction list, so no instruction sits there." + }, + { + "code": 3, + "name": "CounterpartIsExternal", + "msg": "The instruction at the counterpart index belongs to a different program." + }, + { + "code": 4, + "name": "InvalidCounterpartDiscriminator", + "msg": "The counterpart instruction's discriminator byte couldn't be recovered from its data." + }, + { + "code": 5, + "name": "InvalidCounterpartCounterpart", + "msg": "The counterpart instruction's own counterpart index couldn't be recovered from its data." + }, + { + "code": 6, + "name": "MismatchedCounterpartDiscriminator", + "msg": "The counterpart's discriminator isn't the expected BeginSettle/FinalizeSettle kind, or its counterpart index doesn't point back at this instruction." + }, + { + "code": 7, + "name": "OwnerMismatch", + "msg": "CreateOrder instruction wasn't signed by the created OrderIntent owner." + }, + { + "code": 8, + "name": "OrderNotCanonical", + "msg": "A BeginSettle order account doesn't sit at the canonical order PDA derived from the intent it stores and the supplied bump." + }, + { + "code": 9, + "name": "OrdersNotStrictlyIncreasing", + "msg": "BeginSettle's order accounts aren't passed strictly increasing by address." + }, + { + "code": 10, + "name": "SellTokenAccountMismatch", + "msg": "A BeginSettle sell token account doesn't match the sell_token_account recorded in the order's intent." + }, + { + "code": 11, + "name": "SellTokenAccountInvalid", + "msg": "A BeginSettle sell token account isn't a valid SPL token account (wrong data length or not owned by the token program)." + }, + { + "code": 12, + "name": "SellTokenOwnerMismatch", + "msg": "A BeginSettle sell token account's SPL owner isn't the order's intent owner." + }, + { + "code": 13, + "name": "AccountCountNotMatchingOrderCount", + "msg": "BeginSettle's order-account count doesn't match the structure its instruction data expects." + }, + { + "code": 14, + "name": "CalledViaCpi", + "msg": "BeginSettle or FinalizeSettle was invoked via CPI rather than as a top-level transaction instruction." + }, + { + "code": 15, + "name": "OrderCancelled", + "msg": "A BeginSettle order has been cancelled by its owner and can no longer be settled." + }, + { + "code": 16, + "name": "OrderExpired", + "msg": "A BeginSettle order's valid_to lies in the past: the order has expired and can no longer be settled." + }, + { + "code": 17, + "name": "TransferCountMismatch", + "msg": "The transfer counts in BeginSettle don't sum to the number of transfer amounts, so destinations and amounts can't be paired up exactly." + }, + { + "code": 18, + "name": "StateAccountMismatch", + "msg": "BeginSettle's state account isn't the canonical settlement state PDA, which must sign the pulls as the user's token delegate." + } + ] +} From 55f056205fd0b51be1e6f34f1c51105133f991b2 Mon Sep 17 00:00:00 2001 From: Kaze <230549489+kaze-cow@users.noreply.github.com> Date: Thu, 16 Jul 2026 17:20:58 +0900 Subject: [PATCH 02/43] generate js client with codama and add a basic test to make sure it works --- .gitignore | 3 + .../settlement/idl/client/js/package.json | 29 +++++++ .../settlement/idl/client/js/src/hooked.ts | 33 ++++++++ .../settlement/idl/client/js/src/index.ts | 1 + .../idl/client/js/tests/createOrder.test.ts | 75 +++++++++++++++++++ .../idl/client/js/tests/fixtures.ts | 26 +++++++ .../settlement/idl/client/js/tsconfig.json | 12 +++ programs/settlement/idl/generate.mjs | 34 +++++++++ programs/settlement/idl/package.json | 18 +++++ 9 files changed, 231 insertions(+) create mode 100644 programs/settlement/idl/client/js/package.json create mode 100644 programs/settlement/idl/client/js/src/hooked.ts create mode 100644 programs/settlement/idl/client/js/src/index.ts create mode 100644 programs/settlement/idl/client/js/tests/createOrder.test.ts create mode 100644 programs/settlement/idl/client/js/tests/fixtures.ts create mode 100644 programs/settlement/idl/client/js/tsconfig.json create mode 100644 programs/settlement/idl/generate.mjs create mode 100644 programs/settlement/idl/package.json diff --git a/.gitignore b/.gitignore index c812024..4157890 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ /target proptest-regressions/ .cargo-root/ +node_modules/ +pnpm-lock.yaml +generated/ \ No newline at end of file diff --git a/programs/settlement/idl/client/js/package.json b/programs/settlement/idl/client/js/package.json new file mode 100644 index 0000000..298012c --- /dev/null +++ b/programs/settlement/idl/client/js/package.json @@ -0,0 +1,29 @@ +{ + "name": "js-client", + "version": "1.0.0", + "description": "", + "main": "src/index.ts", + "files": [ + "./dist/src", + "./dist/types", + "./src/" + ], + "scripts": { + "test": "vitest run" + }, + "keywords": [], + "author": "", + "peerDependencies": { + "@solana/kit": "^6.10.0" + }, + "dependencies": { + "@solana/program-client-core": "^6.10.0" + }, + "devDependencies": { + "@solana/kit": "^6.10.0", + "@types/node": "^24.10.0", + "litesvm": "^1.3.0", + "typescript": "^5.7.0", + "vitest": "^3.0.0" + } +} diff --git a/programs/settlement/idl/client/js/src/hooked.ts b/programs/settlement/idl/client/js/src/hooked.ts new file mode 100644 index 0000000..b36c25c --- /dev/null +++ b/programs/settlement/idl/client/js/src/hooked.ts @@ -0,0 +1,33 @@ +// Hand-written — Codama's "hooked" convention: functions referenced by a +// `resolverValueNode` default value live here, imported by generated code +// via the fixed "../../hooked" specifier (see generate.mjs). Never touched +// by rendering, which only manages src/generated. +// +// create_order's order PDA is seeded by ["settlement", sha256(borsh(intent)), "order"]. +// The middle seed is a hash of the whole `intent` argument rather than a plain +// field/account reference, which the Anchor PDA-seed grammar (const / arg / account) +// can't express — see cow_settlement.json's create_order docs — so it's handed off +// to this resolver instead of a plain `pda` node. Codama calls this with a +// `resolverScope` object and splices the returned `{ value }` onto the account +// it's resolving, so its shape is dictated by the renderer, not chosen here. + +import { getProgramDerivedAddress, type Address } from "@solana/kit"; +import { getOrderIntentEncoder, type OrderIntentArgs } from "./generated"; + +export async function resolveOrderPda({ + programAddress, + args, +}: { + programAddress: Address; + args: { intent: OrderIntentArgs }; +}): Promise<{ value: Address }> { + const intentBytes = getOrderIntentEncoder().encode(args.intent); + const orderUid = new Uint8Array( + await crypto.subtle.digest("SHA-256", intentBytes), + ); + const [address] = await getProgramDerivedAddress({ + programAddress, + seeds: ["settlement", orderUid, "order"], + }); + return { value: address }; +} diff --git a/programs/settlement/idl/client/js/src/index.ts b/programs/settlement/idl/client/js/src/index.ts new file mode 100644 index 0000000..e84c86c --- /dev/null +++ b/programs/settlement/idl/client/js/src/index.ts @@ -0,0 +1 @@ +export * from "./generated"; diff --git a/programs/settlement/idl/client/js/tests/createOrder.test.ts b/programs/settlement/idl/client/js/tests/createOrder.test.ts new file mode 100644 index 0000000..8ee88ab --- /dev/null +++ b/programs/settlement/idl/client/js/tests/createOrder.test.ts @@ -0,0 +1,75 @@ +import { LiteSVM } from "litesvm"; +import { beforeEach, describe, expect, it } from "vitest"; +import { + appendTransactionMessageInstruction, + createTransactionMessage, + generateKeyPairSigner, + lamports, + pipe, + setTransactionMessageFeePayerSigner, + setTransactionMessageLifetimeUsingBlockhash, + signTransactionMessageWithSigners, +} from "@solana/kit"; +import { + COW_SETTLEMENT_PROGRAM_ADDRESS, + getCreateOrderInstructionAsync, + getOrderAccountDecoder, +} from "../src/generated"; +import { resolveOrderPda } from "../src/hooked"; +import { buildOrderIntent, COW_SETTLEMENT_SO_PATH } from "./fixtures"; + +describe("createOrder", () => { + let svm: LiteSVM; + + beforeEach(() => { + svm = new LiteSVM(); + svm.addProgramFromFile(COW_SETTLEMENT_PROGRAM_ADDRESS, COW_SETTLEMENT_SO_PATH); + }); + + it("creates an order account matching the submitted intent", async () => { + const owner = await generateKeyPairSigner(); + svm.airdrop(owner.address, lamports(1_000_000_000n)); + + const intent = await buildOrderIntent({ owner: owner.address }); + const instruction = await getCreateOrderInstructionAsync({ + owner, + createdBy: owner, + intent, + }); + + const tx = await pipe( + createTransactionMessage({ version: 0 }), + (t) => setTransactionMessageFeePayerSigner(owner, t), + (t) => + setTransactionMessageLifetimeUsingBlockhash( + { blockhash: svm.latestBlockhash(), lastValidBlockHeight: 999_999_999n }, + t, + ), + (t) => appendTransactionMessageInstruction(instruction, t), + signTransactionMessageWithSigners, + ); + + const result = svm.sendTransaction(tx); + if ("err" in result) { + throw new Error(`createOrder failed: ${JSON.stringify(result.err)}`); + } + + const { value: orderPda } = await resolveOrderPda({ + programAddress: COW_SETTLEMENT_PROGRAM_ADDRESS, + args: { intent }, + }); + const account = svm.getAccount(orderPda); + expect(account).not.toBeNull(); + + const decoded = getOrderAccountDecoder().decode(account!.data); + expect(decoded.cancelled).toBe(false); + expect(decoded.amountWithdrawn).toBe(0n); + expect(decoded.amountReceived).toBe(0n); + expect(decoded.createdBy).toBe(owner.address); + expect(decoded.intent).toEqual({ + ...intent, + sellAmount: BigInt(intent.sellAmount), + buyAmount: BigInt(intent.buyAmount), + }); + }); +}); diff --git a/programs/settlement/idl/client/js/tests/fixtures.ts b/programs/settlement/idl/client/js/tests/fixtures.ts new file mode 100644 index 0000000..c6b7721 --- /dev/null +++ b/programs/settlement/idl/client/js/tests/fixtures.ts @@ -0,0 +1,26 @@ +import path from "node:path"; +import { generateKeyPairSigner, type Address } from "@solana/kit"; +import { OrderKind, type OrderIntentArgs } from "../src/generated"; + +export const COW_SETTLEMENT_SO_PATH = path.join( + import.meta.dirname, + "../../../../../../target/deploy/cow_settlement.so", +); + +export async function buildOrderIntent( + overrides: Partial & { owner: Address }, +): Promise { + const buyTokenAccount = await generateKeyPairSigner(); + const sellTokenAccount = await generateKeyPairSigner(); + return { + buyTokenAccount: buyTokenAccount.address, + sellTokenAccount: sellTokenAccount.address, + sellAmount: 1_000_000n, + buyAmount: 2_000_000n, + validTo: Math.floor(Date.now() / 1000) + 3600, + kind: OrderKind.Sell, + partiallyFillable: false, + appData: new Uint8Array(32), + ...overrides, + }; +} diff --git a/programs/settlement/idl/client/js/tsconfig.json b/programs/settlement/idl/client/js/tsconfig.json new file mode 100644 index 0000000..991173d --- /dev/null +++ b/programs/settlement/idl/client/js/tsconfig.json @@ -0,0 +1,12 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "strict": true, + "skipLibCheck": true, + "esModuleInterop": true, + "types": ["node"] + }, + "include": ["src", "tests"] +} diff --git a/programs/settlement/idl/generate.mjs b/programs/settlement/idl/generate.mjs new file mode 100644 index 0000000..0cf3bb0 --- /dev/null +++ b/programs/settlement/idl/generate.mjs @@ -0,0 +1,34 @@ +import { + createFromRoot, + resolverValueNode, + argumentValueNode, + setInstructionAccountDefaultValuesVisitor, +} from "codama"; +import { rootNodeFromAnchor } from "@codama/nodes-from-anchor"; +import { renderVisitor } from "@codama/renderers-js"; +import IDL from "./cow_settlement.json" with {type: 'json'}; + +const codama = createFromRoot(rootNodeFromAnchor(IDL)); + +// order_pda seed generation requires hashing the input intent in `createOrder` +// so we use codama's `resolverValueNode` to inject custom code for this. +codama.update( + setInstructionAccountDefaultValuesVisitor([ + { + instruction: "createOrder", + account: "orderPda", + defaultValue: resolverValueNode("resolveOrderPda", { + dependsOn: [argumentValueNode("intent")], + }), + }, + ]), +); + +codama.accept( + renderVisitor("./client/js", { + // resolveOrderPda hashes with crypto.subtle.digest, which is async, so + // codama must await it and only wire it into the *Async instruction + // builder rather than the sync one. + asyncResolvers: ["resolveOrderPda"], + }), +); diff --git a/programs/settlement/idl/package.json b/programs/settlement/idl/package.json new file mode 100644 index 0000000..3179784 --- /dev/null +++ b/programs/settlement/idl/package.json @@ -0,0 +1,18 @@ +{ + "name": "idl", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "packageManager": "pnpm@10.30.3", + "dependencies": { + "@codama/nodes-from-anchor": "^1.5.2", + "@codama/renderers-js": "^2.3.0", + "codama": "^1.9.0" + } +} From 7e63017a7d3ec15cd0a6b70cba01c57c60e92d36 Mon Sep 17 00:00:00 2001 From: Kaze <230549489+kaze-cow@users.noreply.github.com> Date: Wed, 29 Jul 2026 23:32:03 +0900 Subject: [PATCH 03/43] add validation of the idl --- Cargo.lock | 209 ++++- Cargo.toml | 3 + interface/src/data/intent.rs | 3 + programs/settlement/Cargo.toml | 3 + programs/settlement/idl/cow_settlement.json | 170 +++- .../idl/schema/idl-spec-v0.1.0.json | 780 ++++++++++++++++++ programs/settlement/tests/idl.rs | 364 ++++++++ 7 files changed, 1510 insertions(+), 22 deletions(-) create mode 100644 programs/settlement/idl/schema/idl-spec-v0.1.0.json create mode 100644 programs/settlement/tests/idl.rs diff --git a/Cargo.lock b/Cargo.lock index 2920587..f408f88 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -131,6 +131,7 @@ dependencies = [ "cfg-if", "getrandom 0.3.4", "once_cell", + "serde", "version_check", "zerocopy", ] @@ -620,6 +621,12 @@ dependencies = [ "hybrid-array", ] +[[package]] +name = "borrow-or-share" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc0b364ead1874514c8c2855ab558056ebfeb775653e7ae45ff72f28f8f3166c" + [[package]] name = "borsh" version = "1.7.0" @@ -690,6 +697,12 @@ dependencies = [ "serde", ] +[[package]] +name = "bytecount" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175812e0be2bccb6abe50bb8d566126198344f707e304f45c648fd8f2cc0365e" + [[package]] name = "bytemuck" version = "1.25.0" @@ -1223,6 +1236,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "email_address" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e079f19b08ca6239f47f8ba8509c11cf3ea30095831f7fed61441475edd8c449" +dependencies = [ + "serde", +] + [[package]] name = "encode_unicode" version = "1.0.0" @@ -1285,6 +1307,17 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "fancy-regex" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e24cb5a94bcae1e5408b0effca5cd7172ea3c5755049c5f3af4cd283a165298" +dependencies = [ + "bit-set", + "regex-automata", + "regex-syntax", +] + [[package]] name = "fastrand" version = "2.4.1" @@ -1353,6 +1386,17 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "fluent-uri" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1918b65d96df47d3591bed19c5cca17e3fa5d0707318e4b5ef2eae01764df7e5" +dependencies = [ + "borrow-or-share", + "ref-cast", + "serde", +] + [[package]] name = "fnv" version = "1.0.7" @@ -1368,6 +1412,16 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fraction" +version = "0.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e076045bb43dac435333ed5f04caf35c7463631d0dae2deb2638d94dd0a5b872" +dependencies = [ + "lazy_static", + "num 0.4.3", +] + [[package]] name = "futures" version = "0.3.32" @@ -1919,6 +1973,33 @@ dependencies = [ "serde_json", ] +[[package]] +name = "jsonschema" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1b46a0365a611fbf1d2143104dcf910aada96fafd295bab16c60b802bf6fa1d" +dependencies = [ + "ahash", + "base64 0.22.1", + "bytecount", + "email_address", + "fancy-regex", + "fraction", + "idna", + "itoa", + "num-cmp", + "num-traits", + "once_cell", + "percent-encoding", + "referencing", + "regex", + "regex-syntax", + "reqwest", + "serde", + "serde_json", + "uuid-simd", +] + [[package]] name = "k256" version = "0.13.4" @@ -2198,10 +2279,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8536030f9fea7127f841b45bb6243b27255787fb4eb83958aa1ef9d2fdc0c36" dependencies = [ "num-bigint 0.2.6", - "num-complex", + "num-complex 0.2.4", "num-integer", "num-iter", - "num-rational", + "num-rational 0.2.4", + "num-traits", +] + +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint 0.4.6", + "num-complex 0.4.6", + "num-integer", + "num-iter", + "num-rational 0.4.2", "num-traits", ] @@ -2226,6 +2321,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-cmp" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63335b2e2c34fae2fb0aa2cecfd9f0832a1e24b3b32ecec612c3426d46dc8aaa" + [[package]] name = "num-complex" version = "0.2.4" @@ -2236,6 +2337,15 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + [[package]] name = "num-derive" version = "0.4.2" @@ -2279,6 +2389,17 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint 0.4.6", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -2328,6 +2449,12 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" +[[package]] +name = "outref" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a80800c0488c3a21695ea981a54918fbb37abf04f4d0720c453632255e2ff0e" + [[package]] name = "parking_lot" version = "0.12.5" @@ -2384,7 +2511,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2fd23b938276f14057220b707937bcb42fa76dda7560e57a2da30cb52d557937" dependencies = [ - "num", + "num 0.2.1", ] [[package]] @@ -2737,6 +2864,40 @@ dependencies = [ "bitflags", ] +[[package]] +name = "ref-cast" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "216e8f773d7923bcba9ceb86a86c93cabb3903a11872fc3f138c49630e50b96d" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9283685feec7d69af75fb0e858d5e7378f33fe4fc699383b2916ab9273e03c" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + +[[package]] +name = "referencing" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8eff4fa778b5c2a57e85c5f2fe3a709c52f0e60d23146e2151cbef5893f420e" +dependencies = [ + "ahash", + "fluent-uri", + "once_cell", + "parking_lot", + "percent-encoding", + "serde_json", +] + [[package]] name = "regex" version = "1.12.4" @@ -3019,6 +3180,7 @@ version = "1.0.150" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" dependencies = [ + "indexmap", "itoa", "memchr", "serde", @@ -3065,12 +3227,14 @@ name = "settlement" version = "0.1.0" dependencies = [ "arrayref", + "jsonschema", "litesvm", "litesvm-token", "pinocchio", "pinocchio-system", "pinocchio-token", "proptest", + "serde_json", "settlement-client", "settlement-interface", "solana-address-lookup-table-interface", @@ -3078,6 +3242,7 @@ dependencies = [ "solana-instructions-sysvar", "solana-sdk", "solana-system-interface 3.2.0", + "syn 2.0.118", ] [[package]] @@ -5367,6 +5532,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "sync_wrapper" version = "1.0.2" @@ -5717,6 +5893,27 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" +[[package]] +name = "uuid" +version = "1.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf3923a6f5c4c6382e0b653c4117f48d631ea17f38ed86e2a828e6f7412f5239" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "uuid-simd" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b082222b4f6619906941c17eb2297fff4c2fb96cb60164170522942a200bd8" +dependencies = [ + "outref", + "uuid", + "vsimd", +] + [[package]] name = "version_check" version = "0.9.5" @@ -5729,6 +5926,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" +[[package]] +name = "vsimd" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c3082ca00d5a5ef149bb8b555a72ae84c9c59f7250f013ac822ac2e49b19c64" + [[package]] name = "wait-timeout" version = "0.2.1" diff --git a/Cargo.toml b/Cargo.toml index 2e4f19c..6abbb80 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ solana-program-pack = "3" solana-rpc-client = "3" derive_more = { version = "1", features = ["deref"] } hex-literal = "1" +jsonschema = "0.30" litesvm = "0.12.0" litesvm-token = "0.12.0" num_enum = "0.7" @@ -26,6 +27,7 @@ pinocchio = "0.11.1" pinocchio-system = "0.6" pinocchio-token = "0.6" proptest = "1" +serde_json = { version = "1", features = ["preserve_order"] } settlement-client = { path = "client" } settlement-interface = { path = "interface" } solana-account-view = "2" @@ -43,6 +45,7 @@ solana-system-interface = "3" spl-associated-token-account-interface = { version = "2" } spl-token = "9" spl-token-interface = "2" +syn = { version = "2", features = ["full"] } [workspace.metadata.cli] # Used to help solana-verify identify the correct build image. diff --git a/interface/src/data/intent.rs b/interface/src/data/intent.rs index ba1ac0f..8586b95 100644 --- a/interface/src/data/intent.rs +++ b/interface/src/data/intent.rs @@ -32,6 +32,9 @@ pub enum OrderKind { Buy = 1, } +/// Canonical order intent. Also the exact bytes hashed (SHA-256) to produce the order UID used in the order PDA's seeds, +/// and the exact wire format of create_order's `intent` argument. Field order and encoding here are load-bearing: they +/// must match this program's Rust definition exactly. #[derive(Clone, Debug, Eq, PartialEq, Default)] pub struct OrderIntent { /// Account authorized to create and invalidate this order and whose diff --git a/programs/settlement/Cargo.toml b/programs/settlement/Cargo.toml index 028e2c4..e1b2041 100644 --- a/programs/settlement/Cargo.toml +++ b/programs/settlement/Cargo.toml @@ -21,15 +21,18 @@ solana-instruction = { workspace = true, features = ["syscalls"] } [dev-dependencies] arrayref.workspace = true +jsonschema.workspace = true litesvm.workspace = true litesvm-token.workspace = true proptest.workspace = true +serde_json.workspace = true settlement-client.workspace = true settlement-interface = { workspace = true, features = ["test-fixtures"] } solana-address-lookup-table-interface = { workspace = true, features = ["bincode"] } solana-instructions-sysvar.workspace = true solana-sdk.workspace = true solana-system-interface.workspace = true +syn.workspace = true [lints] workspace = true diff --git a/programs/settlement/idl/cow_settlement.json b/programs/settlement/idl/cow_settlement.json index e9ca134..3c2415a 100644 --- a/programs/settlement/idl/cow_settlement.json +++ b/programs/settlement/idl/cow_settlement.json @@ -13,7 +13,9 @@ "Creates the singleton settlement state PDA. Succeeds only once.", "Non-standard discriminator: this program uses a single instruction-selector byte (see SettlementInstruction in the Rust source), not Anchor's usual 8-byte sighash. The `discriminator` below reflects the real on-chain bytes." ], - "discriminator": [3], + "discriminator": [ + 3 + ], "accounts": [ { "name": "payer", @@ -30,7 +32,18 @@ "seeds": [ { "kind": "const", - "value": [115, 101, 116, 116, 108, 101, 109, 101, 110, 116] + "value": [ + 115, + 101, + 116, + 116, + 108, + 101, + 109, + 101, + 110, + 116 + ] } ] }, @@ -52,7 +65,9 @@ "IDL MODELING NOTE: the real instruction accepts an unbounded number of (buffer_pda, mint) pairs as remaining accounts, one pair per buffer, with at least one pair required (CreateBuffer rejects zero buffers). Anchor's IDL grammar has no 'repeated group' construct, so this file only declares the guaranteed index-0 template (buffer_pda_0/mint_0). This instruction is solver/internal tooling only, not part of the public client surface, so buffers beyond the first are intentionally left unmodeled here: callers needing more than one buffer per transaction append the extra (buffer_pda, mint) account-meta pairs by hand after building the base instruction.", "Each buffer_pda_i must be the canonical PDA for seeds [\"settlement\", mint_i, \"buffer\"]." ], - "discriminator": [4], + "discriminator": [ + 4 + ], "accounts": [ { "name": "payer", @@ -74,7 +89,18 @@ "seeds": [ { "kind": "const", - "value": [115, 101, 116, 116, 108, 101, 109, 101, 110, 116] + "value": [ + 115, + 101, + 116, + 116, + 108, + 101, + 109, + 101, + 110, + 116 + ] }, { "kind": "account", @@ -82,7 +108,14 @@ }, { "kind": "const", - "value": [98, 117, 102, 102, 101, 114] + "value": [ + 98, + 117, + 102, + 102, + 101, + 114 + ] } ] }, @@ -105,7 +138,9 @@ "Allocates a per-order PDA and writes the initial OrderAccount body.", "order_pda's canonical seeds are [\"settlement\", sha256(intent_bytes), \"order\"]. This is not expressible as a static `pda` entry because the middle seed is a hash of the entire `intent` argument, not a plain field/account reference, which is outside what the Anchor PDA-seed grammar (const / arg / account) can describe." ], - "discriminator": [2], + "discriminator": [ + 2 + ], "accounts": [ { "name": "owner", @@ -149,10 +184,12 @@ "name": "begin_settle", "docs": [ "Pulls funds for a batch of orders. Must be paired in the same transaction with a FinalizeSettle at `finalize_ix_index`.", - "IDL LIMITATION: only the fixed-size prefix (finalize_ix_index) is represented as a typed argument. After it, the real wire format is `[order_count: u8][bump; order_count][transfer_count; order_count][amount: u64 BE; sum(transfer_count)]` \u2014 a hand-packed layout with no Borsh length prefixes and a trailing array whose length depends on the sum of an earlier array. This has no representation in the Anchor/Borsh/IDL type grammar (no vec/array type can express 'shared count governs several sibling arrays' or 'length = sum of another field'), so it is intentionally left out of `args` rather than mislabeled as `bytes` (which would imply a Borsh Vec length prefix that isn't actually present and would make a generic decoder misparse it). Anchor/Solscan-style tooling will only decode the discriminator and finalize_ix_index for this instruction; the remainder needs bespoke client logic.", + "IDL LIMITATION: only the fixed-size prefix (finalize_ix_index, auction_id) is represented as typed arguments. After it, the real wire format is `[order_count: u8][bump; order_count][transfer_count; order_count][amount: u64 LE; sum(transfer_count)]` — a hand-packed layout with no Borsh length prefixes and a trailing array whose length depends on the sum of an earlier array. This has no representation in the Anchor/Borsh/IDL type grammar (no vec/array type can express 'shared count governs several sibling arrays' or 'length = sum of another field'), so it is intentionally left out of `args` rather than mislabeled as `bytes` (which would imply a Borsh Vec length prefix that isn't actually present and would make a generic decoder misparse it). Anchor/Solscan-style tooling will only decode the discriminator, finalize_ix_index, and auction_id for this instruction; the remainder needs bespoke client logic.", "Per-order accounts follow the 3 shared accounts below as a repeated remaining-accounts group: [order_pda (readonly), sell_token_account (writable), destination (writable) x transfer_count], sorted by ascending order_pda address." ], - "discriminator": [0], + "discriminator": [ + 0 + ], "accounts": [ { "name": "instructions_sysvar", @@ -176,6 +213,13 @@ "docs": [ "Index of the paired FinalizeSettle in this transaction. Little-endian, matching standard Borsh/Anchor u16 decoding." ] + }, + { + "name": "auction_id", + "type": "i64", + "docs": [ + "The off-chain auction this settlement executes. Carried in the instruction data so the settlement can be tied back to its auction off-chain, unused on-chain." + ] } ] }, @@ -183,13 +227,26 @@ "name": "finalize_settle", "docs": [ "Validates that a BeginSettle at `begin_ix_index` exists and points back at this instruction. Must not be called via CPI.", - "Non-standard discriminator, see the note on `initialize`." + "Non-standard discriminator, see the note on `initialize`.", + "Per-push accounts follow the 3 shared accounts below as a repeated remaining-accounts group: [source_buffer (writable), destination (writable)] x number of pushes." + ], + "discriminator": [ + 1 ], - "discriminator": [1], "accounts": [ { "name": "instructions_sysvar", "address": "Sysvar1nstructions1111111111111111111111111" + }, + { + "name": "state_pda", + "docs": [ + "Must be the canonical state PDA; signs each push as the buffers' SPL token authority." + ] + }, + { + "name": "token_program", + "address": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" } ], "args": [ @@ -201,23 +258,62 @@ ] } ] + }, + { + "name": "reclaim_order", + "docs": [ + "Closes an expired order PDA and returns its rent lamports to the created_by account recorded in the order body. The instruction may only be executed after the order's valid_to timestamp has elapsed.", + "No signature requirement: anyone may reclaim an expired order on behalf of its reclaim_recipient." + ], + "discriminator": [ + 5 + ], + "accounts": [ + { + "name": "order_pda", + "writable": true, + "docs": [ + "The order PDA to close." + ] + }, + { + "name": "reclaim_recipient", + "writable": true, + "docs": [ + "Must match the created_by address recorded in the order; receives the recovered rent lamports." + ] + } + ], + "args": [ + { + "name": "bump", + "type": "u8", + "docs": [ + "order_pda's canonical bump, used to prove it's the canonical order PDA for the intent it stores." + ] + } + ] } ], "accounts": [ { "name": "OrderAccount", - "discriminator": [128] + "discriminator": [ + 128 + ] }, { "name": "SettlementState", - "discriminator": [129] + "discriminator": [ + 129 + ] } ], "types": [ { "name": "OrderAccount", "docs": [ - "Body of an order PDA, created by create_order. 200 bytes total: 1-byte discriminator + 199 bytes of fields below." + "Idiomatic representation of an order PDA's body." ], "type": { "kind": "struct", @@ -255,14 +351,15 @@ "Body of the singleton settlement state PDA. Carries no fields beyond the 1-byte discriminator; its existence and address are what matter." ], "type": { - "kind": "struct", - "fields": [] + "kind": "struct" } }, { "name": "OrderIntent", "docs": [ - "Canonical 150-byte order intent. Also the exact bytes hashed (SHA-256) to produce the order UID used in the order PDA's seeds, and the exact wire format of create_order's `intent` argument. Field order and encoding here are load-bearing: they must match this program's Rust definition exactly." + "Canonical order intent. Also the exact bytes hashed (SHA-256) to produce the order UID used in the order PDA's seeds,", + "and the exact wire format of create_order's `intent` argument. Field order and encoding here are load-bearing: they", + "must match this program's Rust definition exactly." ], "type": { "kind": "struct", @@ -373,8 +470,8 @@ }, { "code": 8, - "name": "OrderNotCanonical", - "msg": "A BeginSettle order account doesn't sit at the canonical order PDA derived from the intent it stores and the supplied bump." + "name": "AccountNotDerivable", + "msg": "An account was provided that cannot be derived from the seeds recognized by the program" }, { "code": 9, @@ -399,7 +496,7 @@ { "code": 13, "name": "AccountCountNotMatchingOrderCount", - "msg": "BeginSettle's order-account count doesn't match the structure its instruction data expects." + "msg": "BeginSettle's order-account count doesn't match the structure its instruction data expects: n orders each contribute an order PDA and a sell token account, plus one destination account per transfer." }, { "code": 14, @@ -425,6 +522,41 @@ "code": 18, "name": "StateAccountMismatch", "msg": "BeginSettle's state account isn't the canonical settlement state PDA, which must sign the pulls as the user's token delegate." + }, + { + "code": 19, + "name": "AccountCountNotMatchingPushCount", + "msg": "FinalizeSettle's push-account count doesn't match its instruction data: each push contributes a source buffer and a destination account, so the count must be twice the number of push amounts." + }, + { + "code": 20, + "name": "SettledOrderPushCountMismatch", + "msg": "BeginSettle: the number of pushes carried by the paired FinalizeSettle doesn't equal the number of settled orders. Each order must be paid by exactly one push." + }, + { + "code": 21, + "name": "PushDestinationMismatch", + "msg": "BeginSettle: a paired FinalizeSettle push doesn't send its proceeds to the order's buy token account; its destination differs from the buy_token_account in the order's intent." + }, + { + "code": 22, + "name": "PushSourceNotBuffer", + "msg": "FinalizeSettle: a push doesn't draw funds from the canonical buffer for its destination's mint." + }, + { + "code": 23, + "name": "InvalidBuyTokenAccount", + "msg": "FinalizeSettle: a push's destination isn't a valid SPL token account (wrong data length or not owned by the token program), so its mint can't be read to derive the buffer." + }, + { + "code": 24, + "name": "OrderNotExpired", + "msg": "ReclaimOrder was called before the order's valid_to has elapsed." + }, + { + "code": 25, + "name": "ReclaimRecipientMismatch", + "msg": "ReclaimOrder's reclaim_recipient account doesn't match the created_by address recorded in the order." } ] } diff --git a/programs/settlement/idl/schema/idl-spec-v0.1.0.json b/programs/settlement/idl/schema/idl-spec-v0.1.0.json new file mode 100644 index 0000000..e2564ff --- /dev/null +++ b/programs/settlement/idl/schema/idl-spec-v0.1.0.json @@ -0,0 +1,780 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://github.com/solana-idl/idl-spec/schema/v0.1.0.json", + "title": "Solana IDL v0.1.0", + "description": "JSON Schema for Solana program Interface Description Language (IDL) files, spec version 0.1.0.", + "type": "object", + "required": ["address", "metadata", "instructions"], + "additionalProperties": false, + "properties": { + "$schema": { + "type": "string", + "description": "Optional JSON Schema reference for editor support." + }, + "address": { + "type": "string", + "description": "The on-chain address of the deployed program." + }, + "metadata": { + "$ref": "#/$defs/IdlMetadata" + }, + "docs": { + "type": "array", + "items": { "type": "string" }, + "default": [], + "description": "Top-level documentation strings for the program. Omitted when empty." + }, + "instructions": { + "type": "array", + "items": { "$ref": "#/$defs/IdlInstruction" }, + "description": "All instructions the program exposes." + }, + "accounts": { + "type": "array", + "items": { "$ref": "#/$defs/IdlAccount" }, + "default": [], + "description": "Account types the program defines (with discriminators). Omitted when empty." + }, + "events": { + "type": "array", + "items": { "$ref": "#/$defs/IdlEvent" }, + "default": [], + "description": "Events the program can emit. Omitted when empty." + }, + "errors": { + "type": "array", + "items": { "$ref": "#/$defs/IdlErrorCode" }, + "default": [], + "description": "Custom error codes. Omitted when empty." + }, + "types": { + "type": "array", + "items": { "$ref": "#/$defs/IdlTypeDef" }, + "default": [], + "description": "Custom type definitions (structs, enums, type aliases). Omitted when empty." + }, + "constants": { + "type": "array", + "items": { "$ref": "#/$defs/IdlConst" }, + "default": [], + "description": "Exported constants. Omitted when empty." + } + }, + "$defs": { + "IdlMetadata": { + "type": "object", + "required": ["name", "version", "spec"], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Program name (typically snake_case)." + }, + "version": { + "type": "string", + "description": "Program version (semver)." + }, + "spec": { + "type": "string", + "const": "0.1.0", + "description": "IDL spec version. Must be \"0.1.0\" for this spec." + }, + "description": { + "type": "string", + "description": "Human-readable program description. Omitted when absent." + }, + "repository": { + "type": "string", + "description": "URL of the source repository. Omitted when absent." + }, + "dependencies": { + "type": "array", + "items": { "$ref": "#/$defs/IdlDependency" }, + "default": [], + "description": "External program dependencies. Omitted when empty." + }, + "contact": { + "type": "string", + "description": "Contact information for the program maintainer. Omitted when absent." + }, + "deployments": { + "$ref": "#/$defs/IdlDeployments", + "description": "Deployment addresses per cluster. Omitted when absent." + } + } + }, + "IdlDependency": { + "type": "object", + "required": ["name", "version"], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Dependency name." + }, + "version": { + "type": "string", + "description": "Dependency version (semver)." + } + } + }, + "IdlDeployments": { + "type": "object", + "required": ["mainnet", "testnet", "devnet", "localnet"], + "additionalProperties": false, + "properties": { + "mainnet": { + "type": ["string", "null"], + "description": "Mainnet-beta program address, or null when absent." + }, + "testnet": { + "type": ["string", "null"], + "description": "Testnet program address, or null when absent." + }, + "devnet": { + "type": ["string", "null"], + "description": "Devnet program address, or null when absent." + }, + "localnet": { + "type": ["string", "null"], + "description": "Localnet program address, or null when absent." + } + } + }, + "IdlDiscriminator": { + "type": "array", + "items": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "description": "Variable-length byte array uniquely identifying instructions, accounts, or events. Length and derivation are framework-specific." + }, + "IdlInstruction": { + "type": "object", + "required": ["name", "discriminator", "accounts", "args"], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Instruction name (camelCase)." + }, + "docs": { + "type": "array", + "items": { "type": "string" }, + "default": [], + "description": "Documentation strings. Omitted when empty." + }, + "discriminator": { + "$ref": "#/$defs/IdlDiscriminator" + }, + "accounts": { + "type": "array", + "items": { "$ref": "#/$defs/IdlInstructionAccountItem" }, + "description": "Accounts required by this instruction." + }, + "args": { + "type": "array", + "items": { "$ref": "#/$defs/IdlField" }, + "description": "Instruction arguments." + }, + "returns": { + "$ref": "#/$defs/IdlType", + "description": "Return type (if the instruction returns data via return_data). Omitted when absent." + } + } + }, + "IdlInstructionAccountItem": { + "description": "Untagged union: either a single account or a composite (nested group). Distinguished by structure: a Composite has an 'accounts' array, a Single does not.", + "oneOf": [ + { "$ref": "#/$defs/IdlInstructionAccounts" }, + { "$ref": "#/$defs/IdlInstructionAccount" } + ] + }, + "IdlInstructionAccount": { + "type": "object", + "required": ["name"], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Account name (camelCase)." + }, + "docs": { + "type": "array", + "items": { "type": "string" }, + "default": [], + "description": "Documentation strings. Omitted when empty." + }, + "writable": { + "type": "boolean", + "default": false, + "description": "Whether the account is written to. Omitted when false." + }, + "signer": { + "type": "boolean", + "default": false, + "description": "Whether the account must sign the transaction. Omitted when false." + }, + "optional": { + "type": "boolean", + "default": false, + "description": "Whether the account is optional. Omitted when false." + }, + "address": { + "type": "string", + "description": "Expected fixed address (e.g. a well-known program). Omitted when absent." + }, + "pda": { + "$ref": "#/$defs/IdlPda", + "description": "PDA derivation info for this account. Omitted when absent." + }, + "relations": { + "type": "array", + "items": { "type": "string" }, + "default": [], + "description": "Names of related accounts (constraint references). Omitted when empty." + } + } + }, + "IdlInstructionAccounts": { + "type": "object", + "required": ["name", "accounts"], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Group name." + }, + "accounts": { + "type": "array", + "items": { "$ref": "#/$defs/IdlInstructionAccountItem" }, + "description": "Nested account items." + } + } + }, + "IdlField": { + "type": "object", + "required": ["name", "type"], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Field name (camelCase)." + }, + "docs": { + "type": "array", + "items": { "type": "string" }, + "default": [], + "description": "Documentation strings. Omitted when empty." + }, + "type": { + "$ref": "#/$defs/IdlType", + "description": "The field's type." + } + } + }, + "IdlAccount": { + "type": "object", + "required": ["name", "discriminator"], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Account type name (PascalCase)." + }, + "discriminator": { + "$ref": "#/$defs/IdlDiscriminator" + } + } + }, + "IdlEvent": { + "type": "object", + "required": ["name", "discriminator"], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Event name (PascalCase)." + }, + "discriminator": { + "$ref": "#/$defs/IdlDiscriminator" + } + } + }, + "IdlErrorCode": { + "type": "object", + "required": ["code", "name"], + "additionalProperties": false, + "properties": { + "code": { + "type": "integer", + "minimum": 0, + "description": "Numeric error code. Custom errors typically start at 6000." + }, + "name": { + "type": "string", + "description": "Error name (PascalCase)." + }, + "msg": { + "type": "string", + "description": "Human-readable error message. Omitted when absent." + } + } + }, + "IdlTypeDef": { + "type": "object", + "required": ["name", "type"], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Type name (PascalCase)." + }, + "docs": { + "type": "array", + "items": { "type": "string" }, + "default": [], + "description": "Documentation strings. Omitted when empty." + }, + "serialization": { + "$ref": "#/$defs/IdlSerialization", + "description": "Serialization format. Omitted when \"borsh\" (default)." + }, + "repr": { + "$ref": "#/$defs/IdlRepr", + "description": "Memory representation hint. Omitted when absent." + }, + "generics": { + "type": "array", + "items": { "$ref": "#/$defs/IdlTypeDefGeneric" }, + "default": [], + "description": "Generic parameters. Omitted when empty." + }, + "type": { + "$ref": "#/$defs/IdlTypeDefTy", + "description": "The kind of type (struct, enum, or alias)." + } + } + }, + "IdlTypeDefTy": { + "description": "Tagged union describing the shape of a type definition. Uses 'kind' as the tag field.", + "oneOf": [ + { + "type": "object", + "required": ["kind"], + "additionalProperties": false, + "properties": { + "kind": { "const": "struct" }, + "fields": { + "$ref": "#/$defs/IdlDefinedFields", + "description": "Struct fields. Omitted when absent." + } + } + }, + { + "type": "object", + "required": ["kind", "variants"], + "additionalProperties": false, + "properties": { + "kind": { "const": "enum" }, + "variants": { + "type": "array", + "items": { "$ref": "#/$defs/IdlEnumVariant" }, + "description": "Enum variants." + } + } + }, + { + "type": "object", + "required": ["kind", "alias"], + "additionalProperties": false, + "properties": { + "kind": { "const": "type" }, + "alias": { + "$ref": "#/$defs/IdlType", + "description": "The aliased type." + } + } + } + ] + }, + "IdlEnumVariant": { + "type": "object", + "required": ["name"], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Variant name (PascalCase)." + }, + "fields": { + "$ref": "#/$defs/IdlDefinedFields", + "description": "Variant data, if any. Omitted when absent." + } + } + }, + "IdlDefinedFields": { + "description": "Untagged union: Named fields (array of objects with 'name' and 'type') or Tuple fields (array of IdlType values).", + "oneOf": [ + { + "type": "array", + "items": { "$ref": "#/$defs/IdlField" }, + "description": "Named fields (like a Rust struct)." + }, + { + "type": "array", + "items": { "$ref": "#/$defs/IdlType" }, + "description": "Positional fields (like a Rust tuple struct)." + } + ] + }, + "IdlType": { + "description": "The IDL type system covering primitives, containers, defined types, and generics.", + "oneOf": [ + { + "type": "string", + "enum": [ + "bool", + "u8", "i8", + "u16", "i16", + "u32", "i32", + "f32", + "u64", "i64", + "f64", + "u128", "i128", + "u256", "i256", + "bytes", "string", "pubkey" + ], + "description": "Primitive type." + }, + { + "type": "object", + "required": ["option"], + "additionalProperties": false, + "properties": { + "option": { "$ref": "#/$defs/IdlType" } + }, + "description": "Optional value." + }, + { + "type": "object", + "required": ["vec"], + "additionalProperties": false, + "properties": { + "vec": { "$ref": "#/$defs/IdlType" } + }, + "description": "Variable-length list." + }, + { + "type": "object", + "required": ["array"], + "additionalProperties": false, + "properties": { + "array": { + "type": "array", + "items": [ + { "$ref": "#/$defs/IdlType" }, + { "$ref": "#/$defs/IdlArrayLen" } + ], + "additionalItems": false, + "minItems": 2, + "maxItems": 2 + } + }, + "description": "Fixed-length array: [type, length]." + }, + { + "type": "object", + "required": ["defined"], + "additionalProperties": false, + "properties": { + "defined": { + "type": "object", + "required": ["name"], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Name of the user-defined type from the types array." + }, + "generics": { + "type": "array", + "items": { "$ref": "#/$defs/IdlGenericArg" }, + "default": [], + "description": "Generic arguments. Omitted when empty." + } + } + } + }, + "description": "Reference to a user-defined type." + }, + { + "type": "object", + "required": ["generic"], + "additionalProperties": false, + "properties": { + "generic": { + "type": "string", + "description": "Name of the generic type parameter." + } + }, + "description": "A generic type parameter." + } + ] + }, + "IdlArrayLen": { + "description": "Array length: a bare number for fixed sizes, or an object for generic const parameters.", + "oneOf": [ + { + "type": "integer", + "minimum": 0, + "description": "Fixed numeric length." + }, + { + "type": "object", + "required": ["generic"], + "additionalProperties": false, + "properties": { + "generic": { + "type": "string", + "description": "Generic const parameter name." + } + }, + "description": "Generic const parameter length." + } + ] + }, + "IdlGenericArg": { + "description": "Generic argument when instantiating a generic type. Tagged with 'kind'.", + "oneOf": [ + { + "type": "object", + "required": ["kind", "type"], + "additionalProperties": false, + "properties": { + "kind": { "const": "type" }, + "type": { "$ref": "#/$defs/IdlType" } + }, + "description": "A type argument." + }, + { + "type": "object", + "required": ["kind", "value"], + "additionalProperties": false, + "properties": { + "kind": { "const": "const" }, + "value": { + "type": "string", + "description": "Const value as a string." + } + }, + "description": "A const argument." + } + ] + }, + "IdlTypeDefGeneric": { + "description": "Declares a generic parameter on a type definition. Tagged with 'kind'.", + "oneOf": [ + { + "type": "object", + "required": ["kind", "name"], + "additionalProperties": false, + "properties": { + "kind": { "const": "type" }, + "name": { + "type": "string", + "description": "Generic type parameter name." + } + }, + "description": "A generic type parameter." + }, + { + "type": "object", + "required": ["kind", "name", "type"], + "additionalProperties": false, + "properties": { + "kind": { "const": "const" }, + "name": { + "type": "string", + "description": "Const generic parameter name." + }, + "type": { + "type": "string", + "description": "The const generic's type (e.g. \"usize\")." + } + }, + "description": "A const generic parameter." + } + ] + }, + "IdlSerialization": { + "description": "Serialization format. Default is \"borsh\" (omitted from output).", + "oneOf": [ + { + "type": "string", + "enum": ["borsh", "bytemuck", "bytemuckunsafe"], + "description": "Built-in serialization format." + }, + { + "type": "object", + "required": ["custom"], + "additionalProperties": false, + "properties": { + "custom": { + "type": "string", + "description": "Custom serialization format name." + } + }, + "description": "A custom serialization format." + } + ] + }, + "IdlRepr": { + "description": "Memory representation hint, mirroring Rust's #[repr(...)]. Tagged with 'kind'.", + "oneOf": [ + { + "type": "object", + "required": ["kind"], + "additionalProperties": false, + "properties": { + "kind": { "const": "rust" }, + "packed": { + "type": "boolean", + "default": false, + "description": "Whether the type uses packed layout. Omitted when false." + }, + "align": { + "type": "integer", + "minimum": 1, + "description": "Explicit alignment in bytes. Omitted when absent." + } + }, + "description": "Default Rust representation." + }, + { + "type": "object", + "required": ["kind"], + "additionalProperties": false, + "properties": { + "kind": { "const": "c" }, + "packed": { + "type": "boolean", + "default": false, + "description": "Whether the type uses packed layout. Omitted when false." + }, + "align": { + "type": "integer", + "minimum": 1, + "description": "Explicit alignment in bytes. Omitted when absent." + } + }, + "description": "C-compatible representation." + }, + { + "type": "object", + "required": ["kind"], + "additionalProperties": false, + "properties": { + "kind": { "const": "transparent" } + }, + "description": "Transparent representation (single-field wrapper)." + } + ] + }, + "IdlConst": { + "type": "object", + "required": ["name", "type", "value"], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Constant name (SCREAMING_SNAKE_CASE)." + }, + "docs": { + "type": "array", + "items": { "type": "string" }, + "default": [], + "description": "Documentation strings. Omitted when empty." + }, + "type": { + "$ref": "#/$defs/IdlType", + "description": "The constant's type." + }, + "value": { + "type": "string", + "description": "The constant's value as a string representation." + } + } + }, + "IdlPda": { + "type": "object", + "required": ["seeds"], + "additionalProperties": false, + "properties": { + "seeds": { + "type": "array", + "items": { "$ref": "#/$defs/IdlSeed" }, + "description": "Ordered list of seeds." + }, + "program": { + "$ref": "#/$defs/IdlSeed", + "description": "The program to derive against (defaults to the current program). Omitted when absent." + } + } + }, + "IdlSeed": { + "description": "Tagged union for PDA seed sources. Uses 'kind' as the tag field.", + "oneOf": [ + { + "type": "object", + "required": ["kind", "value"], + "additionalProperties": false, + "properties": { + "kind": { "const": "const" }, + "value": { + "type": "array", + "items": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "description": "Raw bytes of the constant seed." + } + }, + "description": "A constant byte value." + }, + { + "type": "object", + "required": ["kind", "path"], + "additionalProperties": false, + "properties": { + "kind": { "const": "arg" }, + "path": { + "type": "string", + "description": "Dot-delimited path to the instruction argument." + } + }, + "description": "A value from an instruction argument." + }, + { + "type": "object", + "required": ["kind", "path"], + "additionalProperties": false, + "properties": { + "kind": { "const": "account" }, + "path": { + "type": "string", + "description": "Dot-delimited path to the account field." + }, + "account": { + "type": "string", + "description": "The account type name (if resolving a field from a deserialized account). Omitted when absent." + } + }, + "description": "A value from an account field." + } + ] + } + } +} diff --git a/programs/settlement/tests/idl.rs b/programs/settlement/tests/idl.rs new file mode 100644 index 0000000..2ec5aed --- /dev/null +++ b/programs/settlement/tests/idl.rs @@ -0,0 +1,364 @@ +//! IDL correctness tests for `programs/settlement/idl/cow_settlement.json`. +//! +//! This program is a native Pinocchio program with a hand-written IDL (no +//! `anchor idl build`/shank step keeps it in sync), so these tests +//! cross-check the checked-in file against the Rust source it describes +//! instead of trusting it as-is. +//! +//! The vendored schema (`idl/schema/idl-spec-v0.1.0.json`) is a snapshot of +//! ; +//! re-fetch it there if the spec version ever bumps. + +mod common; + +use std::collections::BTreeSet; + +use serde_json::Value; +use settlement_interface::{ + pda::{buffer::BUFFER_SEED, order::ORDER_SEED, SETTLEMENT_SEED}, + SettlementAccount, SettlementInstruction, +}; + +const IDL_JSON: &str = include_str!("../idl/cow_settlement.json"); +const IDL_SCHEMA_JSON: &str = include_str!("../idl/schema/idl-spec-v0.1.0.json"); +const INTERFACE_LIB_RS: &str = include_str!("../../../interface/src/lib.rs"); +const INTENT_RS: &str = include_str!("../../../interface/src/data/intent.rs"); +const ORDER_RS: &str = include_str!("../../../interface/src/data/order.rs"); + +fn idl() -> Value { + serde_json::from_str(IDL_JSON).expect("IDL must be valid JSON") +} + +fn find_item_in_idl<'a>(idl: &'a Value, type_name: &str, name: &str) -> Option<&'a Value> { + idl[type_name] + .as_array()? + .iter() + .find(|ix| ix["name"] == name) +} + +fn doc_attr_text(attr: &syn::Attribute) -> Option { + if !attr.path().is_ident("doc") { + return None; + } + let syn::Meta::NameValue(nv) = &attr.meta else { + return None; + }; + let syn::Expr::Lit(syn::ExprLit { + lit: syn::Lit::Str(s), + .. + }) = &nv.value + else { + return None; + }; + Some(s.value().trim().to_string()) +} + +fn normalize_doc(lines: &[String]) -> String { + lines + .iter() + .map(|l| l.trim()) + .collect::>() + .join(" ") + .replace('`', "") +} + +// --------------------------------------------------------------------------- +// JSON validity and formatting +// --------------------------------------------------------------------------- + +#[test] +fn idl_is_valid_json() { + let _: Value = idl(); +} + +#[test] +fn idl_is_pretty_formatted() { + let mut formatted = serde_json::to_string_pretty(&idl()).expect("IDL JSON should re-serialize"); + formatted.push('\n'); + assert_eq!( + formatted, IDL_JSON, + "IDL isn't canonically formatted; regenerate it with `serde_json::to_string_pretty` \ + plus a trailing newline" + ); +} + +#[test] +fn idl_address_matches_declared_program_id() { + let idl = idl(); + assert_eq!( + idl["address"].as_str().expect("address must be a string"), + settlement_interface::ID.to_string(), + "IDL `address` must match the program id declared via declare_id! in interface/src/lib.rs" + ); +} + +#[test] +fn idl_conforms_to_official_schema() { + let schema: Value = serde_json::from_str(IDL_SCHEMA_JSON).expect("schema should be valid JSON"); + let validator = jsonschema::validator_for(&schema).expect("schema should compile"); + let instance = idl(); + let errors: Vec = validator + .iter_errors(&instance) + .map(|e| e.to_string()) + .collect(); + assert!( + errors.is_empty(), + "IDL fails schema validation:\n{}", + errors.join("\n") + ); +} + +fn pascal_to_snake(s: &str) -> String { + let mut out = String::new(); + for (i, c) in s.chars().enumerate() { + if c.is_uppercase() { + if i != 0 { + out.push('_'); + } + out.extend(c.to_lowercase()); + } else { + out.push(c); + } + } + out +} + +fn confirm_idl_match(idl: &Value, byte: u8, element_type: &str, idl_name: &str) { + let idl_element = find_item_in_idl(&idl, element_type, &idl_name).expect(&format!( + "IDL does not contain defined settlement element {idl_name}" + )); + + // confirm the discriminator matches + let disc = idl_element["discriminator"] + .as_array() + .expect(&format!("discriminator for {idl_name} should be an array")); + + assert_eq!( + disc.len(), + 1, + "instruction discriminator {disc:?} for {idl_name} should be 1 byte" + ); + assert_eq!( + disc[0].as_u64(), + Some(byte as u64), + "instruction discriminator byte for {idl_name} doesn't match up with the code" + ); + + // confirm the docs match + /*let docs = ix["docs"] + .as_array() + .expect("docs for {idl_name} should be an array");*/ + + // TODO +} + +#[test] +fn idl_matches_instruction_discriminators() { + let idl = idl(); + for byte in 0u8..=255 { + if let Ok(ix) = SettlementInstruction::try_from(byte) { + confirm_idl_match( + &idl, + byte, + "instructions", + &pascal_to_snake(&format!("{ix:?}")), + ); + } + } +} + +#[test] +fn idl_matches_account_discriminators() { + let idl = idl(); + for byte in 0u8..=255 { + if let Ok(account) = SettlementAccount::try_from(byte) { + confirm_idl_match(&idl, byte, "accounts", &format!("{account:?}")); + } + } +} + +fn confirm_idl_types_entry(idl: &Value, rust_file_name: &str, type_name: &str) { + // load in the idl and rust type definitions + let type_in_idl = idl["types"] + .as_array() + .expect("types must be an array") + .iter() + .find(|t| t["name"] == type_name) + .expect("IDL types[] must contain {type_name}"); + + let file = syn::parse_file(rust_file_name).expect("Rust source must parse"); + let rust_struct = file + .items + .iter() + .find_map(|item| match item { + syn::Item::Struct(s) if s.ident == type_name => Some(s), + _ => None, + }) + .expect("struct {struct_name} not found in Rust source"); + + // confirm the docs match + let idl_docs: Vec = type_in_idl["docs"] + .as_array() + .expect("docs should be an array for {type_name}") + .iter() + .map(|i| i.as_str().expect("doc item should be a string").to_string()) + .collect(); + + let rust_docs: Vec = rust_struct + .attrs + .iter() + .filter_map(|attr| doc_attr_text(attr)) + .collect(); + + assert_eq!( + idl_docs, rust_docs, + "documentation between rust and IDL types should be the same for {type_name}" + ); + + // confirm fields match + let idl_fields: Vec = type_in_idl["type"]["fields"] + .as_array() + .expect("struct type {type_name} should have a fields array") + .iter() + .map(|f| { + f["name"] + .as_str() + .expect("field name must be a string") + .to_string() + }) + .collect(); + + let rust_fields: Vec = rust_struct + .fields + .iter() + .map(|f| { + f.ident + .as_ref() + .expect("{struct_name} should have named fields") + .to_string() + }) + .collect(); + + assert_eq!( + idl_fields, + rust_fields, + "OrderIntent's IDL field list/order must match the Rust struct (field order is load-bearing: it's the wire format)" + ); +} + +#[test] +fn idl_matches_rust_types() { + let idl = idl(); + + confirm_idl_types_entry(&idl, INTENT_RS, "OrderIntent"); + confirm_idl_types_entry(&idl, ORDER_RS, "OrderAccount"); +} + +#[test] +fn idl_matches_rust_errors() { + let rust_file = syn::parse_file(INTERFACE_LIB_RS).expect("interface/src/lib.rs must parse"); + let rust_errors_type = rust_file + .items + .iter() + .find_map(|item| match item { + syn::Item::Enum(e) if e.ident == "SettlementError" => Some(e), + _ => None, + }) + .expect("SettlementError enum must exist in interface/src/lib.rs"); + + let idl = idl(); + for rust_err in &rust_errors_type.variants { + let idl_err = find_item_in_idl(&idl, "errors", &rust_err.ident.to_string()) + .expect("Settlement program error {rust_err} is not defined in IDL errors[]"); + + // the idl error's "code" should match up + let rust_code = match &rust_err.discriminant { + Some(( + _, + syn::Expr::Lit(syn::ExprLit { + lit: syn::Lit::Int(i), + .. + }), + )) => i + .base10_parse::() + .expect("discriminant must be a u32 literal"), + Some(_) => panic!("unexpected non-literal discriminant on {}", rust_err.ident), + None => panic!("discriminant should be defined on {}", rust_err.ident), + }; + + let idl_code = idl_err["code"] + .as_u64() + .expect("code should be correct type"); + + assert_eq!( + idl_code, rust_code as u64, + "IDL errors[] name={} should match the code in rust", + rust_err.ident + ); + + // the idl error's "msg" should match up + let rust_doc_lines: Vec = rust_err.attrs.iter().filter_map(doc_attr_text).collect(); + let rust_msg = normalize_doc(&rust_doc_lines); + + let idl_msg = idl_err["msg"].as_str().expect("msg must be a string"); + + assert_eq!( + idl_msg, rust_msg, + "IDL errors[] name={} should match informational msg", + rust_err.ident + ); + } +} + +#[test] +fn idl_pda_seed_literals_match_pda_module() { + let known: BTreeSet<&[u8]> = [SETTLEMENT_SEED, BUFFER_SEED, ORDER_SEED] + .into_iter() + .collect(); + + fn collect_const_seeds(value: &Value, out: &mut Vec>) { + match value { + Value::Object(map) => { + if map.get("kind").and_then(Value::as_str) == Some("const") { + if let Some(Value::Array(bytes)) = map.get("value") { + let decoded: Vec = bytes + .iter() + .map(|b| b.as_u64().expect("seed byte must be a number") as u8) + .collect(); + out.push(decoded); + } + } + for v in map.values() { + collect_const_seeds(v, out); + } + } + Value::Array(arr) => arr.iter().for_each(|v| collect_const_seeds(v, out)), + _ => {} + } + } + + let idl = idl(); + let mut found = Vec::new(); + collect_const_seeds(&idl["instructions"], &mut found); + + // Every const seed the IDL does declare must be a real seed constant. Not + // every seed constant needs to show up: `order_pda`'s canonical seed + // includes `sha256(intent)`, which the IDL can't express as a static + // `pda` entry at all (documented in create_order's docs), so `ORDER_SEED` + // legitimately never appears here. + for seed in &found { + assert!( + known.contains(seed.as_slice()), + "IDL PDA const seed {:?} doesn't match any seed constant in interface::pda", + String::from_utf8_lossy(seed), + ); + } + assert!( + found.iter().any(|s| s.as_slice() == SETTLEMENT_SEED), + "expected SETTLEMENT_SEED to appear in some IDL PDA `seeds`", + ); + assert!( + found.iter().any(|s| s.as_slice() == BUFFER_SEED), + "expected BUFFER_SEED to appear in some IDL PDA `seeds`", + ); +} From adf17c59a7e3613d5a29118c41312b926162b76d Mon Sep 17 00:00:00 2001 From: Kaze <230549489+kaze-cow@users.noreply.github.com> Date: Wed, 29 Jul 2026 23:45:32 +0900 Subject: [PATCH 04/43] fix lint --- programs/settlement/tests/idl.rs | 34 ++++++++++++++++---------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/programs/settlement/tests/idl.rs b/programs/settlement/tests/idl.rs index 2ec5aed..490c63d 100644 --- a/programs/settlement/tests/idl.rs +++ b/programs/settlement/tests/idl.rs @@ -124,14 +124,13 @@ fn pascal_to_snake(s: &str) -> String { } fn confirm_idl_match(idl: &Value, byte: u8, element_type: &str, idl_name: &str) { - let idl_element = find_item_in_idl(&idl, element_type, &idl_name).expect(&format!( - "IDL does not contain defined settlement element {idl_name}" - )); + let idl_element = find_item_in_idl(idl, element_type, idl_name) + .unwrap_or_else(|| panic!("IDL does not contain defined settlement element {idl_name}")); // confirm the discriminator matches let disc = idl_element["discriminator"] .as_array() - .expect(&format!("discriminator for {idl_name} should be an array")); + .unwrap_or_else(|| panic!("discriminator for {idl_name} should be an array")); assert_eq!( disc.len(), @@ -184,7 +183,7 @@ fn confirm_idl_types_entry(idl: &Value, rust_file_name: &str, type_name: &str) { .expect("types must be an array") .iter() .find(|t| t["name"] == type_name) - .expect("IDL types[] must contain {type_name}"); + .unwrap_or_else(|| panic!("IDL types[] must contain {type_name}")); let file = syn::parse_file(rust_file_name).expect("Rust source must parse"); let rust_struct = file @@ -194,21 +193,17 @@ fn confirm_idl_types_entry(idl: &Value, rust_file_name: &str, type_name: &str) { syn::Item::Struct(s) if s.ident == type_name => Some(s), _ => None, }) - .expect("struct {struct_name} not found in Rust source"); + .unwrap_or_else(|| panic!("struct {type_name} not found in Rust source")); // confirm the docs match let idl_docs: Vec = type_in_idl["docs"] .as_array() - .expect("docs should be an array for {type_name}") + .unwrap_or_else(|| panic!("docs should be an array for {type_name}")) .iter() .map(|i| i.as_str().expect("doc item should be a string").to_string()) .collect(); - let rust_docs: Vec = rust_struct - .attrs - .iter() - .filter_map(|attr| doc_attr_text(attr)) - .collect(); + let rust_docs: Vec = rust_struct.attrs.iter().filter_map(doc_attr_text).collect(); assert_eq!( idl_docs, rust_docs, @@ -218,7 +213,7 @@ fn confirm_idl_types_entry(idl: &Value, rust_file_name: &str, type_name: &str) { // confirm fields match let idl_fields: Vec = type_in_idl["type"]["fields"] .as_array() - .expect("struct type {type_name} should have a fields array") + .unwrap_or_else(|| panic!("struct type {type_name} should have a fields array")) .iter() .map(|f| { f["name"] @@ -234,7 +229,7 @@ fn confirm_idl_types_entry(idl: &Value, rust_file_name: &str, type_name: &str) { .map(|f| { f.ident .as_ref() - .expect("{struct_name} should have named fields") + .unwrap_or_else(|| panic!("{type_name} should have named fields")) .to_string() }) .collect(); @@ -242,7 +237,7 @@ fn confirm_idl_types_entry(idl: &Value, rust_file_name: &str, type_name: &str) { assert_eq!( idl_fields, rust_fields, - "OrderIntent's IDL field list/order must match the Rust struct (field order is load-bearing: it's the wire format)" + "{type_name}'s IDL field list/order must match the Rust struct (field order is load-bearing: it's the wire format)" ); } @@ -268,8 +263,13 @@ fn idl_matches_rust_errors() { let idl = idl(); for rust_err in &rust_errors_type.variants { - let idl_err = find_item_in_idl(&idl, "errors", &rust_err.ident.to_string()) - .expect("Settlement program error {rust_err} is not defined in IDL errors[]"); + let idl_err = + find_item_in_idl(&idl, "errors", &rust_err.ident.to_string()).unwrap_or_else(|| { + panic!( + "Settlement program error {} is not defined in IDL errors[]", + rust_err.ident + ) + }); // the idl error's "code" should match up let rust_code = match &rust_err.discriminant { From eb45059c3e8ff72fdf16e89120fb1400c4f70cf5 Mon Sep 17 00:00:00 2001 From: Kaze <230549489+kaze-cow@users.noreply.github.com> Date: Wed, 12 Aug 2026 17:45:53 +0900 Subject: [PATCH 05/43] sync idl and add a couple more tests to cover everything --- programs/settlement/idl/cow_settlement.json | 80 +++++++++++++++-- programs/settlement/tests/idl.rs | 95 +++++++++++++++------ 2 files changed, 142 insertions(+), 33 deletions(-) diff --git a/programs/settlement/idl/cow_settlement.json b/programs/settlement/idl/cow_settlement.json index 3c2415a..8d85843 100644 --- a/programs/settlement/idl/cow_settlement.json +++ b/programs/settlement/idl/cow_settlement.json @@ -42,13 +42,22 @@ 109, 101, 110, - 116 + 116, + 32, + 118, + 48, + 46, + 49, + 32, + 32, + 32, + 32 ] } ] }, "docs": [ - "Canonical PDA seeded by the literal string \"settlement\"." + "Canonical PDA seeded by SETTLEMENT_SEED alone. SETTLEMENT_SEED is the ASCII prefix \"settlement v\" followed by the program's major.minor version, right-padded with spaces to a fixed 19 bytes; the fixed width prevents one version's seeds from being a prefix of another's. The const bytes below are authoritative and change on every minor version bump." ] }, { @@ -56,14 +65,22 @@ "address": "11111111111111111111111111111111" } ], - "args": [] + "args": [ + { + "name": "reclaim_authority", + "docs": [ + "Recorded verbatim in the state PDA's body as SettlementState.reclaim_authority." + ], + "type": "pubkey" + } + ] }, { "name": "create_buffer", "docs": [ "Creates one or more per-token buffer PDAs (SPL token accounts) in a single instruction.", "IDL MODELING NOTE: the real instruction accepts an unbounded number of (buffer_pda, mint) pairs as remaining accounts, one pair per buffer, with at least one pair required (CreateBuffer rejects zero buffers). Anchor's IDL grammar has no 'repeated group' construct, so this file only declares the guaranteed index-0 template (buffer_pda_0/mint_0). This instruction is solver/internal tooling only, not part of the public client surface, so buffers beyond the first are intentionally left unmodeled here: callers needing more than one buffer per transaction append the extra (buffer_pda, mint) account-meta pairs by hand after building the base instruction.", - "Each buffer_pda_i must be the canonical PDA for seeds [\"settlement\", mint_i, \"buffer\"]." + "Each buffer_pda_i must be the canonical PDA for seeds [SETTLEMENT_SEED, mint_i, \"buffer\"]." ], "discriminator": [ 4 @@ -99,7 +116,16 @@ 109, 101, 110, - 116 + 116, + 32, + 118, + 48, + 46, + 49, + 32, + 32, + 32, + 32 ] }, { @@ -136,7 +162,7 @@ "name": "create_order", "docs": [ "Allocates a per-order PDA and writes the initial OrderAccount body.", - "order_pda's canonical seeds are [\"settlement\", sha256(intent_bytes), \"order\"]. This is not expressible as a static `pda` entry because the middle seed is a hash of the entire `intent` argument, not a plain field/account reference, which is outside what the Anchor PDA-seed grammar (const / arg / account) can describe." + "order_pda's canonical seeds are [SETTLEMENT_SEED, sha256(intent_bytes), \"order\"]. This is not expressible as a static `pda` entry because the middle seed is a hash of the entire `intent` argument, not a plain field/account reference, which is outside what the Anchor PDA-seed grammar (const / arg / account) can describe." ], "discriminator": [ 2 @@ -348,10 +374,16 @@ { "name": "SettlementState", "docs": [ - "Body of the singleton settlement state PDA. Carries no fields beyond the 1-byte discriminator; its existence and address are what matter." + "Idiomatic representation of the state PDA's body." ], "type": { - "kind": "struct" + "kind": "struct", + "fields": [ + { + "name": "reclaim_authority", + "type": "pubkey" + } + ] } }, { @@ -550,11 +582,41 @@ }, { "code": 24, + "name": "LimitPriceViolated", + "msg": "BeginSettle: a settled order's executed price (amount_out/amount_in) is worse than the order's limit price (buy_amount/sell_amount)." + }, + { + "code": 25, + "name": "PullAmountOverflow", + "msg": "BeginSettle: an order's pull amounts sum to more than u64::MAX." + }, + { + "code": 26, + "name": "FillExceedsOrderAmount", + "msg": "BeginSettle: filling this order would consume more tokens than the maximum the user is willing to trade on this intent. Sell: amount_in > sell_amount; buy: amount_out > buy_amount." + }, + { + "code": 27, + "name": "OrderNotExactlyFilled", + "msg": "BeginSettle: a non-partially_fillable order isn't filled exactly to its amount (either under- or over-filled). Sell: amount_in != sell_amount; buy: total amount_out != buy_amount." + }, + { + "code": 28, + "name": "AmountWithdrawnOverflow", + "msg": "BeginSettle: the order's cumulative amount_withdrawn would exceed u64::MAX once this settlement's pulls are added." + }, + { + "code": 29, + "name": "AmountReceivedOverflow", + "msg": "BeginSettle: the order's cumulative amount_received would exceed u64::MAX once this settlement's push is added." + }, + { + "code": 30, "name": "OrderNotExpired", "msg": "ReclaimOrder was called before the order's valid_to has elapsed." }, { - "code": 25, + "code": 31, "name": "ReclaimRecipientMismatch", "msg": "ReclaimOrder's reclaim_recipient account doesn't match the created_by address recorded in the order." } diff --git a/programs/settlement/tests/idl.rs b/programs/settlement/tests/idl.rs index 490c63d..134f48c 100644 --- a/programs/settlement/tests/idl.rs +++ b/programs/settlement/tests/idl.rs @@ -13,7 +13,7 @@ mod common; use std::collections::BTreeSet; -use serde_json::Value; +use serde_json::{json, Value}; use settlement_interface::{ pda::{buffer::BUFFER_SEED, order::ORDER_SEED, SETTLEMENT_SEED}, SettlementAccount, SettlementInstruction, @@ -24,6 +24,7 @@ const IDL_SCHEMA_JSON: &str = include_str!("../idl/schema/idl-spec-v0.1.0.json") const INTERFACE_LIB_RS: &str = include_str!("../../../interface/src/lib.rs"); const INTENT_RS: &str = include_str!("../../../interface/src/data/intent.rs"); const ORDER_RS: &str = include_str!("../../../interface/src/data/order.rs"); +const STATE_RS: &str = include_str!("../../../interface/src/data/state.rs"); fn idl() -> Value { serde_json::from_str(IDL_JSON).expect("IDL must be valid JSON") @@ -176,29 +177,69 @@ fn idl_matches_account_discriminators() { } } -fn confirm_idl_types_entry(idl: &Value, rust_file_name: &str, type_name: &str) { +/// Translates a Rust field type into the IDL spec's type grammar, so field +/// types can be compared as JSON. Panics on anything the program's data types +/// don't currently use. +fn rust_type_to_idl(ty: &syn::Type, context: &str) -> Value { + match ty { + syn::Type::Path(path) => { + let ident = path + .path + .get_ident() + .unwrap_or_else(|| panic!("{context}: expected a plain type name")) + .to_string(); + match ident.as_str() { + "Pubkey" => json!("pubkey"), + "bool" | "u8" | "u16" | "u32" | "u64" | "u128" | "i8" | "i16" | "i32" | "i64" + | "i128" => json!(ident), + // Anything else is one of this crate's own types, which the IDL + // carries as its own `types[]` entry and references by name. + _ => json!({ "defined": { "name": ident } }), + } + } + syn::Type::Array(array) => { + let syn::Expr::Lit(syn::ExprLit { + lit: syn::Lit::Int(len), + .. + }) = &array.len + else { + panic!("{context}: array length must be an integer literal"); + }; + let len: u64 = len.base10_parse().expect("array length must be a u64"); + json!({ "array": [rust_type_to_idl(&array.elem, context), len] }) + } + _ => panic!("{context}: unsupported field type"), + } +} + +/// Cross-checks one IDL `types[]` entry against the Rust struct it describes. +/// +/// `idl_name` is passed separately because the two don't always agree: +/// `StateAccount` is called `SettlementState` in the IDL, matching the +/// `SettlementAccount` discriminator variant that names the account. +fn confirm_idl_types_entry(idl: &Value, rust_file_name: &str, rust_type_name: &str, idl_type_name: &str) { // load in the idl and rust type definitions let type_in_idl = idl["types"] .as_array() .expect("types must be an array") .iter() - .find(|t| t["name"] == type_name) - .unwrap_or_else(|| panic!("IDL types[] must contain {type_name}")); + .find(|t| t["name"] == idl_type_name) + .unwrap_or_else(|| panic!("IDL types[] must contain {idl_type_name}")); let file = syn::parse_file(rust_file_name).expect("Rust source must parse"); let rust_struct = file .items .iter() .find_map(|item| match item { - syn::Item::Struct(s) if s.ident == type_name => Some(s), + syn::Item::Struct(s) if s.ident == rust_type_name => Some(s), _ => None, }) - .unwrap_or_else(|| panic!("struct {type_name} not found in Rust source")); + .unwrap_or_else(|| panic!("struct {rust_type_name} not found in Rust source")); // confirm the docs match let idl_docs: Vec = type_in_idl["docs"] .as_array() - .unwrap_or_else(|| panic!("docs should be an array for {type_name}")) + .unwrap_or_else(|| panic!("docs should be an array for {rust_type_name}")) .iter() .map(|i| i.as_str().expect("doc item should be a string").to_string()) .collect(); @@ -207,37 +248,42 @@ fn confirm_idl_types_entry(idl: &Value, rust_file_name: &str, type_name: &str) { assert_eq!( idl_docs, rust_docs, - "documentation between rust and IDL types should be the same for {type_name}" + "documentation between rust and IDL types should be the same for {rust_type_name} and {idl_type_name}" ); - // confirm fields match - let idl_fields: Vec = type_in_idl["type"]["fields"] + // confirm fields match, both in name/order and in type + let idl_fields: Vec<(String, Value)> = type_in_idl["type"]["fields"] .as_array() - .unwrap_or_else(|| panic!("struct type {type_name} should have a fields array")) + .unwrap_or_else(|| panic!("struct type {idl_type_name} should have a fields array")) .iter() .map(|f| { - f["name"] - .as_str() - .expect("field name must be a string") - .to_string() + ( + f["name"] + .as_str() + .expect("field name must be a string") + .to_string(), + f["type"].clone(), + ) }) .collect(); - let rust_fields: Vec = rust_struct + let rust_fields: Vec<(String, Value)> = rust_struct .fields .iter() .map(|f| { - f.ident + let name = f + .ident .as_ref() - .unwrap_or_else(|| panic!("{type_name} should have named fields")) - .to_string() + .unwrap_or_else(|| panic!("{idl_type_name} should have named fields")) + .to_string(); + let idl_type = rust_type_to_idl(&f.ty, &format!("{idl_type_name}.{name}")); + (name, idl_type) }) .collect(); assert_eq!( - idl_fields, - rust_fields, - "{type_name}'s IDL field list/order must match the Rust struct (field order is load-bearing: it's the wire format)" + idl_fields, rust_fields, + "{idl_type_name}'s IDL fields must match the Rust struct {idl_type_name} in name, order and type" ); } @@ -245,8 +291,9 @@ fn confirm_idl_types_entry(idl: &Value, rust_file_name: &str, type_name: &str) { fn idl_matches_rust_types() { let idl = idl(); - confirm_idl_types_entry(&idl, INTENT_RS, "OrderIntent"); - confirm_idl_types_entry(&idl, ORDER_RS, "OrderAccount"); + confirm_idl_types_entry(&idl, INTENT_RS, "OrderIntent", "OrderIntent"); + confirm_idl_types_entry(&idl, ORDER_RS, "OrderAccount", "OrderAccount"); + confirm_idl_types_entry(&idl, STATE_RS, "StateAccount", "SettlementState"); } #[test] From 6c7149a2236f175d55990229bb2cd0428a688cac Mon Sep 17 00:00:00 2001 From: Kaze <230549489+kaze-cow@users.noreply.github.com> Date: Wed, 12 Aug 2026 18:16:07 +0900 Subject: [PATCH 06/43] fix createorder test fialures using newer version of litesvm nodejs lib, and settlement seed now has to be imported dynamically from the IDL because of version bumping --- .../settlement/idl/client/js/src/hooked.ts | 5 +-- .../idl/client/js/tests/createOrder.test.ts | 21 +++++++----- programs/settlement/idl/generate.mjs | 33 +++++++++++++++++++ 3 files changed, 48 insertions(+), 11 deletions(-) diff --git a/programs/settlement/idl/client/js/src/hooked.ts b/programs/settlement/idl/client/js/src/hooked.ts index b36c25c..694d188 100644 --- a/programs/settlement/idl/client/js/src/hooked.ts +++ b/programs/settlement/idl/client/js/src/hooked.ts @@ -3,7 +3,7 @@ // via the fixed "../../hooked" specifier (see generate.mjs). Never touched // by rendering, which only manages src/generated. // -// create_order's order PDA is seeded by ["settlement", sha256(borsh(intent)), "order"]. +// create_order's order PDA is seeded by [SETTLEMENT_SEED, sha256(intent_bytes), "order"]. // The middle seed is a hash of the whole `intent` argument rather than a plain // field/account reference, which the Anchor PDA-seed grammar (const / arg / account) // can't express — see cow_settlement.json's create_order docs — so it's handed off @@ -13,6 +13,7 @@ import { getProgramDerivedAddress, type Address } from "@solana/kit"; import { getOrderIntentEncoder, type OrderIntentArgs } from "./generated"; +import { SETTLEMENT_SEED } from "./generated/settlementSeed"; export async function resolveOrderPda({ programAddress, @@ -27,7 +28,7 @@ export async function resolveOrderPda({ ); const [address] = await getProgramDerivedAddress({ programAddress, - seeds: ["settlement", orderUid, "order"], + seeds: [SETTLEMENT_SEED, orderUid, "order"], }); return { value: address }; } diff --git a/programs/settlement/idl/client/js/tests/createOrder.test.ts b/programs/settlement/idl/client/js/tests/createOrder.test.ts index 8ee88ab..081768e 100644 --- a/programs/settlement/idl/client/js/tests/createOrder.test.ts +++ b/programs/settlement/idl/client/js/tests/createOrder.test.ts @@ -2,12 +2,12 @@ import { LiteSVM } from "litesvm"; import { beforeEach, describe, expect, it } from "vitest"; import { appendTransactionMessageInstruction, + assertAccountExists, createTransactionMessage, generateKeyPairSigner, lamports, pipe, setTransactionMessageFeePayerSigner, - setTransactionMessageLifetimeUsingBlockhash, signTransactionMessageWithSigners, } from "@solana/kit"; import { @@ -40,28 +40,31 @@ describe("createOrder", () => { const tx = await pipe( createTransactionMessage({ version: 0 }), (t) => setTransactionMessageFeePayerSigner(owner, t), - (t) => - setTransactionMessageLifetimeUsingBlockhash( - { blockhash: svm.latestBlockhash(), lastValidBlockHeight: 999_999_999n }, - t, - ), + (t) => svm.setTransactionMessageLifetimeUsingLatestBlockhash(t), (t) => appendTransactionMessageInstruction(instruction, t), signTransactionMessageWithSigners, ); + // litesvm returns a native class, not a POJO: `err`/`meta` are methods, so + // `JSON.stringify(result.err)` would print `undefined` and hide the failure. const result = svm.sendTransaction(tx); if ("err" in result) { - throw new Error(`createOrder failed: ${JSON.stringify(result.err)}`); + throw new Error( + `createOrder failed: ${result.toString()}\n${result.meta().prettyLogs()}`, + ); } const { value: orderPda } = await resolveOrderPda({ programAddress: COW_SETTLEMENT_PROGRAM_ADDRESS, args: { intent }, }); + // `getAccount` returns a `MaybeEncodedAccount`, never null: a missing + // account comes back as `{ exists: false }`, so it needs an explicit check. const account = svm.getAccount(orderPda); - expect(account).not.toBeNull(); + expect(account.exists).toBe(true); + assertAccountExists(account); - const decoded = getOrderAccountDecoder().decode(account!.data); + const decoded = getOrderAccountDecoder().decode(account.data); expect(decoded.cancelled).toBe(false); expect(decoded.amountWithdrawn).toBe(0n); expect(decoded.amountReceived).toBe(0n); diff --git a/programs/settlement/idl/generate.mjs b/programs/settlement/idl/generate.mjs index 0cf3bb0..21a0733 100644 --- a/programs/settlement/idl/generate.mjs +++ b/programs/settlement/idl/generate.mjs @@ -1,3 +1,4 @@ +import { writeFileSync, mkdirSync } from "node:fs"; import { createFromRoot, resolverValueNode, @@ -32,3 +33,35 @@ codama.accept( asyncResolvers: ["resolveOrderPda"], }), ); + +// codama inlines each PDA's const seeds into the function that derives it and +// exports no constant for them, so resolveOrderPda — which builds the order PDA +// seeds by hand — has nothing to import. Emit SETTLEMENT_SEED here, read off the +// state PDA's sole const seed, so the version-dependent bytes still have exactly +// one source (the IDL) and follow it across version bumps. Written after the +// render because renderVisitor wipes its output directory first. +const settlementSeed = IDL.instructions + .find((instruction) => instruction.name === "initialize") + .accounts.find((account) => account.name === "state_pda").pda.seeds[0].value; + +mkdirSync("./client/js/src/generated", { recursive: true }); + +writeFileSync( + "./client/js/src/generated/settlementSeed.ts", + `/** + * This code was AUTOGENERATED by generate.mjs (not by Codama itself, which + * inlines PDA seeds into its derivation functions instead of exporting them). + * Please DO NOT EDIT THIS FILE, edit generate.mjs and rerun it instead. + */ + +/** + * Prefix seed shared by every PDA this program derives: the ASCII "settlement v" + * followed by the program's major.minor version, right-padded with spaces to a + * fixed 19 bytes. The fixed width keeps one version's seeds from being a prefix + * of another's. These bytes change on every minor version bump. + */ +export const SETTLEMENT_SEED: Uint8Array = new Uint8Array([ + ${settlementSeed.join(", ")}, +]); +`, +); From 541bcee3dfc6f629b03dbdeadf913d85b7cd11b3 Mon Sep 17 00:00:00 2001 From: Kaze <230549489+kaze-cow@users.noreply.github.com> Date: Thu, 20 Aug 2026 16:47:01 +0900 Subject: [PATCH 07/43] Update programs/settlement/tests/idl.rs Co-authored-by: Federico Giacon <58218759+fedgiac@users.noreply.github.com> --- programs/settlement/tests/idl.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/programs/settlement/tests/idl.rs b/programs/settlement/tests/idl.rs index 134f48c..0fef6c2 100644 --- a/programs/settlement/tests/idl.rs +++ b/programs/settlement/tests/idl.rs @@ -55,12 +55,7 @@ fn doc_attr_text(attr: &syn::Attribute) -> Option { } fn normalize_doc(lines: &[String]) -> String { - lines - .iter() - .map(|l| l.trim()) - .collect::>() - .join(" ") - .replace('`', "") + lines.join(" ").replace('`', "") } // --------------------------------------------------------------------------- From 4d04660d95ff61054f4763c707d0734720bf9540 Mon Sep 17 00:00:00 2001 From: Kaze <230549489+kaze-cow@users.noreply.github.com> Date: Thu, 20 Aug 2026 16:47:41 +0900 Subject: [PATCH 08/43] Update programs/settlement/tests/idl.rs Co-authored-by: Federico Giacon <58218759+fedgiac@users.noreply.github.com> --- programs/settlement/tests/idl.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/programs/settlement/tests/idl.rs b/programs/settlement/tests/idl.rs index 0fef6c2..bea1984 100644 --- a/programs/settlement/tests/idl.rs +++ b/programs/settlement/tests/idl.rs @@ -51,7 +51,10 @@ fn doc_attr_text(attr: &syn::Attribute) -> Option { else { return None; }; - Some(s.value().trim().to_string()) + // Doc comments start with spaces. We want to remove that, + // but we want to keep extra alignment spacing if present. + let doc = s.value(); + Some(doc.strip_prefix(' ').unwrap_or(&doc).to_string()) } fn normalize_doc(lines: &[String]) -> String { From bae432644296822afdce5325c00062214bbdda6d Mon Sep 17 00:00:00 2001 From: Kaze <230549489+kaze-cow@users.noreply.github.com> Date: Thu, 20 Aug 2026 22:29:00 +0900 Subject: [PATCH 09/43] various fixes from feedback * add comments for settlement instruction and validate match * simplify superfluous comments in the IDL in general * switch to using `LazyLock` and update call sites --- interface/src/lib.rs | 17 ++ programs/settlement/idl/cow_settlement.json | 17 +- .../idl/schema/idl-spec-v0.1.0.json | 2 +- programs/settlement/tests/idl.rs | 152 +++++++++++++----- 4 files changed, 135 insertions(+), 53 deletions(-) diff --git a/interface/src/lib.rs b/interface/src/lib.rs index 03dabac..c88a773 100644 --- a/interface/src/lib.rs +++ b/interface/src/lib.rs @@ -17,11 +17,28 @@ pub mod pda; constructor = SettlementInstruction::unknown_discriminator, ))] pub enum SettlementInstruction { + /// Pulls funds for a batch of orders. Must be paired in the same + /// transaction with a `FinalizeSettle` at `finalize_ix_index`. BeginSettle = 0, + /// Validates that a `BeginSettle` at `begin_ix_index` exists and points + /// back at this instruction. Must not be called via CPI. FinalizeSettle = 1, + /// Allocates a per-order PDA and writes the initial `OrderAccount` body. CreateOrder = 2, + /// Creates the singleton settlement state PDA. Succeeds only once. Initialize = 3, + /// Creates one or more per-token buffer PDAs (SPL token accounts) in a + /// single instruction. + /// + /// Each buffer_pda_i must be the canonical PDA for seeds + /// [SETTLEMENT_SEED, mint_i, "buffer"]. CreateBuffer = 4, + /// Closes an expired order PDA and returns its rent lamports to the + /// created_by account recorded in the order body. The instruction may only + /// be executed after the order's valid_to timestamp has elapsed. + /// + /// No signature requirement: anyone may reclaim an expired order on behalf + /// of its reclaim_recipient. ReclaimOrder = 5, } diff --git a/programs/settlement/idl/cow_settlement.json b/programs/settlement/idl/cow_settlement.json index 8d85843..9d3c7a3 100644 --- a/programs/settlement/idl/cow_settlement.json +++ b/programs/settlement/idl/cow_settlement.json @@ -4,14 +4,14 @@ "name": "cow_settlement", "version": "0.1.0", "spec": "0.1.0", - "description": "CoW Protocol settlement program. HAND-WRITTEN IDL: this program is a native/Pinocchio program, not built with the Anchor framework, so this file was authored manually to describe its wire format as closely as the Anchor IDL grammar allows. See the per-instruction/type docs for spots where the on-chain format cannot be fully expressed (non-standard 1-byte instruction discriminators, and BeginSettle's dynamically-shaped tail)." + "description": "CoW Protocol settlement program. IDL may not be able to generate typical of Anchor programs, so please be careful to read the documentation on the function you are using.", + "repository": "https://github.com/cowprotocol/solana-programs" }, "instructions": [ { "name": "initialize", "docs": [ - "Creates the singleton settlement state PDA. Succeeds only once.", - "Non-standard discriminator: this program uses a single instruction-selector byte (see SettlementInstruction in the Rust source), not Anchor's usual 8-byte sighash. The `discriminator` below reflects the real on-chain bytes." + "Creates the singleton settlement state PDA. Succeeds only once." ], "discriminator": [ 3 @@ -79,7 +79,7 @@ "name": "create_buffer", "docs": [ "Creates one or more per-token buffer PDAs (SPL token accounts) in a single instruction.", - "IDL MODELING NOTE: the real instruction accepts an unbounded number of (buffer_pda, mint) pairs as remaining accounts, one pair per buffer, with at least one pair required (CreateBuffer rejects zero buffers). Anchor's IDL grammar has no 'repeated group' construct, so this file only declares the guaranteed index-0 template (buffer_pda_0/mint_0). This instruction is solver/internal tooling only, not part of the public client surface, so buffers beyond the first are intentionally left unmodeled here: callers needing more than one buffer per transaction append the extra (buffer_pda, mint) account-meta pairs by hand after building the base instruction.", + "IDL LIMITATION: the real instruction accepts an unbounded number of (buffer_pda, mint) pairs as remaining accounts, one pair per buffer, with at least one pair required (CreateBuffer rejects zero buffers). IDL grammar has no 'repeated group' construct, so this file only declares the guaranteed index-0 template (buffer_pda_0/mint_0).", "Each buffer_pda_i must be the canonical PDA for seeds [SETTLEMENT_SEED, mint_i, \"buffer\"]." ], "discriminator": [ @@ -162,7 +162,7 @@ "name": "create_order", "docs": [ "Allocates a per-order PDA and writes the initial OrderAccount body.", - "order_pda's canonical seeds are [SETTLEMENT_SEED, sha256(intent_bytes), \"order\"]. This is not expressible as a static `pda` entry because the middle seed is a hash of the entire `intent` argument, not a plain field/account reference, which is outside what the Anchor PDA-seed grammar (const / arg / account) can describe." + "order_pda's canonical seeds are [SETTLEMENT_SEED, sha256(intent_bytes), \"order\"]. This is not expressible as a static `pda` entry because the middle seed is a hash of the entire `intent` argument, not a plain field/account reference, which is outside what the PDA-seed grammar can describe." ], "discriminator": [ 2 @@ -210,8 +210,7 @@ "name": "begin_settle", "docs": [ "Pulls funds for a batch of orders. Must be paired in the same transaction with a FinalizeSettle at `finalize_ix_index`.", - "IDL LIMITATION: only the fixed-size prefix (finalize_ix_index, auction_id) is represented as typed arguments. After it, the real wire format is `[order_count: u8][bump; order_count][transfer_count; order_count][amount: u64 LE; sum(transfer_count)]` — a hand-packed layout with no Borsh length prefixes and a trailing array whose length depends on the sum of an earlier array. This has no representation in the Anchor/Borsh/IDL type grammar (no vec/array type can express 'shared count governs several sibling arrays' or 'length = sum of another field'), so it is intentionally left out of `args` rather than mislabeled as `bytes` (which would imply a Borsh Vec length prefix that isn't actually present and would make a generic decoder misparse it). Anchor/Solscan-style tooling will only decode the discriminator, finalize_ix_index, and auction_id for this instruction; the remainder needs bespoke client logic.", - "Per-order accounts follow the 3 shared accounts below as a repeated remaining-accounts group: [order_pda (readonly), sell_token_account (writable), destination (writable) x transfer_count], sorted by ascending order_pda address." + "IDL LIMITATION: only the fixed-size prefix (finalize_ix_index, auction_id) is represented as typed arguments. After it, the real wire format is `[order_count: u8][bump; order_count][transfer_count; order_count][amount: u64 LE; sum(transfer_count)]`. Please check the rust documentation for more information." ], "discriminator": [ 0 @@ -252,9 +251,7 @@ { "name": "finalize_settle", "docs": [ - "Validates that a BeginSettle at `begin_ix_index` exists and points back at this instruction. Must not be called via CPI.", - "Non-standard discriminator, see the note on `initialize`.", - "Per-push accounts follow the 3 shared accounts below as a repeated remaining-accounts group: [source_buffer (writable), destination (writable)] x number of pushes." + "Validates that a BeginSettle at `begin_ix_index` exists and points back at this instruction. Must not be called via CPI." ], "discriminator": [ 1 diff --git a/programs/settlement/idl/schema/idl-spec-v0.1.0.json b/programs/settlement/idl/schema/idl-spec-v0.1.0.json index e2564ff..0eec2df 100644 --- a/programs/settlement/idl/schema/idl-spec-v0.1.0.json +++ b/programs/settlement/idl/schema/idl-spec-v0.1.0.json @@ -1,6 +1,6 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://github.com/solana-idl/idl-spec/schema/v0.1.0.json", + "$id": "https://github.com/solana-foundation/idl-spec/schema/v0.1.0.json", "title": "Solana IDL v0.1.0", "description": "JSON Schema for Solana program Interface Description Language (IDL) files, spec version 0.1.0.", "type": "object", diff --git a/programs/settlement/tests/idl.rs b/programs/settlement/tests/idl.rs index 134f48c..414a104 100644 --- a/programs/settlement/tests/idl.rs +++ b/programs/settlement/tests/idl.rs @@ -11,7 +11,7 @@ mod common; -use std::collections::BTreeSet; +use std::{collections::BTreeSet, sync::LazyLock}; use serde_json::{json, Value}; use settlement_interface::{ @@ -26,12 +26,11 @@ const INTENT_RS: &str = include_str!("../../../interface/src/data/intent.rs"); const ORDER_RS: &str = include_str!("../../../interface/src/data/order.rs"); const STATE_RS: &str = include_str!("../../../interface/src/data/state.rs"); -fn idl() -> Value { - serde_json::from_str(IDL_JSON).expect("IDL must be valid JSON") -} +static IDL: LazyLock = + LazyLock::new(|| serde_json::from_str(IDL_JSON).expect("IDL must be valid JSON")); -fn find_item_in_idl<'a>(idl: &'a Value, type_name: &str, name: &str) -> Option<&'a Value> { - idl[type_name] +fn find_item_in_idl<'a>(type_name: &str, name: &str) -> Option<&'a Value> { + IDL[type_name] .as_array()? .iter() .find(|ix| ix["name"] == name) @@ -69,12 +68,12 @@ fn normalize_doc(lines: &[String]) -> String { #[test] fn idl_is_valid_json() { - let _: Value = idl(); + let _ = &*IDL; } #[test] fn idl_is_pretty_formatted() { - let mut formatted = serde_json::to_string_pretty(&idl()).expect("IDL JSON should re-serialize"); + let mut formatted = serde_json::to_string_pretty(&*IDL).expect("IDL JSON should re-serialize"); formatted.push('\n'); assert_eq!( formatted, IDL_JSON, @@ -85,9 +84,8 @@ fn idl_is_pretty_formatted() { #[test] fn idl_address_matches_declared_program_id() { - let idl = idl(); assert_eq!( - idl["address"].as_str().expect("address must be a string"), + IDL["address"].as_str().expect("address must be a string"), settlement_interface::ID.to_string(), "IDL `address` must match the program id declared via declare_id! in interface/src/lib.rs" ); @@ -97,11 +95,7 @@ fn idl_address_matches_declared_program_id() { fn idl_conforms_to_official_schema() { let schema: Value = serde_json::from_str(IDL_SCHEMA_JSON).expect("schema should be valid JSON"); let validator = jsonschema::validator_for(&schema).expect("schema should compile"); - let instance = idl(); - let errors: Vec = validator - .iter_errors(&instance) - .map(|e| e.to_string()) - .collect(); + let errors: Vec = validator.iter_errors(&IDL).map(|e| e.to_string()).collect(); assert!( errors.is_empty(), "IDL fails schema validation:\n{}", @@ -124,8 +118,8 @@ fn pascal_to_snake(s: &str) -> String { out } -fn confirm_idl_match(idl: &Value, byte: u8, element_type: &str, idl_name: &str) { - let idl_element = find_item_in_idl(idl, element_type, idl_name) +fn confirm_idl_match(byte: u8, element_type: &str, idl_name: &str) { + let idl_element = find_item_in_idl(element_type, idl_name) .unwrap_or_else(|| panic!("IDL does not contain defined settlement element {idl_name}")); // confirm the discriminator matches @@ -144,35 +138,113 @@ fn confirm_idl_match(idl: &Value, byte: u8, element_type: &str, idl_name: &str) "instruction discriminator byte for {idl_name} doesn't match up with the code" ); - // confirm the docs match - /*let docs = ix["docs"] - .as_array() - .expect("docs for {idl_name} should be an array");*/ + // confirm the docs match: everything the Rust enum variant documents must + // show up, in order, in the IDL element's docs. The IDL is allowed to say + // more than the Rust source does; it carries notes about what its own + // grammar can't express (`begin_settle`'s dynamically-shaped tail, for + // one), which have no business being in the program's own docs. + let idl_docs: Vec = idl_element + .get("docs") + .map(|docs| { + docs.as_array() + .unwrap_or_else(|| panic!("docs for {idl_name} should be an array")) + .iter() + .map(|doc| { + let doc = doc + .as_str() + .unwrap_or_else(|| panic!("doc entry for {idl_name} should be a string")) + .to_string(); + normalize_doc(&[doc]) + }) + .collect() + }) + .unwrap_or_default(); + + let rust_docs = discriminator_variant_docs(element_type, byte); + + let mut unmatched_idl_docs = idl_docs.iter(); + for rust_doc in &rust_docs { + assert!( + unmatched_idl_docs.any(|idl_doc| idl_doc == rust_doc), + "IDL docs for {idl_name} don't document what the Rust source does; missing (or \ + out of order) paragraph:\n{rust_doc}\nIDL docs are:\n{idl_docs:#?}" + ); + } +} + +/// Doc paragraphs of the `element_type` discriminator enum variant with +/// discriminant `byte`, one string per paragraph (blank doc lines separate +/// paragraphs), normalized the way IDL doc strings are so they can be compared. +fn discriminator_variant_docs(element_type: &str, byte: u8) -> Vec { + let enum_name = match element_type { + "instructions" => "SettlementInstruction", + "accounts" => "SettlementAccount", + other => panic!("no discriminator enum backs IDL {other}[]"), + }; + + let rust_file = syn::parse_file(INTERFACE_LIB_RS).expect("interface/src/lib.rs must parse"); + let rust_enum = rust_file + .items + .iter() + .find_map(|item| match item { + syn::Item::Enum(e) if e.ident == enum_name => Some(e), + _ => None, + }) + .unwrap_or_else(|| panic!("{enum_name} enum must exist in interface/src/lib.rs")); + + let variant = rust_enum + .variants + .iter() + .find(|variant| match &variant.discriminant { + Some(( + _, + syn::Expr::Lit(syn::ExprLit { + lit: syn::Lit::Int(i), + .. + }), + )) => i.base10_parse::().ok() == Some(byte), + _ => panic!("every {enum_name} variant must have a u8 literal discriminant"), + }) + .unwrap_or_else(|| panic!("{enum_name} must have a variant with discriminant {byte}")); - // TODO + doc_paragraphs(&variant.attrs) +} + +/// Splits an item's doc comment into paragraphs on blank doc lines, each +/// normalized into the single line the IDL carries it as. +fn doc_paragraphs(attrs: &[syn::Attribute]) -> Vec { + let mut paragraphs = Vec::new(); + let mut paragraph: Vec = Vec::new(); + for line in attrs.iter().filter_map(doc_attr_text) { + if line.is_empty() { + if !paragraph.is_empty() { + paragraphs.push(normalize_doc(¶graph)); + paragraph.clear(); + } + } else { + paragraph.push(line); + } + } + if !paragraph.is_empty() { + paragraphs.push(normalize_doc(¶graph)); + } + paragraphs } #[test] fn idl_matches_instruction_discriminators() { - let idl = idl(); for byte in 0u8..=255 { if let Ok(ix) = SettlementInstruction::try_from(byte) { - confirm_idl_match( - &idl, - byte, - "instructions", - &pascal_to_snake(&format!("{ix:?}")), - ); + confirm_idl_match(byte, "instructions", &pascal_to_snake(&format!("{ix:?}"))); } } } #[test] fn idl_matches_account_discriminators() { - let idl = idl(); for byte in 0u8..=255 { if let Ok(account) = SettlementAccount::try_from(byte) { - confirm_idl_match(&idl, byte, "accounts", &format!("{account:?}")); + confirm_idl_match(byte, "accounts", &format!("{account:?}")); } } } @@ -217,9 +289,9 @@ fn rust_type_to_idl(ty: &syn::Type, context: &str) -> Value { /// `idl_name` is passed separately because the two don't always agree: /// `StateAccount` is called `SettlementState` in the IDL, matching the /// `SettlementAccount` discriminator variant that names the account. -fn confirm_idl_types_entry(idl: &Value, rust_file_name: &str, rust_type_name: &str, idl_type_name: &str) { +fn confirm_idl_types_entry(rust_file_name: &str, rust_type_name: &str, idl_type_name: &str) { // load in the idl and rust type definitions - let type_in_idl = idl["types"] + let type_in_idl = IDL["types"] .as_array() .expect("types must be an array") .iter() @@ -289,11 +361,9 @@ fn confirm_idl_types_entry(idl: &Value, rust_file_name: &str, rust_type_name: &s #[test] fn idl_matches_rust_types() { - let idl = idl(); - - confirm_idl_types_entry(&idl, INTENT_RS, "OrderIntent", "OrderIntent"); - confirm_idl_types_entry(&idl, ORDER_RS, "OrderAccount", "OrderAccount"); - confirm_idl_types_entry(&idl, STATE_RS, "StateAccount", "SettlementState"); + confirm_idl_types_entry(INTENT_RS, "OrderIntent", "OrderIntent"); + confirm_idl_types_entry(ORDER_RS, "OrderAccount", "OrderAccount"); + confirm_idl_types_entry(STATE_RS, "StateAccount", "SettlementState"); } #[test] @@ -308,10 +378,9 @@ fn idl_matches_rust_errors() { }) .expect("SettlementError enum must exist in interface/src/lib.rs"); - let idl = idl(); for rust_err in &rust_errors_type.variants { let idl_err = - find_item_in_idl(&idl, "errors", &rust_err.ident.to_string()).unwrap_or_else(|| { + find_item_in_idl("errors", &rust_err.ident.to_string()).unwrap_or_else(|| { panic!( "Settlement program error {} is not defined in IDL errors[]", rust_err.ident @@ -384,9 +453,8 @@ fn idl_pda_seed_literals_match_pda_module() { } } - let idl = idl(); let mut found = Vec::new(); - collect_const_seeds(&idl["instructions"], &mut found); + collect_const_seeds(&IDL["instructions"], &mut found); // Every const seed the IDL does declare must be a real seed constant. Not // every seed constant needs to show up: `order_pda`'s canonical seed From b5b00906087cd72ff09d373065bedeb13cbef0e4 Mon Sep 17 00:00:00 2001 From: Kaze <230549489+kaze-cow@users.noreply.github.com> Date: Thu, 20 Aug 2026 23:35:31 +0900 Subject: [PATCH 10/43] refactor idl tests into a folder with relevant code isolated --- programs/settlement/tests/idl.rs | 477 -------------------- programs/settlement/tests/idl/main.rs | 231 ++++++++++ programs/settlement/tests/idl/parse_json.rs | 113 +++++ programs/settlement/tests/idl/parse_rust.rs | 221 +++++++++ 4 files changed, 565 insertions(+), 477 deletions(-) delete mode 100644 programs/settlement/tests/idl.rs create mode 100644 programs/settlement/tests/idl/main.rs create mode 100644 programs/settlement/tests/idl/parse_json.rs create mode 100644 programs/settlement/tests/idl/parse_rust.rs diff --git a/programs/settlement/tests/idl.rs b/programs/settlement/tests/idl.rs deleted file mode 100644 index a09f98e..0000000 --- a/programs/settlement/tests/idl.rs +++ /dev/null @@ -1,477 +0,0 @@ -//! IDL correctness tests for `programs/settlement/idl/cow_settlement.json`. -//! -//! This program is a native Pinocchio program with a hand-written IDL (no -//! `anchor idl build`/shank step keeps it in sync), so these tests -//! cross-check the checked-in file against the Rust source it describes -//! instead of trusting it as-is. -//! -//! The vendored schema (`idl/schema/idl-spec-v0.1.0.json`) is a snapshot of -//! ; -//! re-fetch it there if the spec version ever bumps. - -mod common; - -use std::{collections::BTreeSet, sync::LazyLock}; - -use serde_json::{json, Value}; -use settlement_interface::{ - pda::{buffer::BUFFER_SEED, order::ORDER_SEED, SETTLEMENT_SEED}, - SettlementAccount, SettlementInstruction, -}; - -const IDL_JSON: &str = include_str!("../idl/cow_settlement.json"); -const IDL_SCHEMA_JSON: &str = include_str!("../idl/schema/idl-spec-v0.1.0.json"); -const INTERFACE_LIB_RS: &str = include_str!("../../../interface/src/lib.rs"); -const INTENT_RS: &str = include_str!("../../../interface/src/data/intent.rs"); -const ORDER_RS: &str = include_str!("../../../interface/src/data/order.rs"); -const STATE_RS: &str = include_str!("../../../interface/src/data/state.rs"); - -static IDL: LazyLock = - LazyLock::new(|| serde_json::from_str(IDL_JSON).expect("IDL must be valid JSON")); - -fn find_item_in_idl<'a>(type_name: &str, name: &str) -> Option<&'a Value> { - IDL[type_name] - .as_array()? - .iter() - .find(|ix| ix["name"] == name) -} - -fn doc_attr_text(attr: &syn::Attribute) -> Option { - if !attr.path().is_ident("doc") { - return None; - } - let syn::Meta::NameValue(nv) = &attr.meta else { - return None; - }; - let syn::Expr::Lit(syn::ExprLit { - lit: syn::Lit::Str(s), - .. - }) = &nv.value - else { - return None; - }; - // Doc comments start with spaces. We want to remove that, - // but we want to keep extra alignment spacing if present. - let doc = s.value(); - Some(doc.strip_prefix(' ').unwrap_or(&doc).to_string()) -} - -fn normalize_doc(lines: &[String]) -> String { - lines.join(" ").replace('`', "") -} - -// --------------------------------------------------------------------------- -// JSON validity and formatting -// --------------------------------------------------------------------------- - -#[test] -fn idl_is_valid_json() { - let _ = &*IDL; -} - -#[test] -fn idl_is_pretty_formatted() { - let mut formatted = serde_json::to_string_pretty(&*IDL).expect("IDL JSON should re-serialize"); - formatted.push('\n'); - assert_eq!( - formatted, IDL_JSON, - "IDL isn't canonically formatted; regenerate it with `serde_json::to_string_pretty` \ - plus a trailing newline" - ); -} - -#[test] -fn idl_address_matches_declared_program_id() { - assert_eq!( - IDL["address"].as_str().expect("address must be a string"), - settlement_interface::ID.to_string(), - "IDL `address` must match the program id declared via declare_id! in interface/src/lib.rs" - ); -} - -#[test] -fn idl_conforms_to_official_schema() { - let schema: Value = serde_json::from_str(IDL_SCHEMA_JSON).expect("schema should be valid JSON"); - let validator = jsonschema::validator_for(&schema).expect("schema should compile"); - let errors: Vec = validator.iter_errors(&IDL).map(|e| e.to_string()).collect(); - assert!( - errors.is_empty(), - "IDL fails schema validation:\n{}", - errors.join("\n") - ); -} - -fn pascal_to_snake(s: &str) -> String { - let mut out = String::new(); - for (i, c) in s.chars().enumerate() { - if c.is_uppercase() { - if i != 0 { - out.push('_'); - } - out.extend(c.to_lowercase()); - } else { - out.push(c); - } - } - out -} - -fn confirm_idl_match(byte: u8, element_type: &str, idl_name: &str) { - let idl_element = find_item_in_idl(element_type, idl_name) - .unwrap_or_else(|| panic!("IDL does not contain defined settlement element {idl_name}")); - - // confirm the discriminator matches - let disc = idl_element["discriminator"] - .as_array() - .unwrap_or_else(|| panic!("discriminator for {idl_name} should be an array")); - - assert_eq!( - disc.len(), - 1, - "instruction discriminator {disc:?} for {idl_name} should be 1 byte" - ); - assert_eq!( - disc[0].as_u64(), - Some(byte as u64), - "instruction discriminator byte for {idl_name} doesn't match up with the code" - ); - - // confirm the docs match: everything the Rust enum variant documents must - // show up, in order, in the IDL element's docs. The IDL is allowed to say - // more than the Rust source does; it carries notes about what its own - // grammar can't express (`begin_settle`'s dynamically-shaped tail, for - // one), which have no business being in the program's own docs. - let idl_docs: Vec = idl_element - .get("docs") - .map(|docs| { - docs.as_array() - .unwrap_or_else(|| panic!("docs for {idl_name} should be an array")) - .iter() - .map(|doc| { - let doc = doc - .as_str() - .unwrap_or_else(|| panic!("doc entry for {idl_name} should be a string")) - .to_string(); - normalize_doc(&[doc]) - }) - .collect() - }) - .unwrap_or_default(); - - let rust_docs = discriminator_variant_docs(element_type, byte); - - let mut unmatched_idl_docs = idl_docs.iter(); - for rust_doc in &rust_docs { - assert!( - unmatched_idl_docs.any(|idl_doc| idl_doc == rust_doc), - "IDL docs for {idl_name} don't document what the Rust source does; missing (or \ - out of order) paragraph:\n{rust_doc}\nIDL docs are:\n{idl_docs:#?}" - ); - } -} - -/// Doc paragraphs of the `element_type` discriminator enum variant with -/// discriminant `byte`, one string per paragraph (blank doc lines separate -/// paragraphs), normalized the way IDL doc strings are so they can be compared. -fn discriminator_variant_docs(element_type: &str, byte: u8) -> Vec { - let enum_name = match element_type { - "instructions" => "SettlementInstruction", - "accounts" => "SettlementAccount", - other => panic!("no discriminator enum backs IDL {other}[]"), - }; - - let rust_file = syn::parse_file(INTERFACE_LIB_RS).expect("interface/src/lib.rs must parse"); - let rust_enum = rust_file - .items - .iter() - .find_map(|item| match item { - syn::Item::Enum(e) if e.ident == enum_name => Some(e), - _ => None, - }) - .unwrap_or_else(|| panic!("{enum_name} enum must exist in interface/src/lib.rs")); - - let variant = rust_enum - .variants - .iter() - .find(|variant| match &variant.discriminant { - Some(( - _, - syn::Expr::Lit(syn::ExprLit { - lit: syn::Lit::Int(i), - .. - }), - )) => i.base10_parse::().ok() == Some(byte), - _ => panic!("every {enum_name} variant must have a u8 literal discriminant"), - }) - .unwrap_or_else(|| panic!("{enum_name} must have a variant with discriminant {byte}")); - - doc_paragraphs(&variant.attrs) -} - -/// Splits an item's doc comment into paragraphs on blank doc lines, each -/// normalized into the single line the IDL carries it as. -fn doc_paragraphs(attrs: &[syn::Attribute]) -> Vec { - let mut paragraphs = Vec::new(); - let mut paragraph: Vec = Vec::new(); - for line in attrs.iter().filter_map(doc_attr_text) { - if line.is_empty() { - if !paragraph.is_empty() { - paragraphs.push(normalize_doc(¶graph)); - paragraph.clear(); - } - } else { - paragraph.push(line); - } - } - if !paragraph.is_empty() { - paragraphs.push(normalize_doc(¶graph)); - } - paragraphs -} - -#[test] -fn idl_matches_instruction_discriminators() { - for byte in 0u8..=255 { - if let Ok(ix) = SettlementInstruction::try_from(byte) { - confirm_idl_match(byte, "instructions", &pascal_to_snake(&format!("{ix:?}"))); - } - } -} - -#[test] -fn idl_matches_account_discriminators() { - for byte in 0u8..=255 { - if let Ok(account) = SettlementAccount::try_from(byte) { - confirm_idl_match(byte, "accounts", &format!("{account:?}")); - } - } -} - -/// Translates a Rust field type into the IDL spec's type grammar, so field -/// types can be compared as JSON. Panics on anything the program's data types -/// don't currently use. -fn rust_type_to_idl(ty: &syn::Type, context: &str) -> Value { - match ty { - syn::Type::Path(path) => { - let ident = path - .path - .get_ident() - .unwrap_or_else(|| panic!("{context}: expected a plain type name")) - .to_string(); - match ident.as_str() { - "Pubkey" => json!("pubkey"), - "bool" | "u8" | "u16" | "u32" | "u64" | "u128" | "i8" | "i16" | "i32" | "i64" - | "i128" => json!(ident), - // Anything else is one of this crate's own types, which the IDL - // carries as its own `types[]` entry and references by name. - _ => json!({ "defined": { "name": ident } }), - } - } - syn::Type::Array(array) => { - let syn::Expr::Lit(syn::ExprLit { - lit: syn::Lit::Int(len), - .. - }) = &array.len - else { - panic!("{context}: array length must be an integer literal"); - }; - let len: u64 = len.base10_parse().expect("array length must be a u64"); - json!({ "array": [rust_type_to_idl(&array.elem, context), len] }) - } - _ => panic!("{context}: unsupported field type"), - } -} - -/// Cross-checks one IDL `types[]` entry against the Rust struct it describes. -/// -/// `idl_name` is passed separately because the two don't always agree: -/// `StateAccount` is called `SettlementState` in the IDL, matching the -/// `SettlementAccount` discriminator variant that names the account. -fn confirm_idl_types_entry(rust_file_name: &str, rust_type_name: &str, idl_type_name: &str) { - // load in the idl and rust type definitions - let type_in_idl = IDL["types"] - .as_array() - .expect("types must be an array") - .iter() - .find(|t| t["name"] == idl_type_name) - .unwrap_or_else(|| panic!("IDL types[] must contain {idl_type_name}")); - - let file = syn::parse_file(rust_file_name).expect("Rust source must parse"); - let rust_struct = file - .items - .iter() - .find_map(|item| match item { - syn::Item::Struct(s) if s.ident == rust_type_name => Some(s), - _ => None, - }) - .unwrap_or_else(|| panic!("struct {rust_type_name} not found in Rust source")); - - // confirm the docs match - let idl_docs: Vec = type_in_idl["docs"] - .as_array() - .unwrap_or_else(|| panic!("docs should be an array for {rust_type_name}")) - .iter() - .map(|i| i.as_str().expect("doc item should be a string").to_string()) - .collect(); - - let rust_docs: Vec = rust_struct.attrs.iter().filter_map(doc_attr_text).collect(); - - assert_eq!( - idl_docs, rust_docs, - "documentation between rust and IDL types should be the same for {rust_type_name} and {idl_type_name}" - ); - - // confirm fields match, both in name/order and in type - let idl_fields: Vec<(String, Value)> = type_in_idl["type"]["fields"] - .as_array() - .unwrap_or_else(|| panic!("struct type {idl_type_name} should have a fields array")) - .iter() - .map(|f| { - ( - f["name"] - .as_str() - .expect("field name must be a string") - .to_string(), - f["type"].clone(), - ) - }) - .collect(); - - let rust_fields: Vec<(String, Value)> = rust_struct - .fields - .iter() - .map(|f| { - let name = f - .ident - .as_ref() - .unwrap_or_else(|| panic!("{idl_type_name} should have named fields")) - .to_string(); - let idl_type = rust_type_to_idl(&f.ty, &format!("{idl_type_name}.{name}")); - (name, idl_type) - }) - .collect(); - - assert_eq!( - idl_fields, rust_fields, - "{idl_type_name}'s IDL fields must match the Rust struct {idl_type_name} in name, order and type" - ); -} - -#[test] -fn idl_matches_rust_types() { - confirm_idl_types_entry(INTENT_RS, "OrderIntent", "OrderIntent"); - confirm_idl_types_entry(ORDER_RS, "OrderAccount", "OrderAccount"); - confirm_idl_types_entry(STATE_RS, "StateAccount", "SettlementState"); -} - -#[test] -fn idl_matches_rust_errors() { - let rust_file = syn::parse_file(INTERFACE_LIB_RS).expect("interface/src/lib.rs must parse"); - let rust_errors_type = rust_file - .items - .iter() - .find_map(|item| match item { - syn::Item::Enum(e) if e.ident == "SettlementError" => Some(e), - _ => None, - }) - .expect("SettlementError enum must exist in interface/src/lib.rs"); - - for rust_err in &rust_errors_type.variants { - let idl_err = - find_item_in_idl("errors", &rust_err.ident.to_string()).unwrap_or_else(|| { - panic!( - "Settlement program error {} is not defined in IDL errors[]", - rust_err.ident - ) - }); - - // the idl error's "code" should match up - let rust_code = match &rust_err.discriminant { - Some(( - _, - syn::Expr::Lit(syn::ExprLit { - lit: syn::Lit::Int(i), - .. - }), - )) => i - .base10_parse::() - .expect("discriminant must be a u32 literal"), - Some(_) => panic!("unexpected non-literal discriminant on {}", rust_err.ident), - None => panic!("discriminant should be defined on {}", rust_err.ident), - }; - - let idl_code = idl_err["code"] - .as_u64() - .expect("code should be correct type"); - - assert_eq!( - idl_code, rust_code as u64, - "IDL errors[] name={} should match the code in rust", - rust_err.ident - ); - - // the idl error's "msg" should match up - let rust_doc_lines: Vec = rust_err.attrs.iter().filter_map(doc_attr_text).collect(); - let rust_msg = normalize_doc(&rust_doc_lines); - - let idl_msg = idl_err["msg"].as_str().expect("msg must be a string"); - - assert_eq!( - idl_msg, rust_msg, - "IDL errors[] name={} should match informational msg", - rust_err.ident - ); - } -} - -#[test] -fn idl_pda_seed_literals_match_pda_module() { - let known: BTreeSet<&[u8]> = [SETTLEMENT_SEED, BUFFER_SEED, ORDER_SEED] - .into_iter() - .collect(); - - fn collect_const_seeds(value: &Value, out: &mut Vec>) { - match value { - Value::Object(map) => { - if map.get("kind").and_then(Value::as_str) == Some("const") { - if let Some(Value::Array(bytes)) = map.get("value") { - let decoded: Vec = bytes - .iter() - .map(|b| b.as_u64().expect("seed byte must be a number") as u8) - .collect(); - out.push(decoded); - } - } - for v in map.values() { - collect_const_seeds(v, out); - } - } - Value::Array(arr) => arr.iter().for_each(|v| collect_const_seeds(v, out)), - _ => {} - } - } - - let mut found = Vec::new(); - collect_const_seeds(&IDL["instructions"], &mut found); - - // Every const seed the IDL does declare must be a real seed constant. Not - // every seed constant needs to show up: `order_pda`'s canonical seed - // includes `sha256(intent)`, which the IDL can't express as a static - // `pda` entry at all (documented in create_order's docs), so `ORDER_SEED` - // legitimately never appears here. - for seed in &found { - assert!( - known.contains(seed.as_slice()), - "IDL PDA const seed {:?} doesn't match any seed constant in interface::pda", - String::from_utf8_lossy(seed), - ); - } - assert!( - found.iter().any(|s| s.as_slice() == SETTLEMENT_SEED), - "expected SETTLEMENT_SEED to appear in some IDL PDA `seeds`", - ); - assert!( - found.iter().any(|s| s.as_slice() == BUFFER_SEED), - "expected BUFFER_SEED to appear in some IDL PDA `seeds`", - ); -} diff --git a/programs/settlement/tests/idl/main.rs b/programs/settlement/tests/idl/main.rs new file mode 100644 index 0000000..fea546a --- /dev/null +++ b/programs/settlement/tests/idl/main.rs @@ -0,0 +1,231 @@ +//! IDL correctness tests for `programs/settlement/idl/cow_settlement.json`. +//! +//! This program is a native Pinocchio program with a hand-written IDL (no +//! `anchor idl build`/shank step keeps it in sync), so these tests +//! cross-check the checked-in file against the Rust source it describes. +//! +//! [`parse_json`] reads the IDL and [`parse_rust`] reads the Rust source; the +//! tests here only compare what the two report. + +mod parse_json; +mod parse_rust; + +use std::collections::BTreeSet; + +use parse_json::IDL; +use serde_json::Value; +use settlement_interface::{ + pda::{buffer::BUFFER_SEED, order::ORDER_SEED, SETTLEMENT_SEED}, + SettlementAccount, SettlementInstruction, +}; + +fn pascal_to_snake(s: &str) -> String { + let mut out = String::new(); + for (i, c) in s.chars().enumerate() { + if c.is_uppercase() { + if i != 0 { + out.push('_'); + } + out.extend(c.to_lowercase()); + } else { + out.push(c); + } + } + out +} + +fn confirm_idl_match(byte: u8, element_type: &str, idl_name: &str) { + let idl_element = parse_json::find_item(element_type, idl_name) + .unwrap_or_else(|| panic!("IDL does not contain defined settlement element {idl_name}")); + + // confirm the discriminator matches + assert_eq!( + parse_json::discriminator(idl_element, idl_name), + vec![byte], + "IDL discriminator for {idl_name} should be the single byte the code uses" + ); + + // confirm the docs match: everything the Rust enum variant documents must + // show up, in order, in the IDL element's docs. The IDL is allowed to say + // more than the Rust source does; it carries notes about what its own + // grammar can't express (`begin_settle`'s dynamically-shaped tail, for + // one), which have no business being in the program's own docs. + let idl_docs = parse_json::docs(idl_element, idl_name); + let rust_docs = parse_rust::discriminator_variant_docs(element_type, byte); + + let mut unmatched_idl_docs = idl_docs.iter(); + for rust_doc in &rust_docs { + assert!( + unmatched_idl_docs.any(|idl_doc| idl_doc == rust_doc), + "IDL docs for {idl_name} don't document what the Rust source does; missing (or \ + out of order) paragraph:\n{rust_doc}\nIDL docs are:\n{idl_docs:#?}" + ); + } +} + +// --------------------------------------------------------------------------- +// JSON validity and formatting +// --------------------------------------------------------------------------- + +#[test] +fn idl_is_valid_json() { + let _ = &*IDL; +} + +#[test] +fn idl_is_pretty_formatted() { + let mut formatted = serde_json::to_string_pretty(&*IDL).expect("IDL JSON should re-serialize"); + formatted.push('\n'); + assert_eq!( + formatted, + parse_json::IDL_JSON, + "IDL isn't canonically formatted; regenerate it with `serde_json::to_string_pretty` \ + plus a trailing newline" + ); +} + +#[test] +fn idl_address_matches_declared_program_id() { + assert_eq!( + IDL["address"].as_str().expect("address must be a string"), + settlement_interface::ID.to_string(), + "IDL `address` must match the program id declared via declare_id! in interface/src/lib.rs" + ); +} + +#[test] +fn idl_conforms_to_official_schema() { + let schema: Value = + serde_json::from_str(parse_json::SCHEMA_JSON).expect("schema should be valid JSON"); + let validator = jsonschema::validator_for(&schema).expect("schema should compile"); + let errors: Vec = validator.iter_errors(&IDL).map(|e| e.to_string()).collect(); + assert!( + errors.is_empty(), + "IDL fails schema validation:\n{}", + errors.join("\n") + ); +} + +#[test] +fn idl_matches_instruction_discriminators() { + for byte in 0u8..=255 { + if let Ok(ix) = SettlementInstruction::try_from(byte) { + confirm_idl_match(byte, "instructions", &pascal_to_snake(&format!("{ix:?}"))); + } + } +} + +#[test] +fn idl_matches_account_discriminators() { + for byte in 0u8..=255 { + if let Ok(account) = SettlementAccount::try_from(byte) { + confirm_idl_match(byte, "accounts", &format!("{account:?}")); + } + } +} + +/// Cross-checks one IDL `types[]` entry against the Rust struct it describes. +/// +/// `idl_name` is passed separately because the two don't always agree: +/// `StateAccount` is called `SettlementState` in the IDL, matching the +/// `SettlementAccount` discriminator variant that names the account. +fn confirm_idl_types_entry( + rust_source: &parse_rust::Source, + rust_type_name: &str, + idl_type_name: &str, +) { + // load in the idl and rust type definitions + let type_in_idl = parse_json::find_item("types", idl_type_name) + .unwrap_or_else(|| panic!("IDL types[] must contain {idl_type_name}")); + let rust_struct = rust_source.find_struct(rust_type_name); + + // confirm the docs match. `types[]` carries one docs entry per source + // line where `instructions[]` carries one per paragraph, so both sides are + // compared as a single joined block: same prose, wrapping not load-bearing. + assert_eq!( + parse_json::docs(type_in_idl, idl_type_name).join(" "), + parse_rust::docs(&rust_struct.attrs).join(" "), + "documentation between rust and IDL types should be the same for {rust_type_name} and {idl_type_name}" + ); + + // confirm fields match, both in name/order and in type + assert_eq!( + parse_json::struct_fields(type_in_idl, idl_type_name), + parse_rust::struct_fields(&rust_struct, idl_type_name), + "{idl_type_name}'s IDL fields must match the Rust struct {idl_type_name} in name, order and type" + ); +} + +#[test] +fn idl_matches_rust_types() { + confirm_idl_types_entry(&parse_rust::INTENT_RS, "OrderIntent", "OrderIntent"); + confirm_idl_types_entry(&parse_rust::ORDER_RS, "OrderAccount", "OrderAccount"); + confirm_idl_types_entry(&parse_rust::STATE_RS, "StateAccount", "SettlementState"); +} + +#[test] +fn idl_matches_rust_errors() { + let rust_errors_type = parse_rust::INTERFACE_LIB_RS.find_enum("SettlementError"); + + for rust_err in &rust_errors_type.variants { + let idl_err = + parse_json::find_item("errors", &rust_err.ident.to_string()).unwrap_or_else(|| { + panic!( + "Settlement program error {} is not defined in IDL errors[]", + rust_err.ident + ) + }); + + // the idl error's "code" should match up + let idl_code = idl_err["code"] + .as_u64() + .expect("code should be correct type"); + + assert_eq!( + idl_code, + parse_rust::discriminant(rust_err), + "IDL errors[] name={} should match the code in rust", + rust_err.ident + ); + + // the idl error's "msg" should match up + let rust_msg = parse_rust::docs(&rust_err.attrs).join(" "); + let idl_msg = idl_err["msg"].as_str().expect("msg must be a string"); + + assert_eq!( + idl_msg, rust_msg, + "IDL errors[] name={} should match informational msg", + rust_err.ident + ); + } +} + +#[test] +fn idl_pda_seed_literals_match_pda_module() { + let known: BTreeSet<&[u8]> = [SETTLEMENT_SEED, BUFFER_SEED, ORDER_SEED] + .into_iter() + .collect(); + + let found = parse_json::const_seeds(&IDL["instructions"]); + + // Every const seed the IDL does declare must be a real seed constant. Not + // every seed constant needs to show up: `order_pda`'s canonical seed + // includes `sha256(intent)`, which the IDL can't express as a static + // `pda` entry at all (documented in create_order's docs), so `ORDER_SEED` + // legitimately never appears here. + for seed in &found { + assert!( + known.contains(seed.as_slice()), + "IDL PDA const seed {:?} doesn't match any seed constant in interface::pda", + String::from_utf8_lossy(seed), + ); + } + assert!( + found.iter().any(|s| s.as_slice() == SETTLEMENT_SEED), + "expected SETTLEMENT_SEED to appear in some IDL PDA `seeds`", + ); + assert!( + found.iter().any(|s| s.as_slice() == BUFFER_SEED), + "expected BUFFER_SEED to appear in some IDL PDA `seeds`", + ); +} diff --git a/programs/settlement/tests/idl/parse_json.rs b/programs/settlement/tests/idl/parse_json.rs new file mode 100644 index 0000000..16e2c43 --- /dev/null +++ b/programs/settlement/tests/idl/parse_json.rs @@ -0,0 +1,113 @@ +//! Readers for the checked-in IDL, `programs/settlement/idl/cow_settlement.json`. +//! +//! Accessors panic naming the entry that went missing or came back the wrong +//! shape, so a malformed IDL fails where it's read rather than where it's +//! compared. + +use std::sync::LazyLock; + +use serde_json::Value; + +use crate::parse_rust::normalize_doc; + +pub const IDL_JSON: &str = include_str!("../../idl/cow_settlement.json"); +pub const SCHEMA_JSON: &str = include_str!("../../idl/schema/idl-spec-v0.1.0.json"); + +pub static IDL: LazyLock = + LazyLock::new(|| serde_json::from_str(IDL_JSON).expect("IDL must be valid JSON")); + +/// The top-level `name[]` array, e.g. `instructions` or `types`. +pub fn section(name: &str) -> &'static [Value] { + IDL[name] + .as_array() + .unwrap_or_else(|| panic!("IDL {name}[] must be an array")) +} + +/// The `section[]` entry named `name`, if the IDL declares one. +pub fn find_item(section_name: &str, name: &str) -> Option<&'static Value> { + section(section_name) + .iter() + .find(|item| item["name"] == name) +} + +/// An entry's `docs`, one [`normalize_doc`]d string per entry, so they compare +/// directly against what [`crate::parse_rust::docs`] reports. Absent docs read +/// as none at all; the caller compares against the Rust source to decide +/// whether that's wrong. +pub fn docs(item: &Value, context: &str) -> Vec { + let Some(docs) = item.get("docs") else { + return Vec::new(); + }; + docs.as_array() + .unwrap_or_else(|| panic!("docs for {context} should be an array")) + .iter() + .map(|doc| { + let doc = doc + .as_str() + .unwrap_or_else(|| panic!("doc entry for {context} should be a string")); + normalize_doc(&[doc]) + }) + .collect() +} + +/// An entry's `discriminator` bytes. +pub fn discriminator(item: &Value, context: &str) -> Vec { + item["discriminator"] + .as_array() + .unwrap_or_else(|| panic!("discriminator for {context} should be an array")) + .iter() + .map(|byte| { + let byte = byte + .as_u64() + .unwrap_or_else(|| panic!("discriminator byte for {context} should be a number")); + u8::try_from(byte) + .unwrap_or_else(|_| panic!("discriminator byte for {context} should fit in a u8")) + }) + .collect() +} + +/// The `(name, type)` pairs of a struct `types[]` entry, in declaration order. +pub fn struct_fields(item: &Value, context: &str) -> Vec<(String, Value)> { + item["type"]["fields"] + .as_array() + .unwrap_or_else(|| panic!("struct type {context} should have a fields array")) + .iter() + .map(|field| { + ( + field["name"] + .as_str() + .unwrap_or_else(|| panic!("field name in {context} must be a string")) + .to_string(), + field["type"].clone(), + ) + }) + .collect() +} + +/// Every `{"kind": "const"}` seed byte string anywhere below `value`. +pub fn const_seeds(value: &Value) -> Vec> { + fn collect(value: &Value, out: &mut Vec>) { + match value { + Value::Object(map) => { + if map.get("kind").and_then(Value::as_str) == Some("const") { + if let Some(Value::Array(bytes)) = map.get("value") { + let decoded: Vec = bytes + .iter() + .map(|b| b.as_u64().expect("seed byte must be a number") as u8) + .collect(); + out.push(decoded); + } + } + for v in map.values() { + collect(v, out); + } + } + Value::Array(arr) => arr.iter().for_each(|v| collect(v, out)), + _ => {} + } + } + + let mut found = Vec::new(); + collect(value, &mut found); + found +} diff --git a/programs/settlement/tests/idl/parse_rust.rs b/programs/settlement/tests/idl/parse_rust.rs new file mode 100644 index 0000000..950aeac --- /dev/null +++ b/programs/settlement/tests/idl/parse_rust.rs @@ -0,0 +1,221 @@ +//! Readers for the Rust sources the IDL describes. +//! +//! Everything here goes through `syn`, panicking with the source path when the +//! item the IDL claims to describe isn't there to compare against. + +use serde_json::{json, Value}; + +/// A Rust source file, compiled in so the tests parse the same text the +/// program does. +pub struct Source { + /// Repo-relative path, for panic messages. + display: &'static str, + text: &'static str, +} + +pub const INTERFACE_LIB_RS: Source = Source { + display: "interface/src/lib.rs", + text: include_str!("../../../../interface/src/lib.rs"), +}; + +pub const INTENT_RS: Source = Source { + display: "interface/src/data/intent.rs", + text: include_str!("../../../../interface/src/data/intent.rs"), +}; + +pub const ORDER_RS: Source = Source { + display: "interface/src/data/order.rs", + text: include_str!("../../../../interface/src/data/order.rs"), +}; + +pub const STATE_RS: Source = Source { + display: "interface/src/data/state.rs", + text: include_str!("../../../../interface/src/data/state.rs"), +}; + +impl Source { + fn parse(&self) -> syn::File { + syn::parse_file(self.text) + .unwrap_or_else(|err| panic!("{} must parse: {err}", self.display)) + } + + /// The `enum name` this file declares. + pub fn find_enum(&self, name: &str) -> syn::ItemEnum { + self.parse() + .items + .into_iter() + .find_map(|item| match item { + syn::Item::Enum(e) if e.ident == name => Some(e), + _ => None, + }) + .unwrap_or_else(|| panic!("{name} enum must exist in {}", self.display)) + } + + /// The `struct name` this file declares. + pub fn find_struct(&self, name: &str) -> syn::ItemStruct { + self.parse() + .items + .into_iter() + .find_map(|item| match item { + syn::Item::Struct(s) if s.ident == name => Some(s), + _ => None, + }) + .unwrap_or_else(|| panic!("struct {name} not found in {}", self.display)) + } +} + +/// The variant of `rust_enum` whose discriminant is `byte`. +pub fn variant_by_discriminant(rust_enum: &syn::ItemEnum, byte: u8) -> &syn::Variant { + rust_enum + .variants + .iter() + .find(|variant| discriminant(variant) == u64::from(byte)) + .unwrap_or_else(|| { + panic!( + "{} must have a variant with discriminant {byte}", + rust_enum.ident + ) + }) +} + +/// Translates a Rust field type into the IDL spec's type grammar, so field +/// types can be compared as JSON. Panics on anything the program's data types +/// don't currently use. +pub fn type_to_idl(ty: &syn::Type, context: &str) -> Value { + match ty { + syn::Type::Path(path) => { + let ident = path + .path + .get_ident() + .unwrap_or_else(|| panic!("{context}: expected a plain type name")) + .to_string(); + match ident.as_str() { + "Pubkey" => json!("pubkey"), + "bool" | "u8" | "u16" | "u32" | "u64" | "u128" | "i8" | "i16" | "i32" | "i64" + | "i128" => json!(ident), + // Anything else is one of this crate's own types, which the IDL + // carries as its own `types[]` entry and references by name. + _ => json!({ "defined": { "name": ident } }), + } + } + syn::Type::Array(array) => { + let syn::Expr::Lit(syn::ExprLit { + lit: syn::Lit::Int(len), + .. + }) = &array.len + else { + panic!("{context}: array length must be an integer literal"); + }; + let len: u64 = len.base10_parse().expect("array length must be a u64"); + json!({ "array": [type_to_idl(&array.elem, context), len] }) + } + _ => panic!("{context}: unsupported field type"), + } +} + +/// The `= N` discriminant an enum variant declares. Every enum the IDL mirrors +/// pins its wire values explicitly, so a missing or computed one is a bug. +pub fn discriminant(variant: &syn::Variant) -> u64 { + match &variant.discriminant { + Some(( + _, + syn::Expr::Lit(syn::ExprLit { + lit: syn::Lit::Int(i), + .. + }), + )) => i.base10_parse().unwrap_or_else(|err| { + panic!( + "discriminant on {} must be an unsigned integer literal: {err}", + variant.ident + ) + }), + Some(_) => panic!("unexpected non-literal discriminant on {}", variant.ident), + None => panic!("discriminant should be defined on {}", variant.ident), + } +} + +/// The `(name, type)` pairs of a struct's fields, in declaration order, with +/// each type already translated into the IDL's type grammar. +pub fn struct_fields(rust_struct: &syn::ItemStruct, context: &str) -> Vec<(String, Value)> { + rust_struct + .fields + .iter() + .map(|field| { + let name = field + .ident + .as_ref() + .unwrap_or_else(|| panic!("{context} should have named fields")) + .to_string(); + let idl_type = type_to_idl(&field.ty, &format!("{context}.{name}")); + (name, idl_type) + }) + .collect() +} + +/// Collapses doc lines into the single line the IDL carries them as, dropping +/// the backtick markup the IDL only carries in some places. Both this module +/// and [`crate::parse_json`] hand their doc text through here, so the two sides +/// are always compared in the same form. +pub fn normalize_doc>(lines: &[S]) -> String { + lines + .iter() + .map(AsRef::as_ref) + .collect::>() + .join(" ") + .replace('`', "") +} + +/// Extract the doc text from a single attribute line in Rust +fn doc_attr_text(attr: &syn::Attribute) -> Option { + if !attr.path().is_ident("doc") { + return None; + } + let syn::Meta::NameValue(nv) = &attr.meta else { + return None; + }; + let syn::Expr::Lit(syn::ExprLit { + lit: syn::Lit::Str(s), + .. + }) = &nv.value + else { + return None; + }; + // Doc comments start with spaces. We want to remove that, + // but we want to keep extra alignment spacing if present. + let doc = s.value(); + Some(doc.strip_prefix(' ').unwrap_or(&doc).to_string()) +} + +/// An item's doc comment, one [`normalize_doc`]d string per paragraph, with +/// blank doc lines separating the paragraphs. +pub fn docs(attrs: &[syn::Attribute]) -> Vec { + let mut paragraphs = Vec::new(); + let mut paragraph: Vec = Vec::new(); + for line in attrs.iter().filter_map(doc_attr_text) { + if line.is_empty() { + if !paragraph.is_empty() { + paragraphs.push(normalize_doc(&std::mem::take(&mut paragraph))); + } + } else { + paragraph.push(line); + } + } + if !paragraph.is_empty() { + paragraphs.push(normalize_doc(¶graph)); + } + paragraphs +} + +/// [`docs`] of the variant with discriminant `byte` in whichever discriminator +/// enum backs the IDL's `element_type[]` section. +pub fn discriminator_variant_docs(element_type: &str, byte: u8) -> Vec { + let enum_name = match element_type { + "instructions" => "SettlementInstruction", + "accounts" => "SettlementAccount", + other => panic!("no discriminator enum backs IDL {other}[]"), + }; + + let rust_enum = INTERFACE_LIB_RS.find_enum(enum_name); + + docs(&variant_by_discriminant(&rust_enum, byte).attrs) +} From 3190d0ecd84f19983488c8f6e75c014dc4fae73b Mon Sep 17 00:00:00 2001 From: Kaze <230549489+kaze-cow@users.noreply.github.com> Date: Thu, 20 Aug 2026 23:48:12 +0900 Subject: [PATCH 11/43] switch to an enum to make it more clear what a type is in the idl context --- programs/settlement/tests/idl/main.rs | 24 ++++++---- programs/settlement/tests/idl/parse_json.rs | 52 +++++++++++++++++---- programs/settlement/tests/idl/parse_rust.rs | 12 +++-- 3 files changed, 63 insertions(+), 25 deletions(-) diff --git a/programs/settlement/tests/idl/main.rs b/programs/settlement/tests/idl/main.rs index fea546a..18c644e 100644 --- a/programs/settlement/tests/idl/main.rs +++ b/programs/settlement/tests/idl/main.rs @@ -12,7 +12,7 @@ mod parse_rust; use std::collections::BTreeSet; -use parse_json::IDL; +use parse_json::{Section, IDL}; use serde_json::Value; use settlement_interface::{ pda::{buffer::BUFFER_SEED, order::ORDER_SEED, SETTLEMENT_SEED}, @@ -34,8 +34,8 @@ fn pascal_to_snake(s: &str) -> String { out } -fn confirm_idl_match(byte: u8, element_type: &str, idl_name: &str) { - let idl_element = parse_json::find_item(element_type, idl_name) +fn confirm_idl_match(byte: u8, section: Section, idl_name: &str) { + let idl_element = parse_json::find_item(section, idl_name) .unwrap_or_else(|| panic!("IDL does not contain defined settlement element {idl_name}")); // confirm the discriminator matches @@ -51,7 +51,7 @@ fn confirm_idl_match(byte: u8, element_type: &str, idl_name: &str) { // grammar can't express (`begin_settle`'s dynamically-shaped tail, for // one), which have no business being in the program's own docs. let idl_docs = parse_json::docs(idl_element, idl_name); - let rust_docs = parse_rust::discriminator_variant_docs(element_type, byte); + let rust_docs = parse_rust::discriminator_variant_docs(section, byte); let mut unmatched_idl_docs = idl_docs.iter(); for rust_doc in &rust_docs { @@ -110,7 +110,11 @@ fn idl_conforms_to_official_schema() { fn idl_matches_instruction_discriminators() { for byte in 0u8..=255 { if let Ok(ix) = SettlementInstruction::try_from(byte) { - confirm_idl_match(byte, "instructions", &pascal_to_snake(&format!("{ix:?}"))); + confirm_idl_match( + byte, + Section::Instructions, + &pascal_to_snake(&format!("{ix:?}")), + ); } } } @@ -119,7 +123,7 @@ fn idl_matches_instruction_discriminators() { fn idl_matches_account_discriminators() { for byte in 0u8..=255 { if let Ok(account) = SettlementAccount::try_from(byte) { - confirm_idl_match(byte, "accounts", &format!("{account:?}")); + confirm_idl_match(byte, Section::Accounts, &format!("{account:?}")); } } } @@ -135,7 +139,7 @@ fn confirm_idl_types_entry( idl_type_name: &str, ) { // load in the idl and rust type definitions - let type_in_idl = parse_json::find_item("types", idl_type_name) + let type_in_idl = parse_json::find_item(Section::Types, idl_type_name) .unwrap_or_else(|| panic!("IDL types[] must contain {idl_type_name}")); let rust_struct = rust_source.find_struct(rust_type_name); @@ -168,8 +172,8 @@ fn idl_matches_rust_errors() { let rust_errors_type = parse_rust::INTERFACE_LIB_RS.find_enum("SettlementError"); for rust_err in &rust_errors_type.variants { - let idl_err = - parse_json::find_item("errors", &rust_err.ident.to_string()).unwrap_or_else(|| { + let idl_err = parse_json::find_item(Section::Errors, &rust_err.ident.to_string()) + .unwrap_or_else(|| { panic!( "Settlement program error {} is not defined in IDL errors[]", rust_err.ident @@ -206,7 +210,7 @@ fn idl_pda_seed_literals_match_pda_module() { .into_iter() .collect(); - let found = parse_json::const_seeds(&IDL["instructions"]); + let found = parse_json::const_seeds(parse_json::section(Section::Instructions)); // Every const seed the IDL does declare must be a real seed constant. Not // every seed constant needs to show up: `order_pda`'s canonical seed diff --git a/programs/settlement/tests/idl/parse_json.rs b/programs/settlement/tests/idl/parse_json.rs index 16e2c43..44df647 100644 --- a/programs/settlement/tests/idl/parse_json.rs +++ b/programs/settlement/tests/idl/parse_json.rs @@ -4,7 +4,7 @@ //! shape, so a malformed IDL fails where it's read rather than where it's //! compared. -use std::sync::LazyLock; +use std::{fmt, sync::LazyLock}; use serde_json::Value; @@ -16,15 +16,45 @@ pub const SCHEMA_JSON: &str = include_str!("../../idl/schema/idl-spec-v0.1.0.jso pub static IDL: LazyLock = LazyLock::new(|| serde_json::from_str(IDL_JSON).expect("IDL must be valid JSON")); -/// The top-level `name[]` array, e.g. `instructions` or `types`. -pub fn section(name: &str) -> &'static [Value] { - IDL[name] +/// A top-level array of the IDL. Naming the sections the tests read as a type +/// keeps a mistyped section from reading as a missing entry. +#[derive(Clone, Copy)] +pub enum Section { + Instructions, + Accounts, + Types, + Errors, +} + +impl Section { + /// The IDL key this section lives under. + pub fn as_str(self) -> &'static str { + match self { + Self::Instructions => "instructions", + Self::Accounts => "accounts", + Self::Types => "types", + Self::Errors => "errors", + } + } +} + +impl fmt::Display for Section { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self.as_str()) + } +} + +/// The top-level `section[]` array. +pub fn section(section: Section) -> &'static [Value] { + IDL[section.as_str()] .as_array() - .unwrap_or_else(|| panic!("IDL {name}[] must be an array")) + .unwrap_or_else(|| panic!("IDL {section}[] must be an array")) } -/// The `section[]` entry named `name`, if the IDL declares one. -pub fn find_item(section_name: &str, name: &str) -> Option<&'static Value> { +/// Under the array for `section_name`, find the object where the `name` matches the given value. +/// Since each IDL section follows the same pattern where each section is an array of objects which contain a field `name`, this function +/// is useful for finding just about any item we need in the IDL file. +pub fn find_item(section_name: Section, name: &str) -> Option<&'static Value> { section(section_name) .iter() .find(|item| item["name"] == name) @@ -84,8 +114,8 @@ pub fn struct_fields(item: &Value, context: &str) -> Vec<(String, Value)> { .collect() } -/// Every `{"kind": "const"}` seed byte string anywhere below `value`. -pub fn const_seeds(value: &Value) -> Vec> { +/// Every `{"kind": "const"}` seed byte string anywhere below `values`. +pub fn const_seeds(values: &[Value]) -> Vec> { fn collect(value: &Value, out: &mut Vec>) { match value { Value::Object(map) => { @@ -108,6 +138,8 @@ pub fn const_seeds(value: &Value) -> Vec> { } let mut found = Vec::new(); - collect(value, &mut found); + for value in values { + collect(value, &mut found); + } found } diff --git a/programs/settlement/tests/idl/parse_rust.rs b/programs/settlement/tests/idl/parse_rust.rs index 950aeac..f3bef5a 100644 --- a/programs/settlement/tests/idl/parse_rust.rs +++ b/programs/settlement/tests/idl/parse_rust.rs @@ -5,6 +5,8 @@ use serde_json::{json, Value}; +use crate::parse_json::Section; + /// A Rust source file, compiled in so the tests parse the same text the /// program does. pub struct Source { @@ -207,11 +209,11 @@ pub fn docs(attrs: &[syn::Attribute]) -> Vec { } /// [`docs`] of the variant with discriminant `byte` in whichever discriminator -/// enum backs the IDL's `element_type[]` section. -pub fn discriminator_variant_docs(element_type: &str, byte: u8) -> Vec { - let enum_name = match element_type { - "instructions" => "SettlementInstruction", - "accounts" => "SettlementAccount", +/// enum backs the given IDL `section`. +pub fn discriminator_variant_docs(section: Section, byte: u8) -> Vec { + let enum_name = match section { + Section::Instructions => "SettlementInstruction", + Section::Accounts => "SettlementAccount", other => panic!("no discriminator enum backs IDL {other}[]"), }; From 70050939d11969b0d42b417da750ba37c8785883 Mon Sep 17 00:00:00 2001 From: Kaze <230549489+kaze-cow@users.noreply.github.com> Date: Thu, 20 Aug 2026 23:59:06 +0900 Subject: [PATCH 12/43] update to the latest on the idl side --- programs/settlement/idl/cow_settlement.json | 258 +++++++++++++++++++- 1 file changed, 247 insertions(+), 11 deletions(-) diff --git a/programs/settlement/idl/cow_settlement.json b/programs/settlement/idl/cow_settlement.json index 9d3c7a3..635f519 100644 --- a/programs/settlement/idl/cow_settlement.json +++ b/programs/settlement/idl/cow_settlement.json @@ -1,8 +1,8 @@ { - "address": "MooohhPEAAHwAwEozL7JPEmnDvaahuUpccYN4Yb8ccK", + "address": "J516Mv7YvvvJyMvNEca8tWNTJyDHbFpzwDZD96BNfR3w", "metadata": { "name": "cow_settlement", - "version": "0.1.0", + "version": "0.2.0", "spec": "0.1.0", "description": "CoW Protocol settlement program. IDL may not be able to generate typical of Anchor programs, so please be careful to read the documentation on the function you are using.", "repository": "https://github.com/cowprotocol/solana-programs" @@ -47,7 +47,7 @@ 118, 48, 46, - 49, + 50, 32, 32, 32, @@ -66,10 +66,17 @@ } ], "args": [ + { + "name": "manager", + "docs": [ + "Recorded verbatim in the state PDA's body as the initial holder of the Manager role: the account authorized to add and remove solvers and to transfer any role." + ], + "type": "pubkey" + }, { "name": "reclaim_authority", "docs": [ - "Recorded verbatim in the state PDA's body as SettlementState.reclaim_authority." + "Recorded verbatim in the state PDA's body as the initial holder of the ReclaimAuthority role: the account authorized to close buffer accounts and reclaim their rent." ], "type": "pubkey" } @@ -121,7 +128,7 @@ 118, 48, 46, - 49, + 50, 32, 32, 32, @@ -210,7 +217,7 @@ "name": "begin_settle", "docs": [ "Pulls funds for a batch of orders. Must be paired in the same transaction with a FinalizeSettle at `finalize_ix_index`.", - "IDL LIMITATION: only the fixed-size prefix (finalize_ix_index, auction_id) is represented as typed arguments. After it, the real wire format is `[order_count: u8][bump; order_count][transfer_count; order_count][amount: u64 LE; sum(transfer_count)]`. Please check the rust documentation for more information." + "IDL LIMITATION: only the fixed-size prefix (finalize_ix_index, auction_id) is represented as typed arguments. After it, the real wire format is `[order_count: u8][transfer_count; order_count][amount: u64 LE; sum(transfer_count)]`. Please check the rust documentation for more information." ], "discriminator": [ 0 @@ -251,7 +258,8 @@ { "name": "finalize_settle", "docs": [ - "Validates that a BeginSettle at `begin_ix_index` exists and points back at this instruction. Must not be called via CPI." + "Validates that a BeginSettle at `begin_ix_index` exists and points back at this instruction. Must not be called via CPI.", + "IDL LIMITATION: only the fixed-size prefix (begin_ix_index) is represented as a typed argument. After it, the real wire format is `[bump: u8; push_count][amount: u64 LE; push_count]`, where each bump is the canonical bump of the push's source buffer PDA. Please check the rust documentation for more information." ], "discriminator": [ 1 @@ -296,7 +304,7 @@ "name": "order_pda", "writable": true, "docs": [ - "The order PDA to close." + "The order PDA to close. Its canonical bump is read out of the stored OrderAccount body, so no bump argument is needed." ] }, { @@ -307,12 +315,200 @@ ] } ], + "args": [] + }, + { + "name": "reclaim_buffer", + "docs": [ + "Closes one or more buffer PDAs and sends each closed buffer's rent lamports to a reclaim_recipient of the caller's choosing. Only the current holder of the ReclaimAuthority role recorded in the state PDA may authorize this. A buffer that still holds tokens is skipped, not closed, and the instruction still succeeds.", + "IDL LIMITATION: the real instruction accepts an unbounded number of (buffer_pda, mint) pairs as remaining accounts, one pair per buffer, with at least one pair required (ReclaimBuffer rejects zero buffers). IDL grammar has no 'repeated group' construct, so this file only declares the guaranteed index-0 template (buffer_pda_0/mint_0).", + "Each buffer_pda_i must be the canonical PDA for seeds [SETTLEMENT_SEED, mint_i, \"buffer\"]; mint_i is passed only so that derivation can be checked on-chain." + ], + "discriminator": [ + 6 + ], + "accounts": [ + { + "name": "state_pda", + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 115, + 101, + 116, + 116, + 108, + 101, + 109, + 101, + 110, + 116, + 32, + 118, + 48, + 46, + 50, + 32, + 32, + 32, + 32 + ] + } + ] + }, + "docs": [ + "Must be the canonical state PDA; holds the reclaim_authority the signer is checked against, and is the buffers' SPL token authority. Canonical PDA seeded by SETTLEMENT_SEED alone. SETTLEMENT_SEED is the ASCII prefix \"settlement v\" followed by the program's major.minor version, right-padded with spaces to a fixed 19 bytes; the fixed width prevents one version's seeds from being a prefix of another's. The const bytes below are authoritative and change on every minor version bump." + ] + }, + { + "name": "reclaim_authority", + "signer": true, + "docs": [ + "Must match the reclaim_authority address recorded in the state PDA." + ] + }, + { + "name": "reclaim_recipient", + "writable": true, + "docs": [ + "Receives the rent lamports of every closed buffer." + ] + }, + { + "name": "token_program", + "address": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + { + "name": "buffer_pda_0", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 115, + 101, + 116, + 116, + 108, + 101, + 109, + 101, + 110, + 116, + 32, + 118, + 48, + 46, + 50, + 32, + 32, + 32, + 32 + ] + }, + { + "kind": "account", + "path": "mint_0" + }, + { + "kind": "const", + "value": [ + 98, + 117, + 102, + 102, + 101, + 114 + ] + } + ] + }, + "docs": [ + "Guaranteed present: ReclaimBuffer rejects an instruction with zero buffers." + ] + }, + { + "name": "mint_0", + "docs": [ + "Guaranteed present: ReclaimBuffer rejects an instruction with zero buffers." + ] + } + ], + "args": [] + }, + { + "name": "transfer_authority", + "docs": [ + "Transfers one Role stored in the state PDA to another account in a single step: the signer names the new holder and the role's holder is updated immediately.", + "The signer must be either the manager or the current holder of the role being transferred." + ], + "discriminator": [ + 7 + ], + "accounts": [ + { + "name": "signer", + "signer": true, + "docs": [ + "Authorizes the transfer; must be the manager or the current holder of `role`." + ] + }, + { + "name": "state_pda", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 115, + 101, + 116, + 116, + 108, + 101, + 109, + 101, + 110, + 116, + 32, + 118, + 48, + 46, + 50, + 32, + 32, + 32, + 32 + ] + } + ] + }, + "docs": [ + "Canonical PDA seeded by SETTLEMENT_SEED alone. SETTLEMENT_SEED is the ASCII prefix \"settlement v\" followed by the program's major.minor version, right-padded with spaces to a fixed 19 bytes; the fixed width prevents one version's seeds from being a prefix of another's. The const bytes below are authoritative and change on every minor version bump." + ] + } + ], "args": [ { - "name": "bump", - "type": "u8", + "name": "role", + "type": { + "defined": { + "name": "Role" + } + }, + "docs": [ + "The role to transfer, as its single wire discriminator byte." + ] + }, + { + "name": "new_authority", + "type": "pubkey", "docs": [ - "order_pda's canonical bump, used to prove it's the canonical order PDA for the intent it stores." + "Becomes the holder of `role` once the instruction succeeds." ] } ] @@ -341,6 +537,10 @@ "type": { "kind": "struct", "fields": [ + { + "name": "bump", + "type": "u8" + }, { "name": "cancelled", "type": "bool" @@ -376,6 +576,10 @@ "type": { "kind": "struct", "fields": [ + { + "name": "manager", + "type": "pubkey" + }, { "name": "reclaim_authority", "type": "pubkey" @@ -454,6 +658,23 @@ } ] } + }, + { + "name": "Role", + "docs": [ + "A transferable authority stored in the state PDA. The variant index is the single wire byte that selects the role in transfer_authority." + ], + "type": { + "kind": "enum", + "variants": [ + { + "name": "Manager" + }, + { + "name": "ReclaimAuthority" + } + ] + } } ], "errors": [ @@ -616,6 +837,21 @@ "code": 31, "name": "ReclaimRecipientMismatch", "msg": "ReclaimOrder's reclaim_recipient account doesn't match the created_by address recorded in the order." + }, + { + "code": 32, + "name": "ReclaimAuthorityMismatch", + "msg": "ReclaimBuffer's reclaim_authority account isn't a signer, or doesn't match the reclaim_authority address recorded in the settlement state PDA." + }, + { + "code": 33, + "name": "ReclaimBufferNotCanonical", + "msg": "A ReclaimBuffer buffer_pda doesn't sit at the canonical buffer PDA derived from its paired mint." + }, + { + "code": 34, + "name": "UnauthorizedAuthorityTransfer", + "msg": "TransferAuthority's signer is neither the manager nor the current holder of the role being transferred, so it may not transfer it." } ] } From ba596f8eabba66233683ce5f5ccc07b9387ed396 Mon Sep 17 00:00:00 2001 From: Kaze <230549489+kaze-cow@users.noreply.github.com> Date: Fri, 21 Aug 2026 00:02:35 +0900 Subject: [PATCH 13/43] add test verifying the idl version matches cargo pkg --- programs/settlement/tests/idl/main.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/programs/settlement/tests/idl/main.rs b/programs/settlement/tests/idl/main.rs index 72eab56..b491710 100644 --- a/programs/settlement/tests/idl/main.rs +++ b/programs/settlement/tests/idl/main.rs @@ -12,12 +12,12 @@ mod parse_rust; use std::collections::BTreeSet; -use parse_json::{Section, IDL}; -use serde_json::Value; use cow_settlement_interface::{ pda::{buffer::BUFFER_SEED, order::ORDER_SEED, SETTLEMENT_SEED}, SettlementAccount, SettlementInstruction, }; +use parse_json::{Section, IDL}; +use serde_json::Value; fn pascal_to_snake(s: &str) -> String { let mut out = String::new(); @@ -93,6 +93,18 @@ fn idl_address_matches_declared_program_id() { ); } +#[test] +fn idl_version_matches_cargo_package_version() { + assert_eq!( + IDL["metadata"]["version"] + .as_str() + .expect("metadata.version must be a string"), + env!("CARGO_PKG_VERSION"), + "IDL `metadata.version` must match the settlement program's cargo package version; \ + bumping the minor version also moves every PDA, so a stale value here hides that" + ); +} + #[test] fn idl_conforms_to_official_schema() { let schema: Value = From f4cf0438831f179e29f575cd3fbd53d2333a77a6 Mon Sep 17 00:00:00 2001 From: Kaze <230549489+kaze-cow@users.noreply.github.com> Date: Fri, 21 Aug 2026 00:14:56 +0900 Subject: [PATCH 14/43] improve confirm_idl_match params naming --- programs/settlement/tests/idl/main.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/programs/settlement/tests/idl/main.rs b/programs/settlement/tests/idl/main.rs index b491710..f6cf255 100644 --- a/programs/settlement/tests/idl/main.rs +++ b/programs/settlement/tests/idl/main.rs @@ -34,14 +34,14 @@ fn pascal_to_snake(s: &str) -> String { out } -fn confirm_idl_match(byte: u8, section: Section, idl_name: &str) { - let idl_element = parse_json::find_item(section, idl_name) +fn confirm_idl_match(idl_section: Section, idl_name: &str, discriminator_byte: u8) { + let idl_element = parse_json::find_item(idl_section, idl_name) .unwrap_or_else(|| panic!("IDL does not contain defined settlement element {idl_name}")); // confirm the discriminator matches assert_eq!( parse_json::discriminator(idl_element, idl_name), - vec![byte], + vec![discriminator_byte], "IDL discriminator for {idl_name} should be the single byte the code uses" ); @@ -51,7 +51,7 @@ fn confirm_idl_match(byte: u8, section: Section, idl_name: &str) { // grammar can't express (`begin_settle`'s dynamically-shaped tail, for // one), which have no business being in the program's own docs. let idl_docs = parse_json::docs(idl_element, idl_name); - let rust_docs = parse_rust::discriminator_variant_docs(section, byte); + let rust_docs = parse_rust::discriminator_variant_docs(idl_section, discriminator_byte); let mut unmatched_idl_docs = idl_docs.iter(); for rust_doc in &rust_docs { @@ -123,9 +123,9 @@ fn idl_matches_instruction_discriminators() { for byte in 0u8..=255 { if let Ok(ix) = SettlementInstruction::try_from(byte) { confirm_idl_match( - byte, Section::Instructions, &pascal_to_snake(&format!("{ix:?}")), + byte, ); } } @@ -135,7 +135,7 @@ fn idl_matches_instruction_discriminators() { fn idl_matches_account_discriminators() { for byte in 0u8..=255 { if let Ok(account) = SettlementAccount::try_from(byte) { - confirm_idl_match(byte, Section::Accounts, &format!("{account:?}")); + confirm_idl_match(Section::Accounts, &format!("{account:?}"), byte); } } } From af8cfd32bd579b91976af5d1794b0ef45ae503a3 Mon Sep 17 00:00:00 2001 From: Kaze <230549489+kaze-cow@users.noreply.github.com> Date: Mon, 24 Aug 2026 16:00:23 +0900 Subject: [PATCH 15/43] add more idl checks, when it was easy enough --- programs/settlement/idl/cow_settlement.json | 7 +- programs/settlement/tests/idl/main.rs | 189 +++++++++++++++++++- programs/settlement/tests/idl/parse_json.rs | 59 +++++- programs/settlement/tests/idl/parse_rust.rs | 133 ++++++++++++-- 4 files changed, 359 insertions(+), 29 deletions(-) diff --git a/programs/settlement/idl/cow_settlement.json b/programs/settlement/idl/cow_settlement.json index 635f519..60865a4 100644 --- a/programs/settlement/idl/cow_settlement.json +++ b/programs/settlement/idl/cow_settlement.json @@ -647,6 +647,9 @@ }, { "name": "OrderKind", + "docs": [ + "Direction of the trade." + ], "type": { "kind": "enum", "variants": [ @@ -662,7 +665,9 @@ { "name": "Role", "docs": [ - "A transferable authority stored in the state PDA. The variant index is the single wire byte that selects the role in transfer_authority." + "A transferable authority stored in the state PDA.", + "The discriminant is the wire value carried by the authority-transfer", + "instruction (see transfer_authority)." ], "type": { "kind": "enum", diff --git a/programs/settlement/tests/idl/main.rs b/programs/settlement/tests/idl/main.rs index f6cf255..cea64d2 100644 --- a/programs/settlement/tests/idl/main.rs +++ b/programs/settlement/tests/idl/main.rs @@ -17,7 +17,7 @@ use cow_settlement_interface::{ SettlementAccount, SettlementInstruction, }; use parse_json::{Section, IDL}; -use serde_json::Value; +use serde_json::{json, Value}; fn pascal_to_snake(s: &str) -> String { let mut out = String::new(); @@ -109,6 +109,19 @@ fn idl_version_matches_cargo_package_version() { fn idl_conforms_to_official_schema() { let schema: Value = serde_json::from_str(parse_json::SCHEMA_JSON).expect("schema should be valid JSON"); + + // The bundled schema has to be the one `metadata.spec` claims to follow; + // validating against some other spec's schema would prove nothing about + // the version the IDL advertises. + let spec = IDL["metadata"]["spec"] + .as_str() + .expect("metadata.spec must be a string"); + let schema_id = schema["$id"].as_str().expect("schema $id must be a string"); + assert!( + schema_id.ends_with(&format!("v{spec}.json")), + "IDL `metadata.spec` is {spec} but the schema it's validated against is {schema_id}" + ); + let validator = jsonschema::validator_for(&schema).expect("schema should compile"); let errors: Vec = validator.iter_errors(&IDL).map(|e| e.to_string()).collect(); assert!( @@ -118,8 +131,22 @@ fn idl_conforms_to_official_schema() { ); } +/// Asserts `section[]` holds nothing beyond the `matched` entries a test just +/// cross-checked against the Rust source. Every check reads the Rust source and +/// looks for what it found in the IDL, never the other way around, so without +/// this an entry the IDL invented, or one a rename left behind, is never looked +/// at by anything. +fn confirm_no_extra_idl_entries(idl_section: Section, matched: usize) { + assert_eq!( + parse_json::section(idl_section).len(), + matched, + "IDL {idl_section}[] carries entries with no counterpart in the Rust source" + ); +} + #[test] fn idl_matches_instruction_discriminators() { + let mut matched = 0; for byte in 0u8..=255 { if let Ok(ix) = SettlementInstruction::try_from(byte) { confirm_idl_match( @@ -127,17 +154,22 @@ fn idl_matches_instruction_discriminators() { &pascal_to_snake(&format!("{ix:?}")), byte, ); + matched += 1; } } + confirm_no_extra_idl_entries(Section::Instructions, matched); } #[test] fn idl_matches_account_discriminators() { + let mut matched = 0; for byte in 0u8..=255 { if let Ok(account) = SettlementAccount::try_from(byte) { confirm_idl_match(Section::Accounts, &format!("{account:?}"), byte); + matched += 1; } } + confirm_no_extra_idl_entries(Section::Accounts, matched); } /// Cross-checks one IDL `types[]` entry against the Rust struct it describes. @@ -172,11 +204,68 @@ fn confirm_idl_types_entry( ); } +/// Cross-checks one IDL `types[]` entry against the Rust enum it describes. +/// +/// The spec's enum variants carry a name and nothing else: no discriminant, +/// since a variant's index is its wire byte, and nowhere to put docs. So the +/// variant names in order, plus the type's own docs, are the whole comparison. +fn confirm_idl_types_enum(rust_source: &parse_rust::Source, name: &str) { + let type_in_idl = parse_json::find_item(Section::Types, name) + .unwrap_or_else(|| panic!("IDL types[] must contain {name}")); + let rust_enum = rust_source.find_enum(name); + + // docs are joined and compared as one block, as they are for structs + assert_eq!( + parse_json::docs(type_in_idl, name).join(" "), + parse_rust::docs(&rust_enum.attrs).join(" "), + "documentation between rust and IDL types should be the same for {name}" + ); + + assert_eq!( + parse_json::enum_variants(type_in_idl, name), + parse_rust::enum_variants(&rust_enum), + "{name}'s IDL variants must match the Rust enum {name} in name and order" + ); + + // Position is all the IDL can say about a variant's wire value, so a Rust + // variant that pins its own discriminant has to agree with its index. + for (index, variant) in rust_enum.variants.iter().enumerate() { + let index = u64::try_from(index).expect("variant index should fit in a u64"); + if let Some(declared) = parse_rust::declared_discriminant(variant) { + assert_eq!( + declared, index, + "{name}::{} declares discriminant {declared} but sits at index {index}; the IDL \ + can only express a variant's wire value as its position", + variant.ident + ); + } + } +} + #[test] fn idl_matches_rust_types() { - confirm_idl_types_entry(&parse_rust::INTENT_RS, "OrderIntent", "OrderIntent"); - confirm_idl_types_entry(&parse_rust::ORDER_RS, "OrderAccount", "OrderAccount"); - confirm_idl_types_entry(&parse_rust::STATE_RS, "StateAccount", "SettlementState"); + // `(source, Rust name, IDL name)` of the struct types, and + // `(source, name)` of the enum types. Everything the IDL defines has to be + // listed here; the count is what catches a `types[]` entry the program has + // no definition for. + let structs = [ + (&parse_rust::INTENT_RS, "OrderIntent", "OrderIntent"), + (&parse_rust::ORDER_RS, "OrderAccount", "OrderAccount"), + (&parse_rust::STATE_RS, "StateAccount", "SettlementState"), + ]; + let enums = [ + (&parse_rust::INTENT_RS, "OrderKind"), + (&parse_rust::INTERFACE_LIB_RS, "Role"), + ]; + + for (rust_source, rust_type_name, idl_type_name) in structs { + confirm_idl_types_entry(rust_source, rust_type_name, idl_type_name); + } + for (rust_source, name) in enums { + confirm_idl_types_enum(rust_source, name); + } + + confirm_no_extra_idl_entries(Section::Types, structs.len() + enums.len()); } #[test] @@ -214,6 +303,98 @@ fn idl_matches_rust_errors() { rust_err.ident ); } + + confirm_no_extra_idl_entries(Section::Errors, rust_errors_type.variants.len()); +} + +/// Cross-checks one IDL instruction's `args[]` against the builder struct whose +/// fields become the instruction data. +/// +/// A builder carries the program id and the instruction's accounts too, so the +/// args are matched by name against a subset of its fields: each arg has to name +/// a real field, the two have to agree on type, and the args have to be ordered +/// the way the builder declares the fields, which is the order its +/// `From for Instruction` writes them to the wire. +fn confirm_idl_args_match( + rust_source: &parse_rust::Source, + builder_name: &str, + idl_instruction: &str, +) { + let idl_element = parse_json::find_item(Section::Instructions, idl_instruction) + .unwrap_or_else(|| panic!("IDL instructions[] must contain {idl_instruction}")); + let builder = rust_source.find_struct(builder_name); + let field_names = parse_rust::field_names(&builder, builder_name); + + let mut previous_arg: Option<(String, usize)> = None; + for (arg_name, idl_type) in parse_json::args(idl_element, idl_instruction) { + // panics naming the field if the builder has no such field at all + assert_eq!( + idl_type, + parse_rust::field_type(&builder, &arg_name, builder_name), + "{idl_instruction}'s arg {arg_name} must have the type {builder_name}.{arg_name} \ + declares" + ); + + let position = field_names + .iter() + .position(|field| *field == arg_name) + .expect("field_type panics before this on a field the builder doesn't declare"); + if let Some((previous_name, previous_position)) = &previous_arg { + assert!( + *previous_position < position, + "{idl_instruction} lists arg {arg_name} after {previous_name}, but {builder_name} \ + declares them the other way around; args[] is in wire order" + ); + } + previous_arg = Some((arg_name, position)); + } +} + +#[test] +fn idl_matches_instruction_args() { + confirm_idl_args_match(&parse_rust::INITIALIZE_RS, "Initialize", "initialize"); + confirm_idl_args_match(&parse_rust::BEGIN_SETTLE_RS, "BeginSettle", "begin_settle"); + confirm_idl_args_match( + &parse_rust::FINALIZE_SETTLE_RS, + "FinalizeSettle", + "finalize_settle", + ); + confirm_idl_args_match( + &parse_rust::TRANSFER_AUTHORITY_RS, + "TransferAuthority", + "transfer_authority", + ); + + // `create_order` is the one instruction whose builder doesn't mirror its + // arg: `CreateOrder` takes the intent already encoded, as + // `intent_bytes: [u8; EncodedOrderIntent::SIZE]`, where the IDL names the + // decoded type. That the two describe the same bytes is what + // `idl_matches_rust_types` checks of `OrderIntent` itself. + let create_order = parse_json::find_item(Section::Instructions, "create_order") + .expect("IDL instructions[] must contain create_order"); + assert_eq!( + parse_json::args(create_order, "create_order"), + vec![( + "intent".to_string(), + json!({ "defined": { "name": "OrderIntent" } }) + )], + "create_order takes exactly one arg, the encoded OrderIntent" + ); + let builder = parse_rust::CREATE_ORDER_RS.find_struct("CreateOrder"); + assert!( + parse_rust::field_names(&builder, "CreateOrder").contains(&"intent_bytes".to_string()), + "CreateOrder must still carry the encoded intent that create_order's `intent` arg describes" + ); + + // Instructions whose data is nothing but the discriminator byte. + for idl_instruction in ["create_buffer", "reclaim_order", "reclaim_buffer"] { + let idl_element = parse_json::find_item(Section::Instructions, idl_instruction) + .unwrap_or_else(|| panic!("IDL instructions[] must contain {idl_instruction}")); + assert!( + parse_json::args(idl_element, idl_instruction).is_empty(), + "{idl_instruction} carries no instruction data beyond its discriminator" + ); + } } #[test] diff --git a/programs/settlement/tests/idl/parse_json.rs b/programs/settlement/tests/idl/parse_json.rs index 44df647..f0532ca 100644 --- a/programs/settlement/tests/idl/parse_json.rs +++ b/programs/settlement/tests/idl/parse_json.rs @@ -96,24 +96,65 @@ pub fn discriminator(item: &Value, context: &str) -> Vec { .collect() } -/// The `(name, type)` pairs of a struct `types[]` entry, in declaration order. -pub fn struct_fields(item: &Value, context: &str) -> Vec<(String, Value)> { - item["type"]["fields"] - .as_array() - .unwrap_or_else(|| panic!("struct type {context} should have a fields array")) +/// The `(name, type)` pairs of an array of `{"name", "type"}` objects, in +/// declaration order. `types[]` fields and `instructions[]` args share this +/// shape. +fn name_type_pairs(entries: &[Value], context: &str) -> Vec<(String, Value)> { + entries .iter() - .map(|field| { + .map(|entry| { ( - field["name"] + entry["name"] .as_str() - .unwrap_or_else(|| panic!("field name in {context} must be a string")) + .unwrap_or_else(|| panic!("entry name in {context} must be a string")) .to_string(), - field["type"].clone(), + entry["type"].clone(), ) }) .collect() } +/// The `(name, type)` pairs of a struct `types[]` entry, in declaration order. +pub fn struct_fields(item: &Value, context: &str) -> Vec<(String, Value)> { + name_type_pairs( + item["type"]["fields"] + .as_array() + .unwrap_or_else(|| panic!("struct type {context} should have a fields array")), + context, + ) +} + +/// The `(name, type)` pairs of an `instructions[]` entry's `args`, in wire +/// order. An absent `args` reads as no arguments at all, which is how the IDL +/// spells an instruction whose data is just the discriminator. +pub fn args(item: &Value, context: &str) -> Vec<(String, Value)> { + let Some(args) = item.get("args") else { + return Vec::new(); + }; + name_type_pairs( + args.as_array() + .unwrap_or_else(|| panic!("args for {context} should be an array")), + context, + ) +} + +/// The variant names of an enum `types[]` entry, in declaration order, which is +/// the order the wire discriminant counts in. The spec's `IdlEnumVariant` has +/// nowhere to put per-variant docs, so there's nothing else here to compare. +pub fn enum_variants(item: &Value, context: &str) -> Vec { + item["type"]["variants"] + .as_array() + .unwrap_or_else(|| panic!("enum type {context} should have a variants array")) + .iter() + .map(|variant| { + variant["name"] + .as_str() + .unwrap_or_else(|| panic!("variant name in {context} must be a string")) + .to_string() + }) + .collect() +} + /// Every `{"kind": "const"}` seed byte string anywhere below `values`. pub fn const_seeds(values: &[Value]) -> Vec> { fn collect(value: &Value, out: &mut Vec>) { diff --git a/programs/settlement/tests/idl/parse_rust.rs b/programs/settlement/tests/idl/parse_rust.rs index f3bef5a..d187427 100644 --- a/programs/settlement/tests/idl/parse_rust.rs +++ b/programs/settlement/tests/idl/parse_rust.rs @@ -35,6 +35,31 @@ pub const STATE_RS: Source = Source { text: include_str!("../../../../interface/src/data/state.rs"), }; +pub const INITIALIZE_RS: Source = Source { + display: "interface/src/instruction/initialize.rs", + text: include_str!("../../../../interface/src/instruction/initialize.rs"), +}; + +pub const CREATE_ORDER_RS: Source = Source { + display: "interface/src/instruction/create_order.rs", + text: include_str!("../../../../interface/src/instruction/create_order.rs"), +}; + +pub const BEGIN_SETTLE_RS: Source = Source { + display: "interface/src/instruction/settle/begin.rs", + text: include_str!("../../../../interface/src/instruction/settle/begin.rs"), +}; + +pub const FINALIZE_SETTLE_RS: Source = Source { + display: "interface/src/instruction/settle/finalize.rs", + text: include_str!("../../../../interface/src/instruction/settle/finalize.rs"), +}; + +pub const TRANSFER_AUTHORITY_RS: Source = Source { + display: "interface/src/instruction/transfer_authority.rs", + text: include_str!("../../../../interface/src/instruction/transfer_authority.rs"), +}; + impl Source { fn parse(&self) -> syn::File { syn::parse_file(self.text) @@ -115,9 +140,9 @@ pub fn type_to_idl(ty: &syn::Type, context: &str) -> Value { } } -/// The `= N` discriminant an enum variant declares. Every enum the IDL mirrors -/// pins its wire values explicitly, so a missing or computed one is a bug. -pub fn discriminant(variant: &syn::Variant) -> u64 { +/// The `= N` discriminant an enum variant declares, or `None` where it leans on +/// the implicit "one past the previous variant" value. +pub fn declared_discriminant(variant: &syn::Variant) -> Option { match &variant.discriminant { Some(( _, @@ -125,17 +150,24 @@ pub fn discriminant(variant: &syn::Variant) -> u64 { lit: syn::Lit::Int(i), .. }), - )) => i.base10_parse().unwrap_or_else(|err| { + )) => Some(i.base10_parse().unwrap_or_else(|err| { panic!( "discriminant on {} must be an unsigned integer literal: {err}", variant.ident ) - }), + })), Some(_) => panic!("unexpected non-literal discriminant on {}", variant.ident), - None => panic!("discriminant should be defined on {}", variant.ident), + None => None, } } +/// The `= N` discriminant an enum variant declares. The discriminator enums the +/// IDL mirrors pin their wire values explicitly, so a missing one is a bug. +pub fn discriminant(variant: &syn::Variant) -> u64 { + declared_discriminant(variant) + .unwrap_or_else(|| panic!("discriminant should be defined on {}", variant.ident)) +} + /// The `(name, type)` pairs of a struct's fields, in declaration order, with /// each type already translated into the IDL's type grammar. pub fn struct_fields(rust_struct: &syn::ItemStruct, context: &str) -> Vec<(String, Value)> { @@ -154,17 +186,88 @@ pub fn struct_fields(rust_struct: &syn::ItemStruct, context: &str) -> Vec<(Strin .collect() } +/// The names of a struct's fields, in declaration order. Unlike +/// [`struct_fields`] this translates no types, so it reads structs carrying +/// fields the IDL's type grammar has no equivalent for. +pub fn field_names(rust_struct: &syn::ItemStruct, context: &str) -> Vec { + rust_struct + .fields + .iter() + .map(|field| { + field + .ident + .as_ref() + .unwrap_or_else(|| panic!("{context} should have named fields")) + .to_string() + }) + .collect() +} + +/// One named field's type, translated into the IDL's type grammar. +pub fn field_type(rust_struct: &syn::ItemStruct, name: &str, context: &str) -> Value { + let field = rust_struct + .fields + .iter() + .find(|field| field.ident.as_ref().is_some_and(|ident| ident == name)) + .unwrap_or_else(|| panic!("{context} should have a field named {name}")); + type_to_idl(&field.ty, &format!("{context}.{name}")) +} + +/// The variant names of an enum, in declaration order. +pub fn enum_variants(rust_enum: &syn::ItemEnum) -> Vec { + rust_enum + .variants + .iter() + .map(|variant| variant.ident.to_string()) + .collect() +} + +/// Unwraps rustdoc intra-doc links to the text they display: `[`Role`](Role)` +/// reads as `Role`. The IDL has no notion of a link target, so carrying one +/// there would only be Rust markup leaking into the published interface. +fn strip_doc_links(text: &str) -> String { + /// The display text and the remainder past `[display](target)`, when `text` + /// starts with a link whose two halves nest no brackets of their own. + /// Anything else isn't a link and is left exactly as written. + fn split_link(text: &str) -> Option<(&str, &str)> { + let (display, after_display) = text.strip_prefix('[')?.split_once("](")?; + let (target, after_link) = after_display.split_once(')')?; + (!display.contains('[') && !target.contains('(')).then_some((display, after_link)) + } + + let mut out = String::with_capacity(text.len()); + let mut rest = text; + while let Some(open) = rest.find('[') { + out.push_str(&rest[..open]); + rest = &rest[open..]; + match split_link(rest) { + Some((display, after_link)) => { + out.push_str(display); + rest = after_link; + } + None => { + out.push('['); + rest = &rest[1..]; + } + } + } + out.push_str(rest); + out +} + /// Collapses doc lines into the single line the IDL carries them as, dropping -/// the backtick markup the IDL only carries in some places. Both this module -/// and [`crate::parse_json`] hand their doc text through here, so the two sides -/// are always compared in the same form. +/// the backtick and link markup the IDL only carries in some places. Both this +/// module and [`crate::parse_json`] hand their doc text through here, so the two +/// sides are always compared in the same form. pub fn normalize_doc>(lines: &[S]) -> String { - lines - .iter() - .map(AsRef::as_ref) - .collect::>() - .join(" ") - .replace('`', "") + strip_doc_links( + &lines + .iter() + .map(AsRef::as_ref) + .collect::>() + .join(" ") + .replace('`', ""), + ) } /// Extract the doc text from a single attribute line in Rust From 0ae07e2df200abe2934a93223574780a2e3e626f Mon Sep 17 00:00:00 2001 From: Kaze <230549489+kaze-cow@users.noreply.github.com> Date: Mon, 24 Aug 2026 23:52:12 +0900 Subject: [PATCH 16/43] rethink how the testing structure works it increases the amount of code overall, but it puts us in the right trajectory to be effectively generating parts of the IDL from rust. --- programs/settlement/tests/idl/generate.rs | 337 +++++++++++++++ programs/settlement/tests/idl/main.rs | 432 +++----------------- programs/settlement/tests/idl/parse_json.rs | 186 --------- programs/settlement/tests/idl/parse_rust.rs | 164 ++++---- programs/settlement/tests/idl/superset.rs | 215 ++++++++++ 5 files changed, 682 insertions(+), 652 deletions(-) create mode 100644 programs/settlement/tests/idl/generate.rs delete mode 100644 programs/settlement/tests/idl/parse_json.rs create mode 100644 programs/settlement/tests/idl/superset.rs diff --git a/programs/settlement/tests/idl/generate.rs b/programs/settlement/tests/idl/generate.rs new file mode 100644 index 0000000..c918efa --- /dev/null +++ b/programs/settlement/tests/idl/generate.rs @@ -0,0 +1,337 @@ +//! Assembles the partial IDL the Rust source implies. +//! +//! Everything here reads the program's own source through [`crate::parse_rust`] +//! and emits it in the IDL spec's JSON grammar, producing a document shaped +//! exactly like `idl/cow_settlement.json` but carrying only the facts the +//! source pins. Whatever the source can't state — an instruction's account +//! list, the prose describing each argument, the `metadata` blurbs — is simply +//! left out, and [`crate::superset`] is what says the checked-in IDL has to +//! agree with everything that _is_ here. +//! +//! The tables below are the one place a name has to be written twice. They +//! exist because nothing in the Rust source says which file holds an +//! instruction's parsed input, which struct backs a `types[]` entry, or which +//! of an instruction's accounts the IDL derives as a PDA. + +use cow_settlement_interface::{ + pda::{buffer::BUFFER_SEED, SETTLEMENT_SEED}, + SettlementInstruction, +}; +use serde_json::{json, Map, Value}; + +use crate::parse_rust::{self, Source}; + +/// One seed of a PDA account, as the IDL spells it. +enum Seed { + /// Bytes pinned by a constant in `interface::pda`. + Const(&'static [u8]), + /// Another of the instruction's accounts, named the way the IDL names it. + Account(&'static str), +} + +impl Seed { + fn to_idl(&self) -> Value { + match self { + Self::Const(bytes) => json!({ "kind": "const", "value": bytes }), + Self::Account(path) => json!({ "kind": "account", "path": path }), + } + } +} + +/// The canonical settlement state PDA, seeded by the version-stamped prefix +/// alone. +const STATE_PDA: &[Seed] = &[Seed::Const(SETTLEMENT_SEED)]; + +/// A per-token buffer PDA. The IDL can only declare the guaranteed index-0 +/// buffer of the unbounded run an instruction actually accepts, so the mint it +/// derives from is `mint_0`. +const BUFFER_PDA_0: &[Seed] = &[ + Seed::Const(SETTLEMENT_SEED), + Seed::Account("mint_0"), + Seed::Const(BUFFER_SEED), +]; + +/// What the Rust source doesn't say about one instruction. +struct Instruction { + /// The discriminator variant naming it. The IDL calls the instruction by + /// this name in `snake_case`. + variant: SettlementInstruction, + /// The file declaring `Input`, the struct [`args`] reads. + input: &'static Source, + /// The accounts the IDL declares a `pda` for, and the seeds that PDA is + /// derived from. Accounts without one aren't listed: nothing in the Rust + /// source pins the name the IDL gives them. + pda_accounts: &'static [(&'static str, &'static [Seed])], +} + +const INSTRUCTIONS: &[Instruction] = &[ + Instruction { + variant: SettlementInstruction::Initialize, + input: &parse_rust::INITIALIZE_RS, + pda_accounts: &[("state_pda", STATE_PDA)], + }, + Instruction { + variant: SettlementInstruction::CreateBuffer, + input: &parse_rust::CREATE_BUFFER_RS, + pda_accounts: &[("buffer_pda_0", BUFFER_PDA_0)], + }, + Instruction { + variant: SettlementInstruction::CreateOrder, + input: &parse_rust::CREATE_ORDER_RS, + // `order_pda`'s canonical seeds include `sha256(intent)`, which the IDL + // has no `seeds` kind for; create_order's docs say so instead. + pda_accounts: &[], + }, + Instruction { + variant: SettlementInstruction::BeginSettle, + input: &parse_rust::BEGIN_SETTLE_RS, + // `state_pda` is passed as a plain account here rather than derived: + // BeginSettle checks it against the canonical address itself. + pda_accounts: &[], + }, + Instruction { + variant: SettlementInstruction::FinalizeSettle, + input: &parse_rust::FINALIZE_SETTLE_RS, + pda_accounts: &[], + }, + Instruction { + variant: SettlementInstruction::ReclaimOrder, + input: &parse_rust::RECLAIM_ORDER_RS, + pda_accounts: &[], + }, + Instruction { + variant: SettlementInstruction::ReclaimBuffer, + input: &parse_rust::RECLAIM_BUFFER_RS, + pda_accounts: &[("state_pda", STATE_PDA), ("buffer_pda_0", BUFFER_PDA_0)], + }, + Instruction { + variant: SettlementInstruction::TransferAuthority, + input: &parse_rust::TRANSFER_AUTHORITY_RS, + pda_accounts: &[("state_pda", STATE_PDA)], + }, +]; + +/// The struct types the IDL defines, as `(source, Rust name, IDL name)`. The +/// two names don't always agree: `StateAccount` is called `SettlementState` in +/// the IDL, matching the `SettlementAccount` variant that names the account. +const STRUCT_TYPES: &[(&Source, &str, &str)] = &[ + (&parse_rust::ORDER_RS, "OrderAccount", "OrderAccount"), + (&parse_rust::STATE_RS, "StateAccount", "SettlementState"), + (&parse_rust::INTENT_RS, "OrderIntent", "OrderIntent"), +]; + +/// The enum types the IDL defines, as `(source, name)`. +pub const ENUM_TYPES: &[(&Source, &str)] = &[ + (&parse_rust::INTENT_RS, "OrderKind"), + (&parse_rust::INTERFACE_LIB_RS, "Role"), +]; + +/// The enum whose variants are the IDL's `errors[]`. +const ERRORS: &str = "SettlementError"; + +/// `BeginSettle` reads as `begin_settle`: the IDL names instructions the way +/// Rust names functions, where the discriminator enum names them as variants. +fn pascal_to_snake(s: &str) -> String { + let mut out = String::new(); + for (i, c) in s.chars().enumerate() { + if c.is_uppercase() { + if i != 0 { + out.push('_'); + } + out.extend(c.to_lowercase()); + } else { + out.push(c); + } + } + out +} + +/// Generate an incomplete IDL document based on the Rust source. +pub fn partial_idl() -> Value { + json!({ + "address": cow_settlement_interface::ID.to_string(), + "metadata": { + // Bumping the minor version also moves every PDA, so a stale value + // here hides that. + "version": env!("CARGO_PKG_VERSION"), + }, + "instructions": instructions(), + "accounts": accounts(), + "types": types(), + "errors": errors(), + }) +} + +/// One entry per `SettlementInstruction` variant, in discriminator order. +fn instructions() -> Vec { + discriminator_variants(&parse_rust::INTERFACE_LIB_RS.find_enum("SettlementInstruction")) + .map(|(byte, variant)| { + let instruction = INSTRUCTIONS + .iter() + .find(|instruction| instruction.variant.discriminator() == byte) + .unwrap_or_else(|| { + panic!( + "SettlementInstruction::{} is missing from INSTRUCTIONS", + variant.ident + ) + }); + + let mut entry = Map::new(); + entry.insert( + "name".into(), + json!(pascal_to_snake(&variant.ident.to_string())), + ); + insert_docs(&mut entry, parse_rust::docs(&variant.attrs)); + entry.insert("discriminator".into(), json!([byte])); + if !instruction.pda_accounts.is_empty() { + entry.insert("accounts".into(), pda_accounts(instruction)); + } + entry.insert("args".into(), args(instruction, &variant.ident.to_string())); + Value::Object(entry) + }) + .collect() +} + +/// The `accounts[]` entries an instruction derives as PDAs, each carrying only +/// its name and its seeds. +fn pda_accounts(instruction: &Instruction) -> Value { + let accounts: Vec = instruction + .pda_accounts + .iter() + .map(|(name, seeds)| { + let seeds: Vec = seeds.iter().map(Seed::to_idl).collect(); + json!({ "name": name, "pda": { "seeds": seeds } }) + }) + .collect(); + Value::Array(accounts) +} + +/// An instruction's `args[]`, read off its `Input` struct. +/// +/// That struct is the closest thing the source has to `args[]`: its fields are +/// what a handler gets after parsing, holding the borrowed accounts (`&'a A`) +/// and the trailing repeated groups next to the values the instruction data +/// carries, in the order the data carries them. Dropping every field whose type +/// the IDL's grammar can't name leaves exactly the arguments — with one +/// exception, [`arg_alias`]. +fn args(instruction: &Instruction, variant: &str) -> Value { + let input_name = format!("{variant}Input"); + let input = instruction.input.find_struct(&input_name); + + let args: Vec = input + .fields + .iter() + .filter_map(|field| { + let name = parse_rust::field_name(field, &input_name); + let (name, ty) = match arg_override(instruction.variant, &name) { + Some(aliased) => aliased, + None => (name, parse_rust::try_type_to_idl(&field.ty)?), + }; + Some(json!({ "name": name, "type": ty })) + }) + .collect(); + Value::Array(args) +} + +/// In cases where the IDL needs to differ from the rust code, an override can be set here. +fn arg_override(variant: SettlementInstruction, field: &str) -> Option<(String, Value)> { + match (variant, field) { + (SettlementInstruction::CreateOrder, "intent_bytes") => Some(( + "intent".to_string(), + json!({ "defined": { "name": "OrderIntent" } }), + )), + _ => None, + } +} + +/// One entry per `SettlementAccount` variant, in discriminator order. +fn accounts() -> Vec { + discriminator_variants(&parse_rust::INTERFACE_LIB_RS.find_enum("SettlementAccount")) + .map(|(byte, variant)| { + let mut entry = Map::new(); + entry.insert("name".into(), json!(variant.ident.to_string())); + insert_docs(&mut entry, parse_rust::docs(&variant.attrs)); + entry.insert("discriminator".into(), json!([byte])); + Value::Object(entry) + }) + .collect() +} + +/// One `types[]` entry per struct and enum in the tables above. +fn types() -> Vec { + let structs = STRUCT_TYPES.iter().map(|(source, rust_name, idl_name)| { + let rust_struct = source.find_struct(rust_name); + type_entry( + idl_name, + parse_rust::docs(&rust_struct.attrs), + parse_rust::struct_type(&rust_struct, rust_name), + ) + }); + let enums = ENUM_TYPES.iter().map(|(source, name)| { + let rust_enum = source.find_enum(name); + type_entry( + name, + parse_rust::docs(&rust_enum.attrs), + parse_rust::enum_type(&rust_enum), + ) + }); + structs.chain(enums).collect() +} + +fn type_entry(idl_name: &str, docs: Vec, ty: Value) -> Value { + let mut entry = Map::new(); + entry.insert("name".into(), json!(idl_name)); + insert_docs(&mut entry, docs); + entry.insert("type".into(), ty); + Value::Object(entry) +} + +/// One `errors[]` entry per [`ERRORS`] variant. A variant's discriminant is the +/// `ProgramError::Custom` code the program returns, and its doc comment is the +/// message the IDL publishes for that code. +fn errors() -> Vec { + parse_rust::INTERFACE_LIB_RS + .find_enum(ERRORS) + .variants + .iter() + .map(|variant| { + json!({ + "code": parse_rust::discriminant(variant), + "name": variant.ident.to_string(), + "msg": parse_rust::normalize_doc(&parse_rust::docs(&variant.attrs)), + }) + }) + .collect() +} + +// --------------------------------------------------------------------------- +// Helpers +// --------------------------------------------------------------------------- + +/// The variants of a discriminator enum paired with their wire byte, in +/// discriminator order. +fn discriminator_variants( + rust_enum: &syn::ItemEnum, +) -> impl Iterator + '_ { + let mut variants: Vec<(u8, &syn::Variant)> = rust_enum + .variants + .iter() + .map(|variant| { + let byte = parse_rust::discriminant(variant); + let byte = + u8::try_from(byte).unwrap_or_else(|_| panic!("{} must fit in a u8", variant.ident)); + (byte, variant) + }) + .collect(); + variants.sort_by_key(|(byte, _)| *byte); + variants.into_iter() +} + +/// Records `docs` on an entry, leaving the key out entirely when the Rust +/// source documents nothing. An empty `docs` would claim the IDL must say +/// nothing either, which is the opposite of what a missing doc comment means. +fn insert_docs(entry: &mut Map, docs: Vec) { + if !docs.is_empty() { + entry.insert("docs".into(), json!(docs)); + } +} diff --git a/programs/settlement/tests/idl/main.rs b/programs/settlement/tests/idl/main.rs index cea64d2..31ff063 100644 --- a/programs/settlement/tests/idl/main.rs +++ b/programs/settlement/tests/idl/main.rs @@ -1,75 +1,44 @@ //! IDL correctness tests for `programs/settlement/idl/cow_settlement.json`. //! //! This program is a native Pinocchio program with a hand-written IDL (no -//! `anchor idl build`/shank step keeps it in sync), so these tests -//! cross-check the checked-in file against the Rust source it describes. +//! `anchor idl build`/shank step keeps it in sync), so these tests cross-check +//! the checked-in file against the Rust source it describes. //! -//! [`parse_json`] reads the IDL and [`parse_rust`] reads the Rust source; the -//! tests here only compare what the two report. +//! The cross-check runs in one direction. [`parse_rust`] reads the program's +//! source, [`generate`] assembles what it finds into a partial IDL — a document +//! shaped like the real one, carrying only the facts the source pins — and +//! [`superset`] asserts the checked-in file states all of them. Every run also +//! writes that generated document next to the build output, so a failure can be +//! read as a diff rather than as a list of assertions. +//! +//! The remaining tests here are the ones with no Rust-side counterpart at all: +//! the file has to be valid, canonically formatted JSON, and it has to satisfy +//! the IDL spec's own schema. -mod parse_json; +mod generate; mod parse_rust; +mod superset; -use std::collections::BTreeSet; - -use cow_settlement_interface::{ - pda::{buffer::BUFFER_SEED, order::ORDER_SEED, SETTLEMENT_SEED}, - SettlementAccount, SettlementInstruction, -}; -use parse_json::{Section, IDL}; -use serde_json::{json, Value}; - -fn pascal_to_snake(s: &str) -> String { - let mut out = String::new(); - for (i, c) in s.chars().enumerate() { - if c.is_uppercase() { - if i != 0 { - out.push('_'); - } - out.extend(c.to_lowercase()); - } else { - out.push(c); - } - } - out -} +use std::{fs, path::PathBuf, sync::LazyLock}; -fn confirm_idl_match(idl_section: Section, idl_name: &str, discriminator_byte: u8) { - let idl_element = parse_json::find_item(idl_section, idl_name) - .unwrap_or_else(|| panic!("IDL does not contain defined settlement element {idl_name}")); +use serde_json::Value; - // confirm the discriminator matches - assert_eq!( - parse_json::discriminator(idl_element, idl_name), - vec![discriminator_byte], - "IDL discriminator for {idl_name} should be the single byte the code uses" - ); - - // confirm the docs match: everything the Rust enum variant documents must - // show up, in order, in the IDL element's docs. The IDL is allowed to say - // more than the Rust source does; it carries notes about what its own - // grammar can't express (`begin_settle`'s dynamically-shaped tail, for - // one), which have no business being in the program's own docs. - let idl_docs = parse_json::docs(idl_element, idl_name); - let rust_docs = parse_rust::discriminator_variant_docs(idl_section, discriminator_byte); - - let mut unmatched_idl_docs = idl_docs.iter(); - for rust_doc in &rust_docs { - assert!( - unmatched_idl_docs.any(|idl_doc| idl_doc == rust_doc), - "IDL docs for {idl_name} don't document what the Rust source does; missing (or \ - out of order) paragraph:\n{rust_doc}\nIDL docs are:\n{idl_docs:#?}" - ); - } -} +const IDL_JSON: &str = include_str!("../../idl/cow_settlement.json"); +const SCHEMA_JSON: &str = include_str!("../../idl/schema/idl-spec-v0.1.0.json"); -// --------------------------------------------------------------------------- -// JSON validity and formatting -// --------------------------------------------------------------------------- +static IDL: LazyLock = + LazyLock::new(|| serde_json::from_str(IDL_JSON).expect("IDL must be valid JSON")); -#[test] -fn idl_is_valid_json() { - let _ = &*IDL; +/// Where [`idl_states_everything_the_rust_source_does`] leaves the document it +/// generated, for reading by hand when the assertion it drives fails. +/// +/// `CARGO_TARGET_TMPDIR` is `target/tmp`, so its parent is the target directory +/// wherever cargo put it. +fn generated_idl_path() -> PathBuf { + PathBuf::from(env!("CARGO_TARGET_TMPDIR")) + .parent() + .expect("CARGO_TARGET_TMPDIR lives inside the target directory") + .join("generated_cow_settlement_idl.json") } #[test] @@ -77,38 +46,15 @@ fn idl_is_pretty_formatted() { let mut formatted = serde_json::to_string_pretty(&*IDL).expect("IDL JSON should re-serialize"); formatted.push('\n'); assert_eq!( - formatted, - parse_json::IDL_JSON, + formatted, IDL_JSON, "IDL isn't canonically formatted; regenerate it with `serde_json::to_string_pretty` \ plus a trailing newline" ); } -#[test] -fn idl_address_matches_declared_program_id() { - assert_eq!( - IDL["address"].as_str().expect("address must be a string"), - cow_settlement_interface::ID.to_string(), - "IDL `address` must match the program id declared via declare_id! in interface/src/lib.rs" - ); -} - -#[test] -fn idl_version_matches_cargo_package_version() { - assert_eq!( - IDL["metadata"]["version"] - .as_str() - .expect("metadata.version must be a string"), - env!("CARGO_PKG_VERSION"), - "IDL `metadata.version` must match the settlement program's cargo package version; \ - bumping the minor version also moves every PDA, so a stale value here hides that" - ); -} - #[test] fn idl_conforms_to_official_schema() { - let schema: Value = - serde_json::from_str(parse_json::SCHEMA_JSON).expect("schema should be valid JSON"); + let schema: Value = serde_json::from_str(SCHEMA_JSON).expect("schema should be valid JSON"); // The bundled schema has to be the one `metadata.spec` claims to follow; // validating against some other spec's schema would prove nothing about @@ -131,298 +77,40 @@ fn idl_conforms_to_official_schema() { ); } -/// Asserts `section[]` holds nothing beyond the `matched` entries a test just -/// cross-checked against the Rust source. Every check reads the Rust source and -/// looks for what it found in the IDL, never the other way around, so without -/// this an entry the IDL invented, or one a rename left behind, is never looked -/// at by anything. -fn confirm_no_extra_idl_entries(idl_section: Section, matched: usize) { - assert_eq!( - parse_json::section(idl_section).len(), - matched, - "IDL {idl_section}[] carries entries with no counterpart in the Rust source" - ); -} - -#[test] -fn idl_matches_instruction_discriminators() { - let mut matched = 0; - for byte in 0u8..=255 { - if let Ok(ix) = SettlementInstruction::try_from(byte) { - confirm_idl_match( - Section::Instructions, - &pascal_to_snake(&format!("{ix:?}")), - byte, - ); - matched += 1; - } - } - confirm_no_extra_idl_entries(Section::Instructions, matched); -} - +/// The one test that compares the two sides directly. Everything the Rust source says +/// about the program's interface has to be in the checked-in IDL, said the same +/// way; what the source can't say, the IDL is free to fill in. #[test] -fn idl_matches_account_discriminators() { - let mut matched = 0; - for byte in 0u8..=255 { - if let Ok(account) = SettlementAccount::try_from(byte) { - confirm_idl_match(Section::Accounts, &format!("{account:?}"), byte); - matched += 1; - } - } - confirm_no_extra_idl_entries(Section::Accounts, matched); -} +fn idl_matches_everything_generated_from_rust() { + let generated = generate::partial_idl(); -/// Cross-checks one IDL `types[]` entry against the Rust struct it describes. -/// -/// `idl_name` is passed separately because the two don't always agree: -/// `StateAccount` is called `SettlementState` in the IDL, matching the -/// `SettlementAccount` discriminator variant that names the account. -fn confirm_idl_types_entry( - rust_source: &parse_rust::Source, - rust_type_name: &str, - idl_type_name: &str, -) { - // load in the idl and rust type definitions - let type_in_idl = parse_json::find_item(Section::Types, idl_type_name) - .unwrap_or_else(|| panic!("IDL types[] must contain {idl_type_name}")); - let rust_struct = rust_source.find_struct(rust_type_name); - - // confirm the docs match. `types[]` carries one docs entry per source - // line where `instructions[]` carries one per paragraph, so both sides are - // compared as a single joined block: same prose, wrapping not load-bearing. - assert_eq!( - parse_json::docs(type_in_idl, idl_type_name).join(" "), - parse_rust::docs(&rust_struct.attrs).join(" "), - "documentation between rust and IDL types should be the same for {rust_type_name} and {idl_type_name}" - ); + let path = generated_idl_path(); + let mut json = serde_json::to_string_pretty(&generated).expect("generated IDL must serialize"); + json.push('\n'); + fs::write(&path, &json) + .unwrap_or_else(|err| panic!("{} must be writable: {err}", path.display())); + println!("generated IDL written to {}", path.display()); - // confirm fields match, both in name/order and in type - assert_eq!( - parse_json::struct_fields(type_in_idl, idl_type_name), - parse_rust::struct_fields(&rust_struct, idl_type_name), - "{idl_type_name}'s IDL fields must match the Rust struct {idl_type_name} in name, order and type" - ); -} - -/// Cross-checks one IDL `types[]` entry against the Rust enum it describes. -/// -/// The spec's enum variants carry a name and nothing else: no discriminant, -/// since a variant's index is its wire byte, and nowhere to put docs. So the -/// variant names in order, plus the type's own docs, are the whole comparison. -fn confirm_idl_types_enum(rust_source: &parse_rust::Source, name: &str) { - let type_in_idl = parse_json::find_item(Section::Types, name) - .unwrap_or_else(|| panic!("IDL types[] must contain {name}")); - let rust_enum = rust_source.find_enum(name); - - // docs are joined and compared as one block, as they are for structs - assert_eq!( - parse_json::docs(type_in_idl, name).join(" "), - parse_rust::docs(&rust_enum.attrs).join(" "), - "documentation between rust and IDL types should be the same for {name}" - ); - - assert_eq!( - parse_json::enum_variants(type_in_idl, name), - parse_rust::enum_variants(&rust_enum), - "{name}'s IDL variants must match the Rust enum {name} in name and order" - ); - - // Position is all the IDL can say about a variant's wire value, so a Rust - // variant that pins its own discriminant has to agree with its index. - for (index, variant) in rust_enum.variants.iter().enumerate() { - let index = u64::try_from(index).expect("variant index should fit in a u64"); - if let Some(declared) = parse_rust::declared_discriminant(variant) { - assert_eq!( - declared, index, - "{name}::{} declares discriminant {declared} but sits at index {index}; the IDL \ - can only express a variant's wire value as its position", - variant.ident - ); - } - } -} - -#[test] -fn idl_matches_rust_types() { - // `(source, Rust name, IDL name)` of the struct types, and - // `(source, name)` of the enum types. Everything the IDL defines has to be - // listed here; the count is what catches a `types[]` entry the program has - // no definition for. - let structs = [ - (&parse_rust::INTENT_RS, "OrderIntent", "OrderIntent"), - (&parse_rust::ORDER_RS, "OrderAccount", "OrderAccount"), - (&parse_rust::STATE_RS, "StateAccount", "SettlementState"), - ]; - let enums = [ - (&parse_rust::INTENT_RS, "OrderKind"), - (&parse_rust::INTERFACE_LIB_RS, "Role"), - ]; - - for (rust_source, rust_type_name, idl_type_name) in structs { - confirm_idl_types_entry(rust_source, rust_type_name, idl_type_name); - } - for (rust_source, name) in enums { - confirm_idl_types_enum(rust_source, name); - } - - confirm_no_extra_idl_entries(Section::Types, structs.len() + enums.len()); + superset::assert_superset(&generated, &IDL); } +/// The IDL spec can only express a variant's wire value as its position, so a +/// Rust variant that pins its own discriminant has to agree with its index. +/// Nothing in the generated document can carry this: it's a fact about the Rust +/// enum, checked so the `variants[]` the IDL does carry mean what they say. #[test] -fn idl_matches_rust_errors() { - let rust_errors_type = parse_rust::INTERFACE_LIB_RS.find_enum("SettlementError"); - - for rust_err in &rust_errors_type.variants { - let idl_err = parse_json::find_item(Section::Errors, &rust_err.ident.to_string()) - .unwrap_or_else(|| { - panic!( - "Settlement program error {} is not defined in IDL errors[]", - rust_err.ident - ) - }); - - // the idl error's "code" should match up - let idl_code = idl_err["code"] - .as_u64() - .expect("code should be correct type"); - - assert_eq!( - idl_code, - parse_rust::discriminant(rust_err), - "IDL errors[] name={} should match the code in rust", - rust_err.ident - ); - - // the idl error's "msg" should match up - let rust_msg = parse_rust::docs(&rust_err.attrs).join(" "); - let idl_msg = idl_err["msg"].as_str().expect("msg must be a string"); - - assert_eq!( - idl_msg, rust_msg, - "IDL errors[] name={} should match informational msg", - rust_err.ident - ); - } - - confirm_no_extra_idl_entries(Section::Errors, rust_errors_type.variants.len()); -} - -/// Cross-checks one IDL instruction's `args[]` against the builder struct whose -/// fields become the instruction data. -/// -/// A builder carries the program id and the instruction's accounts too, so the -/// args are matched by name against a subset of its fields: each arg has to name -/// a real field, the two have to agree on type, and the args have to be ordered -/// the way the builder declares the fields, which is the order its -/// `From for Instruction` writes them to the wire. -fn confirm_idl_args_match( - rust_source: &parse_rust::Source, - builder_name: &str, - idl_instruction: &str, -) { - let idl_element = parse_json::find_item(Section::Instructions, idl_instruction) - .unwrap_or_else(|| panic!("IDL instructions[] must contain {idl_instruction}")); - let builder = rust_source.find_struct(builder_name); - let field_names = parse_rust::field_names(&builder, builder_name); - - let mut previous_arg: Option<(String, usize)> = None; - for (arg_name, idl_type) in parse_json::args(idl_element, idl_instruction) { - // panics naming the field if the builder has no such field at all - assert_eq!( - idl_type, - parse_rust::field_type(&builder, &arg_name, builder_name), - "{idl_instruction}'s arg {arg_name} must have the type {builder_name}.{arg_name} \ - declares" - ); - - let position = field_names - .iter() - .position(|field| *field == arg_name) - .expect("field_type panics before this on a field the builder doesn't declare"); - if let Some((previous_name, previous_position)) = &previous_arg { - assert!( - *previous_position < position, - "{idl_instruction} lists arg {arg_name} after {previous_name}, but {builder_name} \ - declares them the other way around; args[] is in wire order" - ); +fn enum_type_discriminants_match_variant_order() { + for (source, name) in generate::ENUM_TYPES { + for (index, variant) in source.find_enum(name).variants.iter().enumerate() { + let index = u64::try_from(index).expect("variant index should fit in a u64"); + if let Some(declared) = parse_rust::declared_discriminant(variant) { + assert_eq!( + declared, index, + "{name}::{} declares discriminant {declared} but sits at index {index}; the \ + IDL can only express a variant's wire value as its position", + variant.ident + ); + } } - previous_arg = Some((arg_name, position)); - } -} - -#[test] -fn idl_matches_instruction_args() { - confirm_idl_args_match(&parse_rust::INITIALIZE_RS, "Initialize", "initialize"); - confirm_idl_args_match(&parse_rust::BEGIN_SETTLE_RS, "BeginSettle", "begin_settle"); - confirm_idl_args_match( - &parse_rust::FINALIZE_SETTLE_RS, - "FinalizeSettle", - "finalize_settle", - ); - confirm_idl_args_match( - &parse_rust::TRANSFER_AUTHORITY_RS, - "TransferAuthority", - "transfer_authority", - ); - - // `create_order` is the one instruction whose builder doesn't mirror its - // arg: `CreateOrder` takes the intent already encoded, as - // `intent_bytes: [u8; EncodedOrderIntent::SIZE]`, where the IDL names the - // decoded type. That the two describe the same bytes is what - // `idl_matches_rust_types` checks of `OrderIntent` itself. - let create_order = parse_json::find_item(Section::Instructions, "create_order") - .expect("IDL instructions[] must contain create_order"); - assert_eq!( - parse_json::args(create_order, "create_order"), - vec![( - "intent".to_string(), - json!({ "defined": { "name": "OrderIntent" } }) - )], - "create_order takes exactly one arg, the encoded OrderIntent" - ); - let builder = parse_rust::CREATE_ORDER_RS.find_struct("CreateOrder"); - assert!( - parse_rust::field_names(&builder, "CreateOrder").contains(&"intent_bytes".to_string()), - "CreateOrder must still carry the encoded intent that create_order's `intent` arg describes" - ); - - // Instructions whose data is nothing but the discriminator byte. - for idl_instruction in ["create_buffer", "reclaim_order", "reclaim_buffer"] { - let idl_element = parse_json::find_item(Section::Instructions, idl_instruction) - .unwrap_or_else(|| panic!("IDL instructions[] must contain {idl_instruction}")); - assert!( - parse_json::args(idl_element, idl_instruction).is_empty(), - "{idl_instruction} carries no instruction data beyond its discriminator" - ); - } -} - -#[test] -fn idl_pda_seed_literals_match_pda_module() { - let known: BTreeSet<&[u8]> = [SETTLEMENT_SEED, BUFFER_SEED, ORDER_SEED] - .into_iter() - .collect(); - - let found = parse_json::const_seeds(parse_json::section(Section::Instructions)); - - // Every const seed the IDL does declare must be a real seed constant. Not - // every seed constant needs to show up: `order_pda`'s canonical seed - // includes `sha256(intent)`, which the IDL can't express as a static - // `pda` entry at all (documented in create_order's docs), so `ORDER_SEED` - // legitimately never appears here. - for seed in &found { - assert!( - known.contains(seed.as_slice()), - "IDL PDA const seed {:?} doesn't match any seed constant in interface::pda", - String::from_utf8_lossy(seed), - ); } - assert!( - found.iter().any(|s| s.as_slice() == SETTLEMENT_SEED), - "expected SETTLEMENT_SEED to appear in some IDL PDA `seeds`", - ); - assert!( - found.iter().any(|s| s.as_slice() == BUFFER_SEED), - "expected BUFFER_SEED to appear in some IDL PDA `seeds`", - ); } diff --git a/programs/settlement/tests/idl/parse_json.rs b/programs/settlement/tests/idl/parse_json.rs deleted file mode 100644 index f0532ca..0000000 --- a/programs/settlement/tests/idl/parse_json.rs +++ /dev/null @@ -1,186 +0,0 @@ -//! Readers for the checked-in IDL, `programs/settlement/idl/cow_settlement.json`. -//! -//! Accessors panic naming the entry that went missing or came back the wrong -//! shape, so a malformed IDL fails where it's read rather than where it's -//! compared. - -use std::{fmt, sync::LazyLock}; - -use serde_json::Value; - -use crate::parse_rust::normalize_doc; - -pub const IDL_JSON: &str = include_str!("../../idl/cow_settlement.json"); -pub const SCHEMA_JSON: &str = include_str!("../../idl/schema/idl-spec-v0.1.0.json"); - -pub static IDL: LazyLock = - LazyLock::new(|| serde_json::from_str(IDL_JSON).expect("IDL must be valid JSON")); - -/// A top-level array of the IDL. Naming the sections the tests read as a type -/// keeps a mistyped section from reading as a missing entry. -#[derive(Clone, Copy)] -pub enum Section { - Instructions, - Accounts, - Types, - Errors, -} - -impl Section { - /// The IDL key this section lives under. - pub fn as_str(self) -> &'static str { - match self { - Self::Instructions => "instructions", - Self::Accounts => "accounts", - Self::Types => "types", - Self::Errors => "errors", - } - } -} - -impl fmt::Display for Section { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(self.as_str()) - } -} - -/// The top-level `section[]` array. -pub fn section(section: Section) -> &'static [Value] { - IDL[section.as_str()] - .as_array() - .unwrap_or_else(|| panic!("IDL {section}[] must be an array")) -} - -/// Under the array for `section_name`, find the object where the `name` matches the given value. -/// Since each IDL section follows the same pattern where each section is an array of objects which contain a field `name`, this function -/// is useful for finding just about any item we need in the IDL file. -pub fn find_item(section_name: Section, name: &str) -> Option<&'static Value> { - section(section_name) - .iter() - .find(|item| item["name"] == name) -} - -/// An entry's `docs`, one [`normalize_doc`]d string per entry, so they compare -/// directly against what [`crate::parse_rust::docs`] reports. Absent docs read -/// as none at all; the caller compares against the Rust source to decide -/// whether that's wrong. -pub fn docs(item: &Value, context: &str) -> Vec { - let Some(docs) = item.get("docs") else { - return Vec::new(); - }; - docs.as_array() - .unwrap_or_else(|| panic!("docs for {context} should be an array")) - .iter() - .map(|doc| { - let doc = doc - .as_str() - .unwrap_or_else(|| panic!("doc entry for {context} should be a string")); - normalize_doc(&[doc]) - }) - .collect() -} - -/// An entry's `discriminator` bytes. -pub fn discriminator(item: &Value, context: &str) -> Vec { - item["discriminator"] - .as_array() - .unwrap_or_else(|| panic!("discriminator for {context} should be an array")) - .iter() - .map(|byte| { - let byte = byte - .as_u64() - .unwrap_or_else(|| panic!("discriminator byte for {context} should be a number")); - u8::try_from(byte) - .unwrap_or_else(|_| panic!("discriminator byte for {context} should fit in a u8")) - }) - .collect() -} - -/// The `(name, type)` pairs of an array of `{"name", "type"}` objects, in -/// declaration order. `types[]` fields and `instructions[]` args share this -/// shape. -fn name_type_pairs(entries: &[Value], context: &str) -> Vec<(String, Value)> { - entries - .iter() - .map(|entry| { - ( - entry["name"] - .as_str() - .unwrap_or_else(|| panic!("entry name in {context} must be a string")) - .to_string(), - entry["type"].clone(), - ) - }) - .collect() -} - -/// The `(name, type)` pairs of a struct `types[]` entry, in declaration order. -pub fn struct_fields(item: &Value, context: &str) -> Vec<(String, Value)> { - name_type_pairs( - item["type"]["fields"] - .as_array() - .unwrap_or_else(|| panic!("struct type {context} should have a fields array")), - context, - ) -} - -/// The `(name, type)` pairs of an `instructions[]` entry's `args`, in wire -/// order. An absent `args` reads as no arguments at all, which is how the IDL -/// spells an instruction whose data is just the discriminator. -pub fn args(item: &Value, context: &str) -> Vec<(String, Value)> { - let Some(args) = item.get("args") else { - return Vec::new(); - }; - name_type_pairs( - args.as_array() - .unwrap_or_else(|| panic!("args for {context} should be an array")), - context, - ) -} - -/// The variant names of an enum `types[]` entry, in declaration order, which is -/// the order the wire discriminant counts in. The spec's `IdlEnumVariant` has -/// nowhere to put per-variant docs, so there's nothing else here to compare. -pub fn enum_variants(item: &Value, context: &str) -> Vec { - item["type"]["variants"] - .as_array() - .unwrap_or_else(|| panic!("enum type {context} should have a variants array")) - .iter() - .map(|variant| { - variant["name"] - .as_str() - .unwrap_or_else(|| panic!("variant name in {context} must be a string")) - .to_string() - }) - .collect() -} - -/// Every `{"kind": "const"}` seed byte string anywhere below `values`. -pub fn const_seeds(values: &[Value]) -> Vec> { - fn collect(value: &Value, out: &mut Vec>) { - match value { - Value::Object(map) => { - if map.get("kind").and_then(Value::as_str) == Some("const") { - if let Some(Value::Array(bytes)) = map.get("value") { - let decoded: Vec = bytes - .iter() - .map(|b| b.as_u64().expect("seed byte must be a number") as u8) - .collect(); - out.push(decoded); - } - } - for v in map.values() { - collect(v, out); - } - } - Value::Array(arr) => arr.iter().for_each(|v| collect(v, out)), - _ => {} - } - } - - let mut found = Vec::new(); - for value in values { - collect(value, &mut found); - } - found -} diff --git a/programs/settlement/tests/idl/parse_rust.rs b/programs/settlement/tests/idl/parse_rust.rs index d187427..c932e80 100644 --- a/programs/settlement/tests/idl/parse_rust.rs +++ b/programs/settlement/tests/idl/parse_rust.rs @@ -1,12 +1,12 @@ //! Readers for the Rust sources the IDL describes. //! -//! Everything here goes through `syn`, panicking with the source path when the -//! item the IDL claims to describe isn't there to compare against. +//! Everything here goes through `syn` and reports what it finds in the IDL +//! spec's own JSON grammar, so [`crate::generate`] can assemble it straight +//! into an IDL document. Lookups panic with the source path when the item the +//! IDL claims to describe isn't there to read. use serde_json::{json, Value}; -use crate::parse_json::Section; - /// A Rust source file, compiled in so the tests parse the same text the /// program does. pub struct Source { @@ -40,6 +40,11 @@ pub const INITIALIZE_RS: Source = Source { text: include_str!("../../../../interface/src/instruction/initialize.rs"), }; +pub const CREATE_BUFFER_RS: Source = Source { + display: "interface/src/instruction/create_buffer.rs", + text: include_str!("../../../../interface/src/instruction/create_buffer.rs"), +}; + pub const CREATE_ORDER_RS: Source = Source { display: "interface/src/instruction/create_order.rs", text: include_str!("../../../../interface/src/instruction/create_order.rs"), @@ -55,6 +60,16 @@ pub const FINALIZE_SETTLE_RS: Source = Source { text: include_str!("../../../../interface/src/instruction/settle/finalize.rs"), }; +pub const RECLAIM_ORDER_RS: Source = Source { + display: "interface/src/instruction/reclaim_order.rs", + text: include_str!("../../../../interface/src/instruction/reclaim_order.rs"), +}; + +pub const RECLAIM_BUFFER_RS: Source = Source { + display: "interface/src/instruction/reclaim_buffer.rs", + text: include_str!("../../../../interface/src/instruction/reclaim_buffer.rs"), +}; + pub const TRANSFER_AUTHORITY_RS: Source = Source { display: "interface/src/instruction/transfer_authority.rs", text: include_str!("../../../../interface/src/instruction/transfer_authority.rs"), @@ -91,39 +106,22 @@ impl Source { } } -/// The variant of `rust_enum` whose discriminant is `byte`. -pub fn variant_by_discriminant(rust_enum: &syn::ItemEnum, byte: u8) -> &syn::Variant { - rust_enum - .variants - .iter() - .find(|variant| discriminant(variant) == u64::from(byte)) - .unwrap_or_else(|| { - panic!( - "{} must have a variant with discriminant {byte}", - rust_enum.ident - ) - }) -} - -/// Translates a Rust field type into the IDL spec's type grammar, so field -/// types can be compared as JSON. Panics on anything the program's data types -/// don't currently use. -pub fn type_to_idl(ty: &syn::Type, context: &str) -> Value { +/// Translates a Rust type into the IDL spec's type grammar, or `None` for the +/// types that grammar can't name: borrowed accounts (`&'a A`), the repeated +/// groups the instructions carry as trailing accounts, and arrays whose length +/// is a named constant rather than a literal. +pub fn try_type_to_idl(ty: &syn::Type) -> Option { match ty { syn::Type::Path(path) => { - let ident = path - .path - .get_ident() - .unwrap_or_else(|| panic!("{context}: expected a plain type name")) - .to_string(); - match ident.as_str() { + let ident = path.path.get_ident()?.to_string(); + Some(match ident.as_str() { "Pubkey" => json!("pubkey"), "bool" | "u8" | "u16" | "u32" | "u64" | "u128" | "i8" | "i16" | "i32" | "i64" | "i128" => json!(ident), // Anything else is one of this crate's own types, which the IDL // carries as its own `types[]` entry and references by name. _ => json!({ "defined": { "name": ident } }), - } + }) } syn::Type::Array(array) => { let syn::Expr::Lit(syn::ExprLit { @@ -131,15 +129,24 @@ pub fn type_to_idl(ty: &syn::Type, context: &str) -> Value { .. }) = &array.len else { - panic!("{context}: array length must be an integer literal"); + return None; }; - let len: u64 = len.base10_parse().expect("array length must be a u64"); - json!({ "array": [type_to_idl(&array.elem, context), len] }) + let len: u64 = len.base10_parse().ok()?; + Some(json!({ "array": [try_type_to_idl(&array.elem)?, len] })) } - _ => panic!("{context}: unsupported field type"), + _ => None, } } +/// Translates a Rust type into the IDL spec's type grammar, panicking on +/// anything the grammar can't name. Used where the IDL is expected to describe +/// the type in full, so a translation that can't be made is a broken IDL rather +/// than a limit to work around. +pub fn type_to_idl(ty: &syn::Type, context: &str) -> Value { + try_type_to_idl(ty) + .unwrap_or_else(|| panic!("{context}: the IDL's type grammar can't name this type")) +} + /// The `= N` discriminant an enum variant declares, or `None` where it leans on /// the implicit "one past the previous variant" value. pub fn declared_discriminant(variant: &syn::Variant) -> Option { @@ -168,58 +175,43 @@ pub fn discriminant(variant: &syn::Variant) -> u64 { .unwrap_or_else(|| panic!("discriminant should be defined on {}", variant.ident)) } -/// The `(name, type)` pairs of a struct's fields, in declaration order, with -/// each type already translated into the IDL's type grammar. -pub fn struct_fields(rust_struct: &syn::ItemStruct, context: &str) -> Vec<(String, Value)> { - rust_struct +/// A struct as an IDL `types[]` entry's `type`: `{"kind": "struct", "fields": +/// [...]}`, with the fields in declaration order, which is the order they're +/// laid out on the wire. +pub fn struct_type(rust_struct: &syn::ItemStruct, context: &str) -> Value { + let fields: Vec = rust_struct .fields .iter() .map(|field| { - let name = field - .ident - .as_ref() - .unwrap_or_else(|| panic!("{context} should have named fields")) - .to_string(); - let idl_type = type_to_idl(&field.ty, &format!("{context}.{name}")); - (name, idl_type) + let name = field_name(field, context); + let ty = type_to_idl(&field.ty, &format!("{context}.{name}")); + json!({ "name": name, "type": ty }) }) - .collect() + .collect(); + json!({ "kind": "struct", "fields": fields }) } -/// The names of a struct's fields, in declaration order. Unlike -/// [`struct_fields`] this translates no types, so it reads structs carrying -/// fields the IDL's type grammar has no equivalent for. -pub fn field_names(rust_struct: &syn::ItemStruct, context: &str) -> Vec { - rust_struct - .fields - .iter() - .map(|field| { - field - .ident - .as_ref() - .unwrap_or_else(|| panic!("{context} should have named fields")) - .to_string() - }) - .collect() -} - -/// One named field's type, translated into the IDL's type grammar. -pub fn field_type(rust_struct: &syn::ItemStruct, name: &str, context: &str) -> Value { - let field = rust_struct - .fields +/// An enum as an IDL `types[]` entry's `type`: `{"kind": "enum", "variants": +/// [...]}`, with the variants in declaration order, which is the order the wire +/// discriminant counts in. The spec's `IdlEnumVariant` carries a name and +/// nothing else — no discriminant, since a variant's index is its wire byte, +/// and nowhere to put docs. +pub fn enum_type(rust_enum: &syn::ItemEnum) -> Value { + let variants: Vec = rust_enum + .variants .iter() - .find(|field| field.ident.as_ref().is_some_and(|ident| ident == name)) - .unwrap_or_else(|| panic!("{context} should have a field named {name}")); - type_to_idl(&field.ty, &format!("{context}.{name}")) + .map(|variant| json!({ "name": variant.ident.to_string() })) + .collect(); + json!({ "kind": "enum", "variants": variants }) } -/// The variant names of an enum, in declaration order. -pub fn enum_variants(rust_enum: &syn::ItemEnum) -> Vec { - rust_enum - .variants - .iter() - .map(|variant| variant.ident.to_string()) - .collect() +/// One field's name. +pub fn field_name(field: &syn::Field, context: &str) -> String { + field + .ident + .as_ref() + .unwrap_or_else(|| panic!("{context} should have named fields")) + .to_string() } /// Unwraps rustdoc intra-doc links to the text they display: `[`Role`](Role)` @@ -255,10 +247,8 @@ fn strip_doc_links(text: &str) -> String { out } -/// Collapses doc lines into the single line the IDL carries them as, dropping -/// the backtick and link markup the IDL only carries in some places. Both this -/// module and [`crate::parse_json`] hand their doc text through here, so the two -/// sides are always compared in the same form. +/// Collapses doc lines into a single line, dropping the backtick and link +/// markup the IDL only carries in some places. pub fn normalize_doc>(lines: &[S]) -> String { strip_doc_links( &lines @@ -310,17 +300,3 @@ pub fn docs(attrs: &[syn::Attribute]) -> Vec { } paragraphs } - -/// [`docs`] of the variant with discriminant `byte` in whichever discriminator -/// enum backs the given IDL `section`. -pub fn discriminator_variant_docs(section: Section, byte: u8) -> Vec { - let enum_name = match section { - Section::Instructions => "SettlementInstruction", - Section::Accounts => "SettlementAccount", - other => panic!("no discriminator enum backs IDL {other}[]"), - }; - - let rust_enum = INTERFACE_LIB_RS.find_enum(enum_name); - - docs(&variant_by_discriminant(&rust_enum, byte).attrs) -} diff --git a/programs/settlement/tests/idl/superset.rs b/programs/settlement/tests/idl/superset.rs new file mode 100644 index 0000000..c4b0ac0 --- /dev/null +++ b/programs/settlement/tests/idl/superset.rs @@ -0,0 +1,215 @@ +//! The comparison between the partial IDL the Rust source implies and the IDL +//! that's actually checked in. +//! +//! [`assert_superset`] holds the checked-in file to everything +//! [`crate::generate`] could derive, and to nothing more: an IDL key the +//! generated document doesn't mention is a fact the Rust source can't state, so +//! it's left for the schema and the human reviewer. That asymmetry is the whole +//! design — the generated side never has to be a complete IDL, only a true one. + +use serde_json::Value; + +use crate::parse_rust::normalize_doc; + +/// Asserts `actual` states everything `generated` does. Every mismatch is +/// collected before failing, so one run reports the full drift rather than +/// whichever entry happened to be compared first. +pub fn assert_superset(generated: &Value, actual: &Value) { + let mut problems = Vec::new(); + compare("", generated, actual, &mut problems); + assert!( + problems.is_empty(), + "the checked-in IDL doesn't agree with the Rust source it describes:\n\n{}\n", + problems.join("\n\n"), + ); +} + +/// How the two sides of an array are lined up. +enum ArrayRule { + /// Index `i` describes the same thing on both sides, and the arrays have to + /// be the same length. This is the rule for everything laid out on the + /// wire, where order and completeness are the point. + Positional, + /// Entries are matched by their `name`, in whatever order each side happens + /// to list them. `exhaustive` additionally rejects an entry in `actual` + /// that the generated side never matched. + ByName { exhaustive: bool }, +} + +/// The rule for the array at `path`. +fn array_rule(path: &str) -> ArrayRule { + match path { + // Top-level sections. The Rust source defines every entry, so one the + // IDL has left over from a rename, or invented outright, is an error — + // but the two are free to order them differently, and they do: the IDL + // reads top to bottom in call order where the discriminator enum counts + // from zero. + "instructions" | "accounts" | "types" | "errors" => ArrayRule::ByName { exhaustive: true }, + // An instruction's accounts. Only the ones whose PDA seeds the interface + // pins are generated, so the IDL legitimately names more, in an order + // nothing in the Rust source fixes. + _ if path.ends_with("].accounts") => ArrayRule::ByName { exhaustive: false }, + // Struct fields, instruction args, enum variants, discriminator bytes, + // PDA seeds and their const bytes: all wire order, all complete. + _ => ArrayRule::Positional, + } +} + +fn compare(path: &str, generated: &Value, actual: &Value, problems: &mut Vec) { + match generated { + Value::Object(generated) => { + let Some(actual) = actual.as_object() else { + problems.push(format!( + "{}: the IDL has {actual} where an object belongs", + at(path) + )); + return; + }; + for (key, generated) in generated { + let path = format!("{path}.{key}"); + let path = path.trim_start_matches('.'); + match actual.get(key) { + // `docs` is prose, and prose is the one thing the two sides + // are allowed to disagree on the shape of. + Some(actual) if key == "docs" => { + compare_docs(path, generated, actual, problems) + } + Some(actual) => compare(path, generated, actual, problems), + None => problems.push(format!( + "{}: missing from the IDL; the Rust source says it is\n {generated}", + at(path) + )), + } + } + } + Value::Array(generated) => { + let Some(actual) = actual.as_array() else { + problems.push(format!( + "{}: the IDL has {actual} where an array belongs", + at(path) + )); + return; + }; + match array_rule(path) { + ArrayRule::Positional => compare_positional(path, generated, actual, problems), + ArrayRule::ByName { exhaustive } => { + compare_by_name(path, generated, actual, exhaustive, problems); + } + } + } + scalar => { + if scalar != actual { + problems.push(format!( + "{}: the IDL says {actual}, the Rust source says {scalar}", + at(path) + )); + } + } + } +} + +fn compare_positional( + path: &str, + generated: &[Value], + actual: &[Value], + problems: &mut Vec, +) { + if generated.len() != actual.len() { + problems.push(format!( + "{}: the IDL lists {} entries, the Rust source has {}", + at(path), + actual.len(), + generated.len() + )); + } + for (index, generated) in generated.iter().enumerate() { + let path = format!("{path}[{index}]"); + match actual.get(index) { + Some(actual) => compare(&path, generated, actual, problems), + None => problems.push(format!( + "{}: missing from the IDL; the Rust source says it is\n {generated}", + at(&path) + )), + } + } +} + +fn compare_by_name( + path: &str, + generated: &[Value], + actual: &[Value], + exhaustive: bool, + problems: &mut Vec, +) { + for generated in generated { + let name = generated["name"] + .as_str() + .unwrap_or_else(|| panic!("{path} entries are matched by name, so each needs one")); + let path = format!("{path}[{name}]"); + match actual.iter().find(|entry| entry["name"] == *name) { + Some(actual) => compare(&path, generated, actual, problems), + None => problems.push(format!("{}: missing from the IDL", at(&path))), + } + } + + if exhaustive && actual.len() != generated.len() { + let unmatched: Vec<&str> = actual + .iter() + .filter_map(|entry| entry["name"].as_str()) + .filter(|name| !generated.iter().any(|entry| entry["name"] == **name)) + .collect(); + problems.push(format!( + "{}: the IDL carries entries with no counterpart in the Rust source: {unmatched:?}", + at(path) + )); + } +} + +/// Checks the IDL documents everything the Rust source does, in the same order. +/// The IDL may contain more docs. +fn compare_docs(path: &str, generated: &Value, actual: &Value, problems: &mut Vec) { + let (Some(generated), Some(actual)) = (generated.as_array(), actual.as_array()) else { + problems.push(format!( + "{}: the IDL has {actual} where docs belong", + at(path) + )); + return; + }; + + let lines: Vec<&str> = actual.iter().filter_map(Value::as_str).collect(); + if lines.len() != actual.len() { + problems.push(format!( + "{}: every IDL doc entry must be a string", + at(path) + )); + return; + } + // The IDL side goes through the same normalization the Rust side already + // did, so the backticks one carries and the other doesn't never show up as + // a difference in what they say. + let idl_prose = normalize_doc(&lines); + + // Each paragraph consumes the prose up to and including itself, so the next + // one can only match further along: that's what makes this an order check + // and not just a set of independent lookups. + let mut unread = idl_prose.as_str(); + for paragraph in generated.iter().filter_map(Value::as_str) { + match unread.split_once(paragraph) { + Some((_, after)) => unread = after, + None => problems.push(format!( + "{}: the IDL doesn't document this, or documents it out of order:\n \ + {paragraph}\nthe IDL's prose is:\n {idl_prose}", + at(path) + )), + } + } +} + +/// Names the position in the IDL a problem was found at. +fn at(path: &str) -> String { + if path.is_empty() { + "the IDL's root".to_string() + } else { + path.to_string() + } +} From b924e85dfd017cbcd932d7b96b2e46ba9e222a10 Mon Sep 17 00:00:00 2001 From: Kaze <230549489+kaze-cow@users.noreply.github.com> Date: Mon, 31 Aug 2026 15:05:39 +0900 Subject: [PATCH 17/43] remove unnecessary comments and add test to confirm link stripping halding --- programs/settlement/tests/idl/parse_rust.rs | 20 +++++++++++++------- programs/settlement/tests/idl/superset.rs | 8 +++----- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/programs/settlement/tests/idl/parse_rust.rs b/programs/settlement/tests/idl/parse_rust.rs index c932e80..244751e 100644 --- a/programs/settlement/tests/idl/parse_rust.rs +++ b/programs/settlement/tests/idl/parse_rust.rs @@ -192,10 +192,7 @@ pub fn struct_type(rust_struct: &syn::ItemStruct, context: &str) -> Value { } /// An enum as an IDL `types[]` entry's `type`: `{"kind": "enum", "variants": -/// [...]}`, with the variants in declaration order, which is the order the wire -/// discriminant counts in. The spec's `IdlEnumVariant` carries a name and -/// nothing else — no discriminant, since a variant's index is its wire byte, -/// and nowhere to put docs. +/// [...]}`, with the variants in declaration order. pub fn enum_type(rust_enum: &syn::ItemEnum) -> Value { let variants: Vec = rust_enum .variants @@ -218,9 +215,6 @@ pub fn field_name(field: &syn::Field, context: &str) -> String { /// reads as `Role`. The IDL has no notion of a link target, so carrying one /// there would only be Rust markup leaking into the published interface. fn strip_doc_links(text: &str) -> String { - /// The display text and the remainder past `[display](target)`, when `text` - /// starts with a link whose two halves nest no brackets of their own. - /// Anything else isn't a link and is left exactly as written. fn split_link(text: &str) -> Option<(&str, &str)> { let (display, after_display) = text.strip_prefix('[')?.split_once("](")?; let (target, after_link) = after_display.split_once(')')?; @@ -300,3 +294,15 @@ pub fn docs(attrs: &[syn::Attribute]) -> Vec { } paragraphs } + +mod tests { + use crate::parse_rust::strip_doc_links; + + #[test] + fn test_link_stripping() { + assert_eq!( + strip_doc_links("There are two ixs, [Begin](begin) and [Finalize](finalize)"), + "There are two ixs, Begin and Finalize" + ) + } +} diff --git a/programs/settlement/tests/idl/superset.rs b/programs/settlement/tests/idl/superset.rs index c4b0ac0..42b5070 100644 --- a/programs/settlement/tests/idl/superset.rs +++ b/programs/settlement/tests/idl/superset.rs @@ -1,11 +1,9 @@ //! The comparison between the partial IDL the Rust source implies and the IDL //! that's actually checked in. //! -//! [`assert_superset`] holds the checked-in file to everything -//! [`crate::generate`] could derive, and to nothing more: an IDL key the -//! generated document doesn't mention is a fact the Rust source can't state, so -//! it's left for the schema and the human reviewer. That asymmetry is the whole -//! design — the generated side never has to be a complete IDL, only a true one. +//! [`assert_superset`] checks that the checked-in IDL is consistent with the +//! JSON generated by crate::generate. The checked-in version may contain more +//! data than what has been generated, but the available information cannot be different. use serde_json::Value; From 0e15786a40d7b94c45f0373887146807f963df09 Mon Sep 17 00:00:00 2001 From: Kaze <230549489+kaze-cow@users.noreply.github.com> Date: Mon, 31 Aug 2026 15:07:51 +0900 Subject: [PATCH 18/43] Update programs/settlement/idl/cow_settlement.json Co-authored-by: Federico Giacon <58218759+fedgiac@users.noreply.github.com> --- programs/settlement/idl/cow_settlement.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/programs/settlement/idl/cow_settlement.json b/programs/settlement/idl/cow_settlement.json index 60865a4..fdb90e4 100644 --- a/programs/settlement/idl/cow_settlement.json +++ b/programs/settlement/idl/cow_settlement.json @@ -4,7 +4,7 @@ "name": "cow_settlement", "version": "0.2.0", "spec": "0.1.0", - "description": "CoW Protocol settlement program. IDL may not be able to generate typical of Anchor programs, so please be careful to read the documentation on the function you are using.", + "description": "CoW Protocol settlement program. Some of the properties and instructions of this program can't be represented via a standard IDL, please be careful to read the documentation on the function you are using. Both the program and this IDL are in early release phase and may contain errors.", "repository": "https://github.com/cowprotocol/solana-programs" }, "instructions": [ From dfaba66cf760b09aa596839579a646464d954f5f Mon Sep 17 00:00:00 2001 From: Kaze <230549489+kaze-cow@users.noreply.github.com> Date: Mon, 31 Aug 2026 15:08:52 +0900 Subject: [PATCH 19/43] Update programs/settlement/idl/cow_settlement.json Co-authored-by: Federico Giacon <58218759+fedgiac@users.noreply.github.com> --- programs/settlement/idl/cow_settlement.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/programs/settlement/idl/cow_settlement.json b/programs/settlement/idl/cow_settlement.json index fdb90e4..692ead4 100644 --- a/programs/settlement/idl/cow_settlement.json +++ b/programs/settlement/idl/cow_settlement.json @@ -69,14 +69,14 @@ { "name": "manager", "docs": [ - "Recorded verbatim in the state PDA's body as the initial holder of the Manager role: the account authorized to add and remove solvers and to transfer any role." + "The initial holder of the Manager role: the account authorized to add and remove solvers and to transfer any role." ], "type": "pubkey" }, { "name": "reclaim_authority", "docs": [ - "Recorded verbatim in the state PDA's body as the initial holder of the ReclaimAuthority role: the account authorized to close buffer accounts and reclaim their rent." + "The initial holder of the ReclaimAuthority role: the account authorized to close buffer accounts and reclaim their rent." ], "type": "pubkey" } From fa8c4d289bbd7149c3115f1b42ed129280579c8d Mon Sep 17 00:00:00 2001 From: Kaze <230549489+kaze-cow@users.noreply.github.com> Date: Mon, 31 Aug 2026 15:42:02 +0900 Subject: [PATCH 20/43] add a test for targetless links --- programs/settlement/tests/idl/generate.rs | 5 ----- programs/settlement/tests/idl/parse_rust.rs | 18 +++++++++++++++--- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/programs/settlement/tests/idl/generate.rs b/programs/settlement/tests/idl/generate.rs index c918efa..d4fdefb 100644 --- a/programs/settlement/tests/idl/generate.rs +++ b/programs/settlement/tests/idl/generate.rs @@ -7,11 +7,6 @@ //! list, the prose describing each argument, the `metadata` blurbs — is simply //! left out, and [`crate::superset`] is what says the checked-in IDL has to //! agree with everything that _is_ here. -//! -//! The tables below are the one place a name has to be written twice. They -//! exist because nothing in the Rust source says which file holds an -//! instruction's parsed input, which struct backs a `types[]` entry, or which -//! of an instruction's accounts the IDL derives as a PDA. use cow_settlement_interface::{ pda::{buffer::BUFFER_SEED, SETTLEMENT_SEED}, diff --git a/programs/settlement/tests/idl/parse_rust.rs b/programs/settlement/tests/idl/parse_rust.rs index 244751e..aa2fc94 100644 --- a/programs/settlement/tests/idl/parse_rust.rs +++ b/programs/settlement/tests/idl/parse_rust.rs @@ -216,9 +216,16 @@ pub fn field_name(field: &syn::Field, context: &str) -> String { /// there would only be Rust markup leaking into the published interface. fn strip_doc_links(text: &str) -> String { fn split_link(text: &str) -> Option<(&str, &str)> { - let (display, after_display) = text.strip_prefix('[')?.split_once("](")?; - let (target, after_link) = after_display.split_once(')')?; - (!display.contains('[') && !target.contains('(')).then_some((display, after_link)) + let (display, after_display) = text.strip_prefix('[')?.split_once("]")?; + + if let Some((target, after_link)) = after_display + .strip_prefix("(") + .and_then(|f| f.split_once(')')) + { + (!display.contains('[') && !target.contains('(')).then_some((display, after_link)) + } else { + (!display.contains("[")).then_some((display, after_display)) + } } let mut out = String::with_capacity(text.len()); @@ -303,6 +310,11 @@ mod tests { assert_eq!( strip_doc_links("There are two ixs, [Begin](begin) and [Finalize](finalize)"), "There are two ixs, Begin and Finalize" + ); + + assert_eq!( + strip_doc_links("Testing a [standalone] link"), + "Testing a standalone link" ) } } From f4f065e1a419492cbff0d4471187cafb299996b7 Mon Sep 17 00:00:00 2001 From: Kaze <230549489+kaze-cow@users.noreply.github.com> Date: Mon, 31 Aug 2026 15:46:01 +0900 Subject: [PATCH 21/43] remove unnecessary comment from IDL --- programs/settlement/idl/cow_settlement.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/programs/settlement/idl/cow_settlement.json b/programs/settlement/idl/cow_settlement.json index 692ead4..bd8493e 100644 --- a/programs/settlement/idl/cow_settlement.json +++ b/programs/settlement/idl/cow_settlement.json @@ -57,7 +57,7 @@ ] }, "docs": [ - "Canonical PDA seeded by SETTLEMENT_SEED alone. SETTLEMENT_SEED is the ASCII prefix \"settlement v\" followed by the program's major.minor version, right-padded with spaces to a fixed 19 bytes; the fixed width prevents one version's seeds from being a prefix of another's. The const bytes below are authoritative and change on every minor version bump." + "Canonical PDA seeded by SETTLEMENT_SEED alone. SETTLEMENT_SEED is the ASCII prefix \"settlement v\" followed by the program's major.minor version, right-padded with spaces to a fixed 19 bytes; the fixed width prevents one version's seeds from being a prefix of another's." ] }, { @@ -359,7 +359,7 @@ ] }, "docs": [ - "Must be the canonical state PDA; holds the reclaim_authority the signer is checked against, and is the buffers' SPL token authority. Canonical PDA seeded by SETTLEMENT_SEED alone. SETTLEMENT_SEED is the ASCII prefix \"settlement v\" followed by the program's major.minor version, right-padded with spaces to a fixed 19 bytes; the fixed width prevents one version's seeds from being a prefix of another's. The const bytes below are authoritative and change on every minor version bump." + "Must be the canonical state PDA; holds the reclaim_authority the signer is checked against, and is the buffers' SPL token authority. Canonical PDA seeded by SETTLEMENT_SEED alone. SETTLEMENT_SEED is the ASCII prefix \"settlement v\" followed by the program's major.minor version, right-padded with spaces to a fixed 19 bytes; the fixed width prevents one version's seeds from being a prefix of another's." ] }, { @@ -488,7 +488,7 @@ ] }, "docs": [ - "Canonical PDA seeded by SETTLEMENT_SEED alone. SETTLEMENT_SEED is the ASCII prefix \"settlement v\" followed by the program's major.minor version, right-padded with spaces to a fixed 19 bytes; the fixed width prevents one version's seeds from being a prefix of another's. The const bytes below are authoritative and change on every minor version bump." + "Canonical PDA seeded by SETTLEMENT_SEED alone. SETTLEMENT_SEED is the ASCII prefix \"settlement v\" followed by the program's major.minor version, right-padded with spaces to a fixed 19 bytes; the fixed width prevents one version's seeds from being a prefix of another's." ] } ], From 4ba1d331e3ba5c92c070f4b3144878538d7b6b85 Mon Sep 17 00:00:00 2001 From: Kaze <230549489+kaze-cow@users.noreply.github.com> Date: Mon, 31 Aug 2026 22:11:49 +0900 Subject: [PATCH 22/43] explain variants better --- programs/settlement/tests/idl/main.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/programs/settlement/tests/idl/main.rs b/programs/settlement/tests/idl/main.rs index 31ff063..a21dfac 100644 --- a/programs/settlement/tests/idl/main.rs +++ b/programs/settlement/tests/idl/main.rs @@ -94,10 +94,11 @@ fn idl_matches_everything_generated_from_rust() { superset::assert_superset(&generated, &IDL); } -/// The IDL spec can only express a variant's wire value as its position, so a -/// Rust variant that pins its own discriminant has to agree with its index. -/// Nothing in the generated document can carry this: it's a fact about the Rust -/// enum, checked so the `variants[]` the IDL does carry mean what they say. +/// The IDL specification provides no way to specify the numeric value +/// of enum variants. If an enum is used as an input for an instruction or +/// account encoding (such as with OrderKind), a mismatch in the order +/// in the IDL would lead to mis-encoding. This test prevents them from +/// happening by making the ordering of variants sensitive. #[test] fn enum_type_discriminants_match_variant_order() { for (source, name) in generate::ENUM_TYPES { From ef978a8cd0db631bf45852ae047365b6b799b155 Mon Sep 17 00:00:00 2001 From: Kaze <230549489+kaze-cow@users.noreply.github.com> Date: Tue, 1 Sep 2026 16:41:23 +0900 Subject: [PATCH 23/43] test(idl-client): build order intents from the current OrderIntent shape MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The createOrder fixture still set `kind` and `partiallyFillable`, which the intent no longer carries, and omitted `buyMint`, `sellMint` and `flags`. The struct encoder walks fields in order, so the first missing one reached the address encoder as `undefined` and failed inside `assertIsAddress`. Assemble the flags byte from the settings it packs instead, mirroring the bit layout in `interface/src/data/intent.rs`, with created_on_chain set — the program rejects an on-chain creation whose bit is clear. Co-Authored-By: Claude Opus 5 (1M context) --- .../idl/client/js/tests/fixtures.ts | 43 +++++++++++++++++-- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/programs/settlement/idl/client/js/tests/fixtures.ts b/programs/settlement/idl/client/js/tests/fixtures.ts index c6b7721..7a80636 100644 --- a/programs/settlement/idl/client/js/tests/fixtures.ts +++ b/programs/settlement/idl/client/js/tests/fixtures.ts @@ -7,19 +7,54 @@ export const COW_SETTLEMENT_SO_PATH = path.join( "../../../../../../target/deploy/cow_settlement.so", ); +/** + * Assembles the intent's `flags` byte from the settings it packs: bit 0 is + * created_on_chain, bit 1 the order kind, bit 2 partially_fillable. Reserved + * bits are left clear — the program rejects a byte carrying one. + */ +export function encodeFlags({ + createdOnChain, + kind, + partiallyFillable, +}: { + createdOnChain: boolean; + kind: OrderKind; + partiallyFillable: boolean; +}): number { + return ( + (createdOnChain ? 1 << 0 : 0) | + (kind === OrderKind.Buy ? 1 << 1 : 0) | + (partiallyFillable ? 1 << 2 : 0) + ); +} + export async function buildOrderIntent( overrides: Partial & { owner: Address }, ): Promise { - const buyTokenAccount = await generateKeyPairSigner(); - const sellTokenAccount = await generateKeyPairSigner(); + // create_order doesn't touch the token accounts or mints the intent names, so + // they only have to be distinct addresses. + const [buyTokenAccount, buyMint, sellTokenAccount, sellMint] = + await Promise.all([ + generateKeyPairSigner(), + generateKeyPairSigner(), + generateKeyPairSigner(), + generateKeyPairSigner(), + ]); return { buyTokenAccount: buyTokenAccount.address, + buyMint: buyMint.address, sellTokenAccount: sellTokenAccount.address, + sellMint: sellMint.address, sellAmount: 1_000_000n, buyAmount: 2_000_000n, validTo: Math.floor(Date.now() / 1000) + 3600, - kind: OrderKind.Sell, - partiallyFillable: false, + // This is the on-chain creation flow, so created_on_chain has to be set: + // create_order rejects an intent whose bit is clear. + flags: encodeFlags({ + createdOnChain: true, + kind: OrderKind.Sell, + partiallyFillable: false, + }), appData: new Uint8Array(32), ...overrides, }; From 3acbf98e391654763b2ac3a4de3ce4e100ca252c Mon Sep 17 00:00:00 2001 From: Kaze <230549489+kaze-cow@users.noreply.github.com> Date: Tue, 1 Sep 2026 16:41:47 +0900 Subject: [PATCH 24/43] refactor(idl): ship the IDL with the generated client MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit generate.mjs hand-rolled a TypeScript module exporting SETTLEMENT_SEED, which was just the state PDA's const seed lifted out of the IDL because codama inlines const seeds into its derivation functions and exports no constant for them. Copy the IDL into the rendered client instead and let resolveOrderPda — the one consumer, which builds the order PDA's seeds by hand — read that seed off it. Same single source for the version-dependent bytes, no generated code to maintain. Reaching the JSON needs `resolveJsonModule` and an ESM module mode, so mark the package as ESM. That in turn moves module resolution to the bundler pair: strict NodeNext demands `.js` extensions on relative imports, which codama's renderer doesn't emit. `tsc --noEmit` now passes, where before it failed on the fixtures' `import.meta`. Co-Authored-By: Claude Opus 5 (1M context) --- .../settlement/idl/client/js/package.json | 1 + .../settlement/idl/client/js/src/hooked.ts | 36 ++++++++++++++++++- .../settlement/idl/client/js/tsconfig.json | 8 +++-- programs/settlement/idl/generate.mjs | 35 ++++-------------- 4 files changed, 49 insertions(+), 31 deletions(-) diff --git a/programs/settlement/idl/client/js/package.json b/programs/settlement/idl/client/js/package.json index 298012c..e08a788 100644 --- a/programs/settlement/idl/client/js/package.json +++ b/programs/settlement/idl/client/js/package.json @@ -1,6 +1,7 @@ { "name": "js-client", "version": "1.0.0", + "type": "module", "description": "", "main": "src/index.ts", "files": [ diff --git a/programs/settlement/idl/client/js/src/hooked.ts b/programs/settlement/idl/client/js/src/hooked.ts index 694d188..b4c5177 100644 --- a/programs/settlement/idl/client/js/src/hooked.ts +++ b/programs/settlement/idl/client/js/src/hooked.ts @@ -13,7 +13,41 @@ import { getProgramDerivedAddress, type Address } from "@solana/kit"; import { getOrderIntentEncoder, type OrderIntentArgs } from "./generated"; -import { SETTLEMENT_SEED } from "./generated/settlementSeed"; +import IDL from "./generated/idl.json" with { type: "json" }; + +/** + * The slice of the IDL this file reads. Annotating the import replaces the shape + * TypeScript infers from the JSON — a union over every instruction, account and + * seed kind — with just the path walked below, on which `pda` is reachable. + */ +type SeedBearingIdl = { + instructions: { + name: string; + accounts: { + name: string; + pda?: { seeds: { kind: string; value?: number[] }[] }; + }[]; + }[]; +}; + +/** + * Prefix seed shared by every PDA this program derives: the ASCII "settlement v" + * followed by the program's major.minor version, right-padded with spaces to a + * fixed 19 bytes. The fixed width keeps one version's seeds from being a prefix + * of another's. These bytes change on every minor version bump, so they're read + * off the IDL — the state PDA's sole const seed — rather than written out here. + */ +const SETTLEMENT_SEED: Uint8Array = (() => { + const idl: SeedBearingIdl = IDL; + const seed = idl.instructions + .find((instruction) => instruction.name === "initialize") + ?.accounts.find((account) => account.name === "state_pda") + ?.pda?.seeds[0]?.value; + if (!seed) { + throw new Error("IDL: initialize's state_pda has no const seed"); + } + return new Uint8Array(seed); +})(); export async function resolveOrderPda({ programAddress, diff --git a/programs/settlement/idl/client/js/tsconfig.json b/programs/settlement/idl/client/js/tsconfig.json index 991173d..3da9187 100644 --- a/programs/settlement/idl/client/js/tsconfig.json +++ b/programs/settlement/idl/client/js/tsconfig.json @@ -1,9 +1,13 @@ { "compilerOptions": { "target": "ES2022", - "module": "NodeNext", - "moduleResolution": "NodeNext", + // The package ships TS sources (see package.json's `main`) and is consumed + // through a bundler, as vitest does here: extensionless relative specifiers + // — which is all codama's renderer emits — only resolve under this pair. + "module": "Preserve", + "moduleResolution": "bundler", "strict": true, + "resolveJsonModule": true, "skipLibCheck": true, "esModuleInterop": true, "types": ["node"] diff --git a/programs/settlement/idl/generate.mjs b/programs/settlement/idl/generate.mjs index 21a0733..f40f276 100644 --- a/programs/settlement/idl/generate.mjs +++ b/programs/settlement/idl/generate.mjs @@ -1,4 +1,4 @@ -import { writeFileSync, mkdirSync } from "node:fs"; +import { copyFileSync, mkdirSync } from "node:fs"; import { createFromRoot, resolverValueNode, @@ -36,32 +36,11 @@ codama.accept( // codama inlines each PDA's const seeds into the function that derives it and // exports no constant for them, so resolveOrderPda — which builds the order PDA -// seeds by hand — has nothing to import. Emit SETTLEMENT_SEED here, read off the -// state PDA's sole const seed, so the version-dependent bytes still have exactly -// one source (the IDL) and follow it across version bumps. Written after the -// render because renderVisitor wipes its output directory first. -const settlementSeed = IDL.instructions - .find((instruction) => instruction.name === "initialize") - .accounts.find((account) => account.name === "state_pda").pda.seeds[0].value; - +// seeds by hand — has nothing to import. Ship the IDL itself alongside the +// rendered client and let the resolver read the seed it needs off it, so the +// version-dependent bytes keep exactly one source and follow it across version +// bumps. Copied after the render because renderVisitor wipes its output +// directory first. mkdirSync("./client/js/src/generated", { recursive: true }); -writeFileSync( - "./client/js/src/generated/settlementSeed.ts", - `/** - * This code was AUTOGENERATED by generate.mjs (not by Codama itself, which - * inlines PDA seeds into its derivation functions instead of exporting them). - * Please DO NOT EDIT THIS FILE, edit generate.mjs and rerun it instead. - */ - -/** - * Prefix seed shared by every PDA this program derives: the ASCII "settlement v" - * followed by the program's major.minor version, right-padded with spaces to a - * fixed 19 bytes. The fixed width keeps one version's seeds from being a prefix - * of another's. These bytes change on every minor version bump. - */ -export const SETTLEMENT_SEED: Uint8Array = new Uint8Array([ - ${settlementSeed.join(", ")}, -]); -`, -); +copyFileSync("./cow_settlement.json", "./client/js/src/generated/idl.json"); From 49a649eead4f503d483a482f9d1f5cc6f455e790 Mon Sep 17 00:00:00 2001 From: Kaze <230549489+kaze-cow@users.noreply.github.com> Date: Tue, 1 Sep 2026 16:42:23 +0900 Subject: [PATCH 25/43] ci(idl-client): run the JS client tests in CI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add `just test-js-client`, which builds the .so the tests drive through litesvm, renders the client from the current IDL — that output is gitignored, so a fresh checkout has none — and runs vitest. Both packages install with `corepack pnpm`, so the pinned pnpm version comes from their package.json and no global install is needed, locally or on the runner. Commit the lockfiles the frozen installs resolve against. The .gitignore negation that exempts the IDL from the Solana-key `*.json` rule was also pulling node_modules and the rendered client back in, leaving both as untracked noise; exclude them again. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/ci.yml | 26 + .gitignore | 7 + Justfile | 13 +- .../settlement/idl/client/js/package.json | 1 + .../settlement/idl/client/js/pnpm-lock.yaml | 2912 +++++++++++++++++ programs/settlement/idl/pnpm-lock.yaml | 505 +++ 6 files changed, 3463 insertions(+), 1 deletion(-) create mode 100644 programs/settlement/idl/client/js/pnpm-lock.yaml create mode 100644 programs/settlement/idl/pnpm-lock.yaml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a58829e..75896a6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -43,6 +43,32 @@ jobs: exit 1 } + test-js-client: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + with: + persist-credentials: false + + # litesvm loads the built .so, so this job needs the Solana toolchain too. + - uses: ./.github/actions/setup-solana + - uses: ./.github/actions/setup-just + - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 + + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + with: + # Bump to upgrade. Releases: https://github.com/nodejs/node/releases + # Node ships corepack, which `just test-js-client` uses to run the pnpm + # version the packages pin — so pnpm needs no separate setup step here. + node-version: "24" + + - name: Test JS client + # Corepack otherwise asks for confirmation before fetching pnpm, which + # would hang the job. + env: + COREPACK_ENABLE_DOWNLOAD_PROMPT: "0" + run: just test-js-client + fmt-check: runs-on: ubuntu-latest steps: diff --git a/.gitignore b/.gitignore index 2ded9aa..51b47a2 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,10 @@ generated/ *.json !bench-report.json !programs/settlement/idl/** + +# That negation re-includes the whole IDL directory, taking installed dependencies +# and the rendered client — excluded everywhere by the rules at the top — back with +# it. Exclude them again; what the negation has to reach is the IDL, its schema and +# the pnpm lockfiles, which CI installs from and so are committed here on purpose. +programs/settlement/idl/**/node_modules/ +programs/settlement/idl/client/js/src/generated/ diff --git a/Justfile b/Justfile index a58e79a..0315c4a 100644 --- a/Justfile +++ b/Justfile @@ -18,6 +18,17 @@ build: build-program test: build-program build-test-programs cargo test +# The two JS recipes below install with `corepack pnpm`, which runs the pnpm version +# each package.json pins, so neither one needs pnpm installed globally. + +# Render the JS client from the hand-written IDL (the output is kept out of git, so re-render it before use). +generate-js-client: + cd programs/settlement/idl && corepack pnpm install --frozen-lockfile && node generate.mjs + +# Run the JS client's tests, which drive the real program through litesvm (needs the .so and a freshly rendered client). +test-js-client: build-program generate-js-client + cd programs/settlement/idl/client/js && corepack pnpm install --frozen-lockfile && corepack pnpm exec vitest run + # Each test outputs its consumption during test execution to a series of target/bench-report/*.jsonl files. # Assembles into a single `bench-report.json` bench: build-program build-test-programs @@ -85,4 +96,4 @@ deploy programid keypair: build-verified initialize \ || echo "warning: \`initialize\` failed, the state PDA may already exist" >&2 -all: build bench lint fmt-check doc-dev +all: build bench test-js-client lint fmt-check doc-dev diff --git a/programs/settlement/idl/client/js/package.json b/programs/settlement/idl/client/js/package.json index e08a788..3073b26 100644 --- a/programs/settlement/idl/client/js/package.json +++ b/programs/settlement/idl/client/js/package.json @@ -2,6 +2,7 @@ "name": "js-client", "version": "1.0.0", "type": "module", + "packageManager": "pnpm@10.30.3", "description": "", "main": "src/index.ts", "files": [ diff --git a/programs/settlement/idl/client/js/pnpm-lock.yaml b/programs/settlement/idl/client/js/pnpm-lock.yaml new file mode 100644 index 0000000..2c71e9c --- /dev/null +++ b/programs/settlement/idl/client/js/pnpm-lock.yaml @@ -0,0 +1,2912 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@solana/program-client-core': + specifier: ^6.10.0 + version: 6.10.0(typescript@5.9.3) + devDependencies: + '@solana/kit': + specifier: ^6.10.0 + version: 6.10.0(typescript@5.9.3) + '@types/node': + specifier: ^24.10.0 + version: 24.13.3 + litesvm: + specifier: ^1.3.0 + version: 1.4.1(typescript@5.9.3) + typescript: + specifier: ^5.7.0 + version: 5.9.3 + vitest: + specifier: ^3.0.0 + version: 3.2.7(@types/node@24.13.3) + +packages: + + '@esbuild/aix-ppc64@0.28.2': + resolution: {integrity: sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.28.2': + resolution: {integrity: sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.28.2': + resolution: {integrity: sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.28.2': + resolution: {integrity: sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.28.2': + resolution: {integrity: sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.28.2': + resolution: {integrity: sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.28.2': + resolution: {integrity: sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.28.2': + resolution: {integrity: sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.28.2': + resolution: {integrity: sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.28.2': + resolution: {integrity: sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.28.2': + resolution: {integrity: sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.28.2': + resolution: {integrity: sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.28.2': + resolution: {integrity: sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.28.2': + resolution: {integrity: sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.28.2': + resolution: {integrity: sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.28.2': + resolution: {integrity: sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.28.2': + resolution: {integrity: sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.28.2': + resolution: {integrity: sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.28.2': + resolution: {integrity: sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.28.2': + resolution: {integrity: sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.28.2': + resolution: {integrity: sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.28.2': + resolution: {integrity: sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.28.2': + resolution: {integrity: sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.28.2': + resolution: {integrity: sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.28.2': + resolution: {integrity: sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.28.2': + resolution: {integrity: sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@jridgewell/sourcemap-codec@1.6.0': + resolution: {integrity: sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==} + + '@napi-rs/lzma-linux-x64-gnu@1.5.1': + resolution: {integrity: sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ==} + engines: {node: ^22.20 || ^24.12 || >=25} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-android-arm-eabi@4.63.1': + resolution: {integrity: sha512-UZ8sUxPTiHWYX9QNdJedb1kDZSpS1t/VPWBWGSgqHNi9w3Cu6IXvu2mzbhiTiPvtrqgTQJ+zqiAq2iPIPilpaQ==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.63.1': + resolution: {integrity: sha512-cQ4nFQABN5cDvDpbvJ7bMStCpnaVxynZrRMfUJYgxcIk9Sh54FIO1vtfkg0B69REjER77ioZ/ov+eAApx/KmLQ==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.63.1': + resolution: {integrity: sha512-FQNqd1lRy/0QhDk3xeRIkSBiCpXCiDnZO3YLVdcDKN1UBiKToNftCzcXYNLshmPDUMlu2TdeS8tGcsU6f3YF1Q==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.63.1': + resolution: {integrity: sha512-pvD16V939D3CloK0+qikpGaxiPrDUXTe7Y5cWOMkMSy7m1cawa8EGy/kXYi/G/cKAC4HDAbSnzCIk1WmsoOKXg==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.63.1': + resolution: {integrity: sha512-pcFGeL2345VwdTnJhA6zLbew+YgWB0qBG2+dMtXjCicf6+rm6kO6cOoh5VnTe0ZMrMRgRyuHmCJxZWrIdzYuOw==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.63.1': + resolution: {integrity: sha512-mRJlqSRulVzcKq/LKA6ICSIc3K/l4fzlVn/gePn2nXIHy8seRi5z/eeRE0d/XMBxcMldiXtQTSpRj0tkkC3g8Q==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.63.1': + resolution: {integrity: sha512-YDUNvVM85TI3g/1OpnqKP1h4NeW/j64DfWMf+G3M809xNk1bJSnpFp4sh83NpmVE5DXnkh8ULor4LTVZKoYLHw==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-arm-musleabihf@4.63.1': + resolution: {integrity: sha512-7Mcn71p9ZuQFAj+h+dhQXy/yeLePRS2yKRnmW1DijA9thKO5qap0GNOIQK4yQ6iP3SU0Mrb/yWo8h8vgRba8lw==} + cpu: [arm] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-arm64-gnu@4.63.1': + resolution: {integrity: sha512-4YiLQTX6U4CSl0L9cluep9A9W6UmTfqBDc2/CH6wlu54pl4E7Jn3cOD8oxzvBDEGk/JMKgJ47C8g+radF7mwvg==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-arm64-musl@4.63.1': + resolution: {integrity: sha512-2ra8F7w8OquwZN9z2/fKFnli69wa8PLwaVzRMIPGb13ByMJwC28Fbp8YcVGoUhlYMTt7j5j9bNgpysrN2UM+vw==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-loong64-gnu@4.63.1': + resolution: {integrity: sha512-Sy20ncyhjmBP0Ml+UvQbimjlk6VFgjW5uNP+qqwHB00mTE8Bl2C1TuHTlRwK2YoXeZbee5lP2XevBWVkAQAtSQ==} + cpu: [loong64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-loong64-musl@4.63.1': + resolution: {integrity: sha512-noITLp8oNjYliPnGWmLyelIHwULGqbHloQHGw1rtxbWhTuWooRpnZarZQJ1y9EUC4szuCusCc+HEpUtxpIwYvA==} + cpu: [loong64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-ppc64-gnu@4.63.1': + resolution: {integrity: sha512-hlxxXd+F1mWiAcaFR7Sv9ZQT6m6UfI8+Vy/kFJzztq2pDMU/0wZ9sish0iszNZvsQDo8Gc0i5yuFEOz5dDf6fA==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-ppc64-musl@4.63.1': + resolution: {integrity: sha512-EF7OpqQTQ/BvGqLzUi4rEHuagCV9MugAUXSHemwPW5vxZ75RR+jxO/2j95Ph2dalMpFHSVECjRoioHZgA9zOYA==} + cpu: [ppc64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-riscv64-gnu@4.63.1': + resolution: {integrity: sha512-wQO3JesW9PRkwlabQ27y7sPfVOOTLRG73I4F2UYHG5PXun3J9U3y+b7ezVKSYbsvSKGQ1k1cq8Qlun4C9kLt3w==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-riscv64-musl@4.63.1': + resolution: {integrity: sha512-ouAGwhO6wHRXdnOVCOsB0tRFkA7nhNB2Nwax6oECXN0YiN8EYUTBAOudADOB1PI+yDL61TeNx/u7MVCzksNbkQ==} + cpu: [riscv64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-s390x-gnu@4.63.1': + resolution: {integrity: sha512-q2R38Sn+1J8RxhfJ+T54wSWmyKXWec+9jgDfqO2AtArEqHO5R2aeayp5H5OYLr5UYDVGsVaZPEFUooMhYCdz5A==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-x64-gnu@4.63.1': + resolution: {integrity: sha512-gfI5T24WLLuFfSKw7Go/zDXjAAV0fny0swTaDv+WjK7vqcw4cRhFfdsyKL1n+ukI+ooBxn3bVQnyrn06WpI50w==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-x64-musl@4.63.1': + resolution: {integrity: sha512-4h6XqthmB4Hspji84wvgk+ElodTsGj+dbZqHJHHtKxj4mYq0ANSEEPX9ys3moJueqsRjwpaJYH7874Itwnj2ow==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rollup/rollup-openbsd-x64@4.63.1': + resolution: {integrity: sha512-dlfCOa87o1VAYegLQ9EKilx2JCeRofiyPGhTCmqnuXZ6bMPiycO1rq1+sKoulAp7pGLIsTIw+1x5R+zgh5LhhA==} + cpu: [x64] + os: [openbsd] + + '@rollup/rollup-openharmony-arm64@4.63.1': + resolution: {integrity: sha512-cjkLbOlfcm3QGhMM1J5zaZjsw1GggbN6rw9UTSSRrPrR1KkcXnN7Uq9rPw34xImQ9VOY9GN+6u2Zj80B9ptkcw==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.63.1': + resolution: {integrity: sha512-Li1KdUnWGE4N3e1F/B4RTB1ms+nG4WBgjByO46pkeBVX/2UBsY53xf5vK9WygVmnH3RwncIST7lkSdLSY6P9lg==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.63.1': + resolution: {integrity: sha512-t4ZYOSoLTgwhuFMrmTMLx/+i1DQVK7HYqMc6kY46EApwi8X0nIVphzdNoThU3xt6n+N5urG1/gxBdCaKDLavfg==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.63.1': + resolution: {integrity: sha512-RgroPfMmKlD1RzSDxvwgcPiy2HNQKoYV7OmwIXDsk73uKW5t6B/V8KIy27SMv/FNXFo/oSBtWc9J0X7t91ezZg==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.63.1': + resolution: {integrity: sha512-at8QVep6S3h5Y6gSbdGU06bRY5WJkf6WUduM9YtvYMbYhB1MOFfUgc6kehitQXzOtMSaT70q7f9ydPhpqu821w==} + cpu: [x64] + os: [win32] + + '@solana-program/system@0.14.0': + resolution: {integrity: sha512-Pjs2RINZHYmk/pqWNBCuQmfNjZT9woPJ/w7QkzzCSwcqcokbARtxsnIdgj4lJVxvr1DuxG8JGIbKnq6z1QRY6Q==} + peerDependencies: + '@solana/kit': ^8.0.0 + + '@solana-program/token@0.16.0': + resolution: {integrity: sha512-VuFIu5vXsw1zwqls4/sGB88234oucmpuig553A33UnrbYnPZ8yXmqLYULBD92/k1pCGnMK+NMLWvsKzlZQ/1Kw==} + engines: {node: '>=24.0.0'} + peerDependencies: + '@solana/kit': ^8.0.0 + + '@solana/accounts@6.10.0': + resolution: {integrity: sha512-+FxfDOrnifoPlBkF+fr8eeQdgM6xtIgAg9xKMu3WnIz60oZd4Xnry6+ff6t+ePPoZZp397FSg9ZJet68VCWm5Q==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/accounts@8.2.0': + resolution: {integrity: sha512-An3BICrQJQ7jR5EIgXzYnaKyCE7+ZusW9xX8m6Vj7U2cKo8t6Y3PTQ+aMjEajwzsQfxEL8QnpClFC9hdoIu7MA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/addresses@6.10.0': + resolution: {integrity: sha512-vEoCGBTxG0HCERAn84KXkrJjl+pDaNzOpZ0qbgcPS98fYxP5yzbKB8SNOY2bzrbkRUmmw5Q3hqTRERemUN2Gcw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/addresses@8.2.0': + resolution: {integrity: sha512-7Okh8u7d3QrKu7ltJa3PASniUhasn1cdbcMQ/8gpGsmHQNCvdtAmvw18xSTdr4m62RJ/0cI/DtTVQyNwooeAXQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/assertions@6.10.0': + resolution: {integrity: sha512-lKSAdVo+P/6Lp4vs6shstXmFOpvxrABwn4o1462tb7sKkNapk6o9pPFVPGw4DUgPS3WqWRs1j2tmpuVjhQRntg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/assertions@8.2.0': + resolution: {integrity: sha512-izrnF8ZsviZDK0WCKl9ha5Ht4TNDHoU2QzMrPYOqkSkKkVh15p3MjTRXVFnM4CA+Xigtu8y8OPu2UnQNcAUVHQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/codecs-core@6.10.0': + resolution: {integrity: sha512-nfAl9OMGo4HanIMxGsQoVB7BxMoqBCYEUxl8oEAZZ09pDxnaXQZkTRXEwPPccag37XfW1ciPd1vWPKwB2b0HHQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/codecs-core@8.2.0': + resolution: {integrity: sha512-ORwzswFXbqNqlyVigogFIrn3Ge5cpDQkuMY0u3M40HBwHcC6a79uqM87DpoZypncKJDWA1DfJ/3w9hhTGumYAw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/codecs-data-structures@6.10.0': + resolution: {integrity: sha512-CNasJW3bq5u+632Zt5aJ8rOjAjv2HyenpV8o9kAIqdmV4CBpjCCoBnKn8LkuR/sbeREZxJYfhKTXO/9ruAkw7A==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/codecs-data-structures@8.2.0': + resolution: {integrity: sha512-uq59oSAXM9QR+cO7R3JmSTxBiNNJnayVWz2VHBdhhCQS8DEmd6hhqY1RVmPTpFtE0Jix5MkRV3Bu5GTmf6Y66A==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/codecs-numbers@6.10.0': + resolution: {integrity: sha512-CcM+wX4zOiA9zkh8A7t1787A0Ehgmu5+6Z2tKoHew6cNw/dkaUTPa8JnNHbvfsLC8dfHC1BhAEJl86sKmRsfkQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/codecs-numbers@8.2.0': + resolution: {integrity: sha512-GTOYzyk0SxQJS7MAN9zsyax4RFUtQDYzkVcpRf0Zo7eOy2/hPfuih09VJL2YdLPBJBcg8satdAYBYxxC282PYQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/codecs-strings@6.10.0': + resolution: {integrity: sha512-zlaqkg7K6F6IN4V/Ec8TWkTn054gxv7ZLagvGkuEyAdPQ6BzzsehOm2TqCuyXgJJTCGPLY1bEk6yH9NxANe0kA==} + engines: {node: '>=20.18.0'} + peerDependencies: + fastestsmallesttextencoderdecoder: ^1.0.22 + typescript: '>=5.4.0' + peerDependenciesMeta: + fastestsmallesttextencoderdecoder: + optional: true + typescript: + optional: true + + '@solana/codecs-strings@8.2.0': + resolution: {integrity: sha512-Dt/+rJ6gmH/OcOtvrhm6CtbB9jtVOGMxcIXoi62eNXw39Z1kJyN1gkqTjzBSS8Xb+X5lfkL70GHE9EDBb1JmqA==} + engines: {node: '>=20.18.0'} + peerDependencies: + fastestsmallesttextencoderdecoder: ^1.0.22 + typescript: '>=5.4.0' + peerDependenciesMeta: + fastestsmallesttextencoderdecoder: + optional: true + typescript: + optional: true + + '@solana/codecs@6.10.0': + resolution: {integrity: sha512-lLVuxod4ChWp9i7OvpgIykYG8Q9OGPVXKnHM9VlzDDLylsx7Y1FoQL00sHa7PqFkJVmkBufaA6dcGbQ7FU+lAQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/codecs@8.2.0': + resolution: {integrity: sha512-kn2esyzFznx6Pbb+8FUe3YNKYRZUB8H81pCiXSIe1+0WJ44lRhZHMo0s4L3FQMKhWHOnlV30sWeIg8taHLVW7g==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/errors@6.10.0': + resolution: {integrity: sha512-KBLAxCtAXr357JNhCyIDQXWbuSj5vN6w+28FSfcYY6OOSiphmXLAV3V58jgV0C6iNbIzFJFi6yatFyDTdeJsNg==} + engines: {node: '>=20.18.0'} + hasBin: true + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/errors@8.2.0': + resolution: {integrity: sha512-BXc9mafl3SOnRL542jY02ezBSXHgqQOUCzREN/vvh1ASUPrUB3iorOEc62cSxFdDU4aDVMcugowJawmVNTXXSg==} + engines: {node: '>=20.18.0'} + hasBin: true + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/fast-stable-stringify@6.10.0': + resolution: {integrity: sha512-iCNed27wk6PKSS3QUtHovRfMWF/jbVWogs2vB4tukKUCsqG4rDfDInIwZ6ur/nY6XTrgi2gMMdZq9GAUlWsbfw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/fast-stable-stringify@8.2.0': + resolution: {integrity: sha512-OND76Qsng/fiTVSUvaNZFv0WKEULlwcGRtgeIE2keA2xYoHYNTSoD6mxv4iWANfeDo4EH7D/HnOwnGEFXMjr9w==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/fixed-points@6.10.0': + resolution: {integrity: sha512-ZkKL0alXH3L7/wMiVG8YUuG8qBKunlM810+YBD7nUPRhifiGsX1zwADViHLYNqLr/jUk0mTYFUcKznTpB/K+Gg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/fixed-points@8.2.0': + resolution: {integrity: sha512-w19JKErcbbENZzw4B+oBGwJXVKMIOi8TC7WxBawmpuv0XJSk6LP6surosg+XeoBHhtEsVCNHDtizi0mAS6OmMw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/functional@6.10.0': + resolution: {integrity: sha512-P8cevu4mAqHTXC37h1TVoOh8zhWB2tlOI/R9vWjYPpcLwcyWf8p2qq4LEGHl5kY+1C+4PNX39HsmCocXOPCDkQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/functional@8.2.0': + resolution: {integrity: sha512-+oTPl9yRZBbppUZU8qs4eu93iWPvs4Ij+HELPHISxLFo/cuG2YZGTDcWBVEzc8XEw0DUwwBOvou/wP7v1SnH+A==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/instruction-plans@6.10.0': + resolution: {integrity: sha512-YG7mo4zykzdc6ZTV0BuN6pveK9qeBySzlYYerq578A4eQu3xcypMAYRGAvhMZtWTanjjmD6CKtM0M7kVp0TNxg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/instruction-plans@8.2.0': + resolution: {integrity: sha512-DDVHBAPifG3Q0s5e2hiBbfvrruLb3AhumTupDK+3f3f7MDc0Dth6rX054HtIINloqbFIw15f6/A3Z4VTh74CTg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/instructions@6.10.0': + resolution: {integrity: sha512-0TToYF+8LXQ3ofPMx+yF6yaM9l4YJvcAPMy0qV5JsrBUFlWXBSANRuudKBQLHMvb+a3OiUTq5X7omuorKMBB3A==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/instructions@8.2.0': + resolution: {integrity: sha512-SFts84wW6hDXGSrLK5spl8nbKxKns2aR+S2ar0Zi3I0bl007heyoO7UKyxAoUvhfhObIfEIMuy2/qLoo6vDcjQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/keys@6.10.0': + resolution: {integrity: sha512-26IRfdm/hTUCmM7MeEeX0ULSbCM6OzkZTkfkrPircqmRM7xyNqP4hq7u0P7wjb9dl7NfgyG6K7cdvUxrj2e3mA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/keys@8.2.0': + resolution: {integrity: sha512-DezFZ0/ya98nILq+eSeq9fu9onVfqQYb7mtuDctdWxY1QFJvix562zkkFuFqnjOLL7XMEpdVPMxxQOzZ33wGCg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/kit@6.10.0': + resolution: {integrity: sha512-/WnnQp3uARh2JCFSfAakejTAqwmXVuMVTcRn5r2yDwY2yzZ4R6mt/Cl59VPimVLNSoTyN/KsEwhv9omr3ERazQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/kit@8.2.0': + resolution: {integrity: sha512-1BfmnYmWe17u3RRX3HuNxjWkr2/n9Bai+yIG/XjMpgviobF3n8zsisZBJHPH2uORqvjkTFnOqGXoEQC8vUZHzw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/nominal-types@6.10.0': + resolution: {integrity: sha512-9ykyBBvnkInH7fCacjJi7zu2PJyd+OCt+VTjIISv070fHzKIMFqZqJJ/dJ0SRH2aHwfB3n86iVsmtBtuxi4KKA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/nominal-types@8.2.0': + resolution: {integrity: sha512-iuDE6ewgT7LJOSVC6UK4HR6n8INujujbglYVVFWNK/xWKi5p1y8JCOEEWAl/htK26LhLC51A1nMNfmBmTjP3ZQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/offchain-messages@6.10.0': + resolution: {integrity: sha512-RiEgAueeMkFMC1suOXBIcmCZgtXRxy24yk0DldPB37bB4zwOF1SAaRjNRPjIkGK8RhCYrEpPosnzLyavw9ueRg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/offchain-messages@8.2.0': + resolution: {integrity: sha512-yXfVtK1VoQ/Eyz2jH/1+avixhYcpCPkGkXuiXxA3Vf73WCvniC8mNVQ5ppsV+OqCNw62mxaFMmNiVgiAQapKuw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/options@6.10.0': + resolution: {integrity: sha512-RO9UT3UYD8/Cu2uM6ZXbKvLeMnVD42+g9JRds7Pfs4AhiOyg4R4TJrQUAppTgavPTO3PBRlWtWOC05ZH/yAIbg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/options@8.2.0': + resolution: {integrity: sha512-b3//UzZe/uBaIpw4fT/nvCOghh5IHoNkW7FCMA/nzvQ48A16n8qpLki9/+lLHi0V0o7/Jz5Sof0UYc0aSf1Dig==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/plugin-core@6.10.0': + resolution: {integrity: sha512-JE70YTQOfFACVFGvoJon4Scc/eHUWjMu8Ovo35CcV2kHTAHYMCd4UkBd2gmlhK0vRMMomsQi1ZLPlAlTq0OoUQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/plugin-core@8.2.0': + resolution: {integrity: sha512-V7oSIhYXbUzjd5LUY4tbSUnyBka1hmULPFKuqxNzYxeY4eLI7S8GmTOg7xg6tOC0bJ+HLPvv64asuMXAn/PklQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/plugin-interfaces@6.10.0': + resolution: {integrity: sha512-vr0/l9wcM4orwGr8cjkFWaJ9A4HvzuAv00jMFNMg0Spd0GZqnwnpW+D/fXa1lIJnTRaF3EeEjLh4VjKU037T0Q==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/plugin-interfaces@8.2.0': + resolution: {integrity: sha512-goOhGI493Fq+xhZ8JKl9/FDVFd0SJdkv5Lh0L2ubqekzUiGRCvHNwgXL8nVS7fso2UxIssDQmYKwXvubfhBVhw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/program-client-core@6.10.0': + resolution: {integrity: sha512-4PPbTLdC1ylHIuvhOFDP8RnSkXPCFjNFWGslzc+UFKnoR4ajzBcByX94jmaruDMk5ncxgj7tr9pzJTvfGHIaMA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/program-client-core@8.2.0': + resolution: {integrity: sha512-miQ7qKW0d0etaa2YAehGU3heV5Y4ip5BBCwZXb/yg8yWndTt4d4E+8z+5Q/oS5kOuFraOFYr+Uev7SQKngNXBg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/programs@6.10.0': + resolution: {integrity: sha512-qn/HeLP5KGUJXVub3fyGe69/rWaLX4jzwm6V/1pNxJDbdF+MBdgn18hP6F+VmhfdNmwK0lue3J/1HQ1UTMuQeQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/programs@8.2.0': + resolution: {integrity: sha512-yttl6ps7G9vM83pdfekyregTIqmRThFpdcrCIZ3y2qOLZ63KVxVMhNJ8kn8FrX3MyWh5rr/hTWdWKc4/U12Epg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/promises@6.10.0': + resolution: {integrity: sha512-oJSIn+VBBMWDo8oqw7RV3tI6Jih+Ieup6FcQLYLDUriaeo7+8l1Zdezl8zh7SIfeU4lOfAbRg6mR0huaS/Lltg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/promises@8.2.0': + resolution: {integrity: sha512-i33ll+en6/Qcjw10gPeikCmU687W1pQNZPxirEuRWO/+PhE2qDQ9ZODgEakVi/1k+vSwL8sK941qfWig+3D0dQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-api@6.10.0': + resolution: {integrity: sha512-RjPIVsAb/85P1ptoO3WpC0x7QG6gG/e4q/3lo6gbSznUZOcoM+8sSBnCX7BwP1ZkCDS6NK/ClXLnhhhYZx+OGg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-api@8.2.0': + resolution: {integrity: sha512-lGvk1xeOo4cbypuD/5AAkJPHv5E3g7lqbzRIxZhsQPBkK+knVuEb7e3UncOnjuWkijZoFiB/k+Rfk83gmlhdpg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-parsed-types@6.10.0': + resolution: {integrity: sha512-5275mvSV1mxhwvrMVa+K7BU/nAetpHfcb+8Ql9rtA8RRf6DyiimFQFZUukE4Ez6XJihEpCHNy98yhkgai9wytQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-parsed-types@8.2.0': + resolution: {integrity: sha512-JJ4BfUlX8eCIUh3zm8jTkHkNLf6HyY9UjJmi4GPicFPJZ5MXSUeh42eaSxvHszXUoS7u9V30kTt1hznwfF5fqA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-spec-types@6.10.0': + resolution: {integrity: sha512-NDZrKyZrJk4HaMFhTE/lAiMB824cWAodKqDHyKi0UteHU9pyRmil3BN1jt7e+j08mwMWwfklSgyrTaq52g6DIQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-spec-types@8.2.0': + resolution: {integrity: sha512-pKOezoP0vuVwyjUKcS4Ewl3Mm/owv/16n7RocqFC3nx94qtk5FpSOAtielUHzBQ3JUgRLJrSKonw2yWxqgtVFg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-spec@6.10.0': + resolution: {integrity: sha512-yQdbWw5mZEWrwsunHR9NHkuhMXIB9sPOObwm18D53v5tAJnxTB0IcHvO647XqFDLTK/yQ4AdDtlYD1vsY07AMQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-spec@8.2.0': + resolution: {integrity: sha512-fR0hv/NP3K4WNePK9+97GYrDjzoN7kF0hlffRlSygksAC0FKvtKQ5lPBMg0ptWtswInp8Kk7Cz1zTCf6S+wLUQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-subscriptions-api@6.10.0': + resolution: {integrity: sha512-CRPQoTtT1cOwOQUsqS7jgo7wYdAj7jB5ab/UmMPWVpecf2FNMhWhgvxP2s82M7VkDGTGl13qaQ0WySmi7Egrlg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-subscriptions-api@8.2.0': + resolution: {integrity: sha512-37UHtjFmBUagtRw9NeWViTqSJlExyuI2j88m3jJSw9c6WRw7lLzUJIRGA51ArYyhAyhtAoGjXpUZiODKSE9lEw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-subscriptions-channel-websocket@6.10.0': + resolution: {integrity: sha512-KkqP1186HELPlJftA88SNAT2znR8knCVzsUipXVzY4zfW8sN3LOa0ePMzh9VZ/V+J+raTt55laR87ovAO0n+zw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-subscriptions-channel-websocket@8.2.0': + resolution: {integrity: sha512-R9pk8Lq030M1+bAz6e2qKv6ldGLmICFYJOaLxVifyDE4VBb1BGV3Tt1VTAaFIfHyYucmFmxGRmPFmedA3Kysqw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-subscriptions-spec@6.10.0': + resolution: {integrity: sha512-nWMwGaG4ulzeX2sskY5TywXF3cwEd8FDmUpLe2JBWxE8XDAOGOKcsYPYFcBgb8ee9KqfPT2PTNdcz9jOhJf34w==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-subscriptions-spec@8.2.0': + resolution: {integrity: sha512-ajcncAnQ7XzE85MZ8uajjO9E7NyLwLWFVUYG+y82vb04ZWFRN3DrMswIC4T5m14OkU3RY/Z2WGxC9nT1W4wPWw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-subscriptions@6.10.0': + resolution: {integrity: sha512-6mfuHp/K7unFKCOTCCBC9ziEGnxe2tyJ74EbR51QUnBeCUdYD7Hhdpxic1WRSJ3UeNW/mG4OzFM6z8Wi64Eh9Q==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-subscriptions@8.2.0': + resolution: {integrity: sha512-pHf/RiDqIHeGp2blseYRVjzWz4WUAY/5vkOya+BQhjx+7Odr/J19G3ZVDwExgtU95UhCDL9gVHPyAgKr0mNcUg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-transformers@6.10.0': + resolution: {integrity: sha512-2nFUrVTiE720pJOY4XKx3HuYmishw0of/4oScu76YGm6O8wsmvFvPNAkrEinmieWXQkfpBfRvLZmpl8PaAy+ug==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-transformers@8.2.0': + resolution: {integrity: sha512-tiMdJ9ZRgqANBNxlXK7OSDbwixAy7K1MzowzO7vNdlJbV+0WN0Lm/X5hEhKnlU42AD+clC6t9qZjVbg7BhQrqw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-transport-http@6.10.0': + resolution: {integrity: sha512-JrdNuYi0nBbD3X8JUtgX1dQJwIwz/WJvmigDdELysXfGB2bTJpfjqGDLhCLOz2sRl66FASIEqgG/LVa2C9VXcA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-transport-http@8.2.0': + resolution: {integrity: sha512-eOkgv52ZSMFLYNQaCsvxmPciZeXplWaPjbEcl9iZkGOAp3B2bO6KyMg8trEjaZNfcLC15+CpXMOZpMArXXSBCg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-types@6.10.0': + resolution: {integrity: sha512-zaSecTfCPvz/vcoAmKD6XoRstGHTr1EKJBD8T9UcpEFFB6CtF6DxerDB+wrzkamuT6msmnR2DWXMrYOGDAsgIg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-types@8.2.0': + resolution: {integrity: sha512-rGF2vB8Bk0G2DYNxgEbDlANk+KirQGHVS1qRLxsi6OxACrgsSrGqrp0Onb5J8HLRMTEF+QrbbORDz9TQ5Q71fQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc@6.10.0': + resolution: {integrity: sha512-EwxsqoD+NXV+m+iobnWNtATD93gTgaNsOiQOzYB1/2e+8S6fl6obdNPB55yfXgtl4jt6GV6/ae4xuPhLv76vvg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc@8.2.0': + resolution: {integrity: sha512-Of/2KqDf728HxKzJlwlZRvRSrgpHoDAg5+t/3RwdXWBoRQ1r3FXqwBXOrBT2g47w+fUy1iJcy5XZ7LXnXBXPIg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/signers@6.10.0': + resolution: {integrity: sha512-+vtCc+mT1FpGxrA5oL2aaMxSHiMJ2hH5PcDIfjo2XJkHz2klZiCZyT5F9+zpltc9vdi1QTElQq59Sfplmtd33A==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/signers@8.2.0': + resolution: {integrity: sha512-wfLiDhtPMnE9Mn8IeSAJ0RMfCyHUqeNZllFLfgDY3RUsCf5s9EgMC5U+HNSvtEWJ8ABGWWR5nYyWMXTWiMeuPA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/subscribable@6.10.0': + resolution: {integrity: sha512-VsR6XMwkiDBkZJUcoGkEOhf397pOV75gKCL9Bx8bpi2T3Bbs0CxUpMn4yaUgAnRba3eXmjbXMNCXjttfa6sKbw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/subscribable@8.2.0': + resolution: {integrity: sha512-ATJBeJkaCUIxU3JWUcgfOjnOM3nn9qDfTigEkr0Cp3xFzIHnIVwis3W4Hcc/de1z0uvOXQOIYroahDr8H+djOg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/sysvars@6.10.0': + resolution: {integrity: sha512-cG13p1+onxz+20iWjwWQr1Z1jQwPm0fnjoW75fqZq7p4rVCie3L2sXvaJsYPjWKrUvpOzOIEHnqZGkG05rCpjg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/sysvars@8.2.0': + resolution: {integrity: sha512-kwhOwBfUvUGuGGGnwTGHtNVQ02O3YCfXpp4xwUhe6bjUyp9M9wEmf70up6I9x2D4uB1nHaZRfco1CXfxhcH8sg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/transaction-confirmation@6.10.0': + resolution: {integrity: sha512-ULvtg65qfenh4T/GYcIlKSUv5EqDcng9UN0dxbHU4kuZdR2e0B8HN2xDC4WhcFQVeFJSbTZmaYFkeTY/Y4gfGQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/transaction-confirmation@8.2.0': + resolution: {integrity: sha512-3L1LlMQ00l2kb3pcejvQ7vMKzyFayFhc6PqvZyh3M0/FNPfsc4z46yUf35I79SI6cuFWy2VkzA+a2ylOuCNC7w==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/transaction-introspection@8.2.0': + resolution: {integrity: sha512-unha6ugKrZa1TcB5Slnxisa/uQC56fyYi7BDvfCVI60OLEowtOTTvmJMKe35ETMzbimjBEPE/B5EgbydOHVBnQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/transaction-messages@6.10.0': + resolution: {integrity: sha512-s7v8G3BTxGlKYIj3eWCG0g1296v+1LBt16mVnlRH5FuyaJ5AdhlhtRho5HUDpdwE8EXun+y1c48V6uhcZ8wdbQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/transaction-messages@8.2.0': + resolution: {integrity: sha512-+0U4iR/WRb8UiBXRhJJUY0+BmAOv+bQj7fifUF6o7x/IPg/K2Y4CmH4m7dOT2yhcg0KDzZPkXidXLm6saBX0Hw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/transactions@6.10.0': + resolution: {integrity: sha512-VADSqP9OTYmhrox4pcgDd4+RjVmednXSE0+8Y7SPK4PN1pK5Az2RJ0nSsy0xcTnaOr8mF/crwFktqPrRQwSbQA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/transactions@8.2.0': + resolution: {integrity: sha512-WfbzFTf2BvpW14OIOin/9Mj29XE5GJVORAnziDK+GEiTPnruNzNkHBrd2kt/ACg12dh12kmutDj5WI3pzrN3Bw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@types/chai@5.2.3': + resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} + + '@types/deep-eql@4.0.2': + resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + + '@types/estree@1.0.9': + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} + + '@types/node@24.13.3': + resolution: {integrity: sha512-Dh8vAsV36ig5wa9OX4pXvMc9D3Veibfw2wix0CUwYODLD8nkj9UsLjASr49nPg+2eKzxhBV+v7L8pXvT4e639Q==} + + '@vitest/expect@3.2.7': + resolution: {integrity: sha512-E8eBXaKibuvH2pSZErOjdVb5vF4PbKYcrnluBTYxEk1l/VhhwZg1kZQsdtjq+CsF5CFydf2Rdkz7jDHKSisi3w==} + + '@vitest/mocker@3.2.7': + resolution: {integrity: sha512-Trr0hYO9CM3Wj6ksWHRhK9IZpIY6wTMO5u/MqXurMxT57sWBaOPEtP3Oq60ihZuh5JsiagKfz95OcxdEP6dBrA==} + peerDependencies: + msw: ^2.4.9 + vite: ^5.0.0 || ^6.0.0 || ^7.0.0-0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + '@vitest/pretty-format@3.2.7': + resolution: {integrity: sha512-KUHlwqVu0sRlhCdyPdQ/wBoTfRahjUky1MubOmYw9fWfIZy1gNoHpuaaQBPAaMaVYdQYHJLurzj8ECCj5OwTqA==} + + '@vitest/runner@3.2.7': + resolution: {integrity: sha512-sB9y4ovltoQP+WaUPwmSxO9WIg9Ig694Di5PalVPsYHklAdE027mehpWF2SQSVq+k6sFgaivbTjTJwZLSHbedA==} + + '@vitest/snapshot@3.2.7': + resolution: {integrity: sha512-7C+MwShwtBSI5Buwoyg3s/iY1eHL9PKAf+O1wVh/TdnjXUtkoL/9YQtre90i4MtNXM6edP1wJ2zOBpfCyhIS7g==} + + '@vitest/spy@3.2.7': + resolution: {integrity: sha512-Q2eQGI6d2L/hBtZ0qNuKcAGid68XK6cv1xsoaIma6PaJhHPoqcEJhYpXZ/5myCMqkNgtP6UKuBhbc0nHKnrkuQ==} + + '@vitest/utils@3.2.7': + resolution: {integrity: sha512-x6BDOd7dyo3PFLY3I9/HJ25X/6OurhGXk2/B9gOZNPF7XDVjeBK4k01lQE5uvDpbuheErh91qYuE1E2OEjK3Rw==} + + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + + cac@6.7.14: + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} + engines: {node: '>=8'} + + chai@5.3.3: + resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==} + engines: {node: '>=18'} + + chalk@5.6.2: + resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + + check-error@2.1.3: + resolution: {integrity: sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==} + engines: {node: '>= 16'} + + commander@15.0.0: + resolution: {integrity: sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==} + engines: {node: '>=22.12.0'} + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + deep-eql@5.0.2: + resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} + engines: {node: '>=6'} + + es-module-lexer@1.7.0: + resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + + esbuild@0.28.2: + resolution: {integrity: sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==} + engines: {node: '>=18'} + hasBin: true + + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + + expect-type@1.4.0: + resolution: {integrity: sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==} + engines: {node: '>=12.0.0'} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + js-tokens@9.0.1: + resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} + + litesvm-darwin-arm64@1.4.1: + resolution: {integrity: sha512-6dofWLOxtknSL0W6N9W3f/kdnitsJ3xR0oE1W37CLcfd5kX4qCMVbaejZWJkLo4G2JzAk+hFZi965Z2OPyJACg==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [darwin] + + litesvm-darwin-x64@1.4.1: + resolution: {integrity: sha512-Rjyg6SfnSKAO5/vMpnZpIHTcBWEUzjFj/GshXwzdyiWorrpC0poQjK3OJ9RJneJW2YDd+oUsGZCfwAplTXPGfg==} + engines: {node: '>= 20'} + cpu: [x64] + os: [darwin] + + litesvm-linux-arm64-gnu@1.4.1: + resolution: {integrity: sha512-hyL/tcuFisAwNEwVzDGjtDRuLYDc+8PoX9QZU/M46vsLrdU2WCBU3g4WdV5z0z1nPl16TzcHVboqydyBy3ImFQ==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + litesvm-linux-arm64-musl@1.4.1: + resolution: {integrity: sha512-Folc4nWAXwkWvwK5iqf3C74eNAPRERg8Yn2QGVW+6pMgCXtaQt77PuIB9m32mLo+W+LZxiU+t3et0ZiFEm4YgQ==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + libc: [musl] + + litesvm-linux-x64-gnu@1.4.1: + resolution: {integrity: sha512-sAKax22lAMS0DpWQcT6ICt8vs6phEjRJXT84LhhftnlNkcU03b0RJziFDr34LUTrkY5SMi/uqZEy0T86Xokg+w==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + libc: [glibc] + + litesvm-linux-x64-musl@1.4.1: + resolution: {integrity: sha512-kKsOVhF7o8/sMiP6mgZCoIYr7zWEzwOBQdC0WrWp29JvOJpKOOgz3jioFdgWv/LnSYfkbJ+wZNWI8tMhAkmNOw==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + libc: [musl] + + litesvm@1.4.1: + resolution: {integrity: sha512-SGMdN6c44m5Deo27nZX7GIn42e/OlfQ4jIv0JIVxR3F5vU8ZbbjsLRGUj3b/r5jCITyN22u14JnuP+mhDyNLlg==} + engines: {node: '>= 20'} + + loupe@3.2.1: + resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanoid@3.3.18: + resolution: {integrity: sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + + pathval@2.0.1: + resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==} + engines: {node: '>= 14.16'} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@4.0.7: + resolution: {integrity: sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==} + engines: {node: '>=12'} + + postcss@8.5.26: + resolution: {integrity: sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==} + engines: {node: ^10 || ^12 || >=14} + + rollup@4.63.1: + resolution: {integrity: sha512-3Df9jsstwhccuEfmAMi9l8XUh/GOkVObmFTU7CCVBysEbcOZLl84jCtaAZMcPiMz2EGKsATzQcU+Xr3n/wU6cg==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + + std-env@3.10.0: + resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + + strip-literal@3.1.0: + resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==} + + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + + tinyexec@0.3.2: + resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + + tinyglobby@0.2.17: + resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} + engines: {node: '>=12.0.0'} + + tinypool@1.1.1: + resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==} + engines: {node: ^18.0.0 || >=20.0.0} + + tinyrainbow@2.0.0: + resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==} + engines: {node: '>=14.0.0'} + + tinyspy@4.0.4: + resolution: {integrity: sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==} + engines: {node: '>=14.0.0'} + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + undici-types@7.18.2: + resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} + + undici-types@8.10.1: + resolution: {integrity: sha512-ZpkgovMu+ALwfuo6Bgys8H82gHJ25d4ARMB51FD2BeLnUCDRgY6N3caWk3N6CtKR77gHmRKYHnLF723owNYPNA==} + + vite-node@3.2.4: + resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + + vite@7.3.6: + resolution: {integrity: sha512-4XP60spRGjSZFf1qYH+dJIkK2znL3zQfl9KkOV9MkkRR/3Dls0dxaBsQPTloEc5BLXWPL9vsOxopxyKoMmDueg==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + jiti: '>=1.21.0' + less: ^4.0.0 + lightningcss: ^1.21.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vitest@3.2.7: + resolution: {integrity: sha512-KrxIJ62Fd89gfysR4WotlgZABiz2dqFPgqGzX7s+CwsqLFomRH7777ZcrOD6+WVAh7khPQP41A+BKbpcJFrdEg==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@types/debug': ^4.1.12 + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + '@vitest/browser': 3.2.7 + '@vitest/ui': 3.2.7 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@types/debug': + optional: true + '@types/node': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + + ws@8.21.3: + resolution: {integrity: sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + +snapshots: + + '@esbuild/aix-ppc64@0.28.2': + optional: true + + '@esbuild/android-arm64@0.28.2': + optional: true + + '@esbuild/android-arm@0.28.2': + optional: true + + '@esbuild/android-x64@0.28.2': + optional: true + + '@esbuild/darwin-arm64@0.28.2': + optional: true + + '@esbuild/darwin-x64@0.28.2': + optional: true + + '@esbuild/freebsd-arm64@0.28.2': + optional: true + + '@esbuild/freebsd-x64@0.28.2': + optional: true + + '@esbuild/linux-arm64@0.28.2': + optional: true + + '@esbuild/linux-arm@0.28.2': + optional: true + + '@esbuild/linux-ia32@0.28.2': + optional: true + + '@esbuild/linux-loong64@0.28.2': + optional: true + + '@esbuild/linux-mips64el@0.28.2': + optional: true + + '@esbuild/linux-ppc64@0.28.2': + optional: true + + '@esbuild/linux-riscv64@0.28.2': + optional: true + + '@esbuild/linux-s390x@0.28.2': + optional: true + + '@esbuild/linux-x64@0.28.2': + optional: true + + '@esbuild/netbsd-arm64@0.28.2': + optional: true + + '@esbuild/netbsd-x64@0.28.2': + optional: true + + '@esbuild/openbsd-arm64@0.28.2': + optional: true + + '@esbuild/openbsd-x64@0.28.2': + optional: true + + '@esbuild/openharmony-arm64@0.28.2': + optional: true + + '@esbuild/sunos-x64@0.28.2': + optional: true + + '@esbuild/win32-arm64@0.28.2': + optional: true + + '@esbuild/win32-ia32@0.28.2': + optional: true + + '@esbuild/win32-x64@0.28.2': + optional: true + + '@jridgewell/sourcemap-codec@1.6.0': {} + + '@napi-rs/lzma-linux-x64-gnu@1.5.1': + optional: true + + '@rollup/rollup-android-arm-eabi@4.63.1': + optional: true + + '@rollup/rollup-android-arm64@4.63.1': + optional: true + + '@rollup/rollup-darwin-arm64@4.63.1': + optional: true + + '@rollup/rollup-darwin-x64@4.63.1': + optional: true + + '@rollup/rollup-freebsd-arm64@4.63.1': + optional: true + + '@rollup/rollup-freebsd-x64@4.63.1': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.63.1': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.63.1': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.63.1': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.63.1': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.63.1': + optional: true + + '@rollup/rollup-linux-loong64-musl@4.63.1': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.63.1': + optional: true + + '@rollup/rollup-linux-ppc64-musl@4.63.1': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.63.1': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.63.1': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.63.1': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.63.1': + optional: true + + '@rollup/rollup-linux-x64-musl@4.63.1': + optional: true + + '@rollup/rollup-openbsd-x64@4.63.1': + optional: true + + '@rollup/rollup-openharmony-arm64@4.63.1': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.63.1': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.63.1': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.63.1': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.63.1': + optional: true + + '@solana-program/system@0.14.0(@solana/kit@8.2.0(typescript@5.9.3))': + dependencies: + '@solana/kit': 8.2.0(typescript@5.9.3) + + '@solana-program/token@0.16.0(@solana/kit@8.2.0(typescript@5.9.3))': + dependencies: + '@solana-program/system': 0.14.0(@solana/kit@8.2.0(typescript@5.9.3)) + '@solana/kit': 8.2.0(typescript@5.9.3) + + '@solana/accounts@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 6.10.0(typescript@5.9.3) + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/codecs-strings': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/rpc-spec': 6.10.0(typescript@5.9.3) + '@solana/rpc-types': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/accounts@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.2.0(typescript@5.9.3) + '@solana/codecs-core': 8.2.0(typescript@5.9.3) + '@solana/codecs-strings': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/rpc-spec': 8.2.0(typescript@5.9.3) + '@solana/rpc-types': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/addresses@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/assertions': 6.10.0(typescript@5.9.3) + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/codecs-strings': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/nominal-types': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/addresses@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/assertions': 8.2.0(typescript@5.9.3) + '@solana/codecs-core': 8.2.0(typescript@5.9.3) + '@solana/codecs-strings': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/nominal-types': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/assertions@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/assertions@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/codecs-core@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/codecs-core@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/codecs-data-structures@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/codecs-numbers': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/codecs-data-structures@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 8.2.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/codecs-numbers@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/codecs-numbers@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/codecs-strings@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/codecs-numbers': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/codecs-strings@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 8.2.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/codecs@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/codecs-data-structures': 6.10.0(typescript@5.9.3) + '@solana/codecs-numbers': 6.10.0(typescript@5.9.3) + '@solana/codecs-strings': 6.10.0(typescript@5.9.3) + '@solana/fixed-points': 6.10.0(typescript@5.9.3) + '@solana/options': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/codecs@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 8.2.0(typescript@5.9.3) + '@solana/codecs-data-structures': 8.2.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.2.0(typescript@5.9.3) + '@solana/codecs-strings': 8.2.0(typescript@5.9.3) + '@solana/fixed-points': 8.2.0(typescript@5.9.3) + '@solana/options': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/errors@6.10.0(typescript@5.9.3)': + dependencies: + chalk: 5.6.2 + commander: 15.0.0 + optionalDependencies: + typescript: 5.9.3 + + '@solana/errors@8.2.0(typescript@5.9.3)': + dependencies: + chalk: 5.6.2 + commander: 15.0.0 + optionalDependencies: + typescript: 5.9.3 + + '@solana/fast-stable-stringify@6.10.0(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + + '@solana/fast-stable-stringify@8.2.0(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + + '@solana/fixed-points@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/fixed-points@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/functional@6.10.0(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + + '@solana/functional@8.2.0(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + + '@solana/instruction-plans@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/instructions': 6.10.0(typescript@5.9.3) + '@solana/keys': 6.10.0(typescript@5.9.3) + '@solana/promises': 6.10.0(typescript@5.9.3) + '@solana/transaction-messages': 6.10.0(typescript@5.9.3) + '@solana/transactions': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/instruction-plans@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/instructions': 8.2.0(typescript@5.9.3) + '@solana/keys': 8.2.0(typescript@5.9.3) + '@solana/promises': 8.2.0(typescript@5.9.3) + '@solana/transaction-messages': 8.2.0(typescript@5.9.3) + '@solana/transactions': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/instructions@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/instructions@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/keys@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/assertions': 6.10.0(typescript@5.9.3) + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/codecs-strings': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/nominal-types': 6.10.0(typescript@5.9.3) + '@solana/promises': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/keys@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/assertions': 8.2.0(typescript@5.9.3) + '@solana/codecs-core': 8.2.0(typescript@5.9.3) + '@solana/codecs-strings': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/nominal-types': 8.2.0(typescript@5.9.3) + '@solana/promises': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/kit@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/accounts': 6.10.0(typescript@5.9.3) + '@solana/addresses': 6.10.0(typescript@5.9.3) + '@solana/codecs': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/functional': 6.10.0(typescript@5.9.3) + '@solana/instruction-plans': 6.10.0(typescript@5.9.3) + '@solana/instructions': 6.10.0(typescript@5.9.3) + '@solana/keys': 6.10.0(typescript@5.9.3) + '@solana/offchain-messages': 6.10.0(typescript@5.9.3) + '@solana/plugin-core': 6.10.0(typescript@5.9.3) + '@solana/plugin-interfaces': 6.10.0(typescript@5.9.3) + '@solana/program-client-core': 6.10.0(typescript@5.9.3) + '@solana/programs': 6.10.0(typescript@5.9.3) + '@solana/rpc': 6.10.0(typescript@5.9.3) + '@solana/rpc-api': 6.10.0(typescript@5.9.3) + '@solana/rpc-parsed-types': 6.10.0(typescript@5.9.3) + '@solana/rpc-spec-types': 6.10.0(typescript@5.9.3) + '@solana/rpc-subscriptions': 6.10.0(typescript@5.9.3) + '@solana/rpc-types': 6.10.0(typescript@5.9.3) + '@solana/signers': 6.10.0(typescript@5.9.3) + '@solana/subscribable': 6.10.0(typescript@5.9.3) + '@solana/sysvars': 6.10.0(typescript@5.9.3) + '@solana/transaction-confirmation': 6.10.0(typescript@5.9.3) + '@solana/transaction-messages': 6.10.0(typescript@5.9.3) + '@solana/transactions': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - bufferutil + - fastestsmallesttextencoderdecoder + - utf-8-validate + + '@solana/kit@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/accounts': 8.2.0(typescript@5.9.3) + '@solana/addresses': 8.2.0(typescript@5.9.3) + '@solana/codecs': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/functional': 8.2.0(typescript@5.9.3) + '@solana/instruction-plans': 8.2.0(typescript@5.9.3) + '@solana/instructions': 8.2.0(typescript@5.9.3) + '@solana/keys': 8.2.0(typescript@5.9.3) + '@solana/offchain-messages': 8.2.0(typescript@5.9.3) + '@solana/plugin-core': 8.2.0(typescript@5.9.3) + '@solana/plugin-interfaces': 8.2.0(typescript@5.9.3) + '@solana/program-client-core': 8.2.0(typescript@5.9.3) + '@solana/programs': 8.2.0(typescript@5.9.3) + '@solana/promises': 8.2.0(typescript@5.9.3) + '@solana/rpc': 8.2.0(typescript@5.9.3) + '@solana/rpc-api': 8.2.0(typescript@5.9.3) + '@solana/rpc-parsed-types': 8.2.0(typescript@5.9.3) + '@solana/rpc-spec-types': 8.2.0(typescript@5.9.3) + '@solana/rpc-subscriptions': 8.2.0(typescript@5.9.3) + '@solana/rpc-types': 8.2.0(typescript@5.9.3) + '@solana/signers': 8.2.0(typescript@5.9.3) + '@solana/subscribable': 8.2.0(typescript@5.9.3) + '@solana/sysvars': 8.2.0(typescript@5.9.3) + '@solana/transaction-confirmation': 8.2.0(typescript@5.9.3) + '@solana/transaction-introspection': 8.2.0(typescript@5.9.3) + '@solana/transaction-messages': 8.2.0(typescript@5.9.3) + '@solana/transactions': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - bufferutil + - fastestsmallesttextencoderdecoder + - utf-8-validate + + '@solana/nominal-types@6.10.0(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + + '@solana/nominal-types@8.2.0(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + + '@solana/offchain-messages@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 6.10.0(typescript@5.9.3) + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/codecs-data-structures': 6.10.0(typescript@5.9.3) + '@solana/codecs-numbers': 6.10.0(typescript@5.9.3) + '@solana/codecs-strings': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/keys': 6.10.0(typescript@5.9.3) + '@solana/nominal-types': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/offchain-messages@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.2.0(typescript@5.9.3) + '@solana/codecs-core': 8.2.0(typescript@5.9.3) + '@solana/codecs-data-structures': 8.2.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.2.0(typescript@5.9.3) + '@solana/codecs-strings': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/keys': 8.2.0(typescript@5.9.3) + '@solana/nominal-types': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/options@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/codecs-data-structures': 6.10.0(typescript@5.9.3) + '@solana/codecs-numbers': 6.10.0(typescript@5.9.3) + '@solana/codecs-strings': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/options@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 8.2.0(typescript@5.9.3) + '@solana/codecs-data-structures': 8.2.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.2.0(typescript@5.9.3) + '@solana/codecs-strings': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/plugin-core@6.10.0(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + + '@solana/plugin-core@8.2.0(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + + '@solana/plugin-interfaces@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 6.10.0(typescript@5.9.3) + '@solana/instruction-plans': 6.10.0(typescript@5.9.3) + '@solana/keys': 6.10.0(typescript@5.9.3) + '@solana/rpc-spec': 6.10.0(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 6.10.0(typescript@5.9.3) + '@solana/rpc-types': 6.10.0(typescript@5.9.3) + '@solana/signers': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/plugin-interfaces@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/accounts': 8.2.0(typescript@5.9.3) + '@solana/addresses': 8.2.0(typescript@5.9.3) + '@solana/instruction-plans': 8.2.0(typescript@5.9.3) + '@solana/keys': 8.2.0(typescript@5.9.3) + '@solana/rpc-spec': 8.2.0(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 8.2.0(typescript@5.9.3) + '@solana/rpc-types': 8.2.0(typescript@5.9.3) + '@solana/signers': 8.2.0(typescript@5.9.3) + '@solana/transactions': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/program-client-core@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/accounts': 6.10.0(typescript@5.9.3) + '@solana/addresses': 6.10.0(typescript@5.9.3) + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/instruction-plans': 6.10.0(typescript@5.9.3) + '@solana/instructions': 6.10.0(typescript@5.9.3) + '@solana/plugin-interfaces': 6.10.0(typescript@5.9.3) + '@solana/rpc-api': 6.10.0(typescript@5.9.3) + '@solana/signers': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/program-client-core@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/accounts': 8.2.0(typescript@5.9.3) + '@solana/addresses': 8.2.0(typescript@5.9.3) + '@solana/codecs-core': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/instruction-plans': 8.2.0(typescript@5.9.3) + '@solana/instructions': 8.2.0(typescript@5.9.3) + '@solana/plugin-interfaces': 8.2.0(typescript@5.9.3) + '@solana/rpc-api': 8.2.0(typescript@5.9.3) + '@solana/signers': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/programs@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/programs@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/promises@6.10.0(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + + '@solana/promises@8.2.0(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + + '@solana/rpc-api@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 6.10.0(typescript@5.9.3) + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/codecs-strings': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/keys': 6.10.0(typescript@5.9.3) + '@solana/rpc-parsed-types': 6.10.0(typescript@5.9.3) + '@solana/rpc-spec': 6.10.0(typescript@5.9.3) + '@solana/rpc-transformers': 6.10.0(typescript@5.9.3) + '@solana/rpc-types': 6.10.0(typescript@5.9.3) + '@solana/transaction-messages': 6.10.0(typescript@5.9.3) + '@solana/transactions': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/rpc-api@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.2.0(typescript@5.9.3) + '@solana/codecs-core': 8.2.0(typescript@5.9.3) + '@solana/codecs-strings': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/keys': 8.2.0(typescript@5.9.3) + '@solana/rpc-parsed-types': 8.2.0(typescript@5.9.3) + '@solana/rpc-spec': 8.2.0(typescript@5.9.3) + '@solana/rpc-transformers': 8.2.0(typescript@5.9.3) + '@solana/rpc-types': 8.2.0(typescript@5.9.3) + '@solana/transaction-messages': 8.2.0(typescript@5.9.3) + '@solana/transactions': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/rpc-parsed-types@6.10.0(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + + '@solana/rpc-parsed-types@8.2.0(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + + '@solana/rpc-spec-types@6.10.0(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + + '@solana/rpc-spec-types@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/rpc-spec@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/rpc-spec-types': 6.10.0(typescript@5.9.3) + '@solana/subscribable': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/rpc-spec@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/rpc-spec-types': 8.2.0(typescript@5.9.3) + '@solana/subscribable': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/rpc-subscriptions-api@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 6.10.0(typescript@5.9.3) + '@solana/keys': 6.10.0(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 6.10.0(typescript@5.9.3) + '@solana/rpc-transformers': 6.10.0(typescript@5.9.3) + '@solana/rpc-types': 6.10.0(typescript@5.9.3) + '@solana/transaction-messages': 6.10.0(typescript@5.9.3) + '@solana/transactions': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/rpc-subscriptions-api@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.2.0(typescript@5.9.3) + '@solana/keys': 8.2.0(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 8.2.0(typescript@5.9.3) + '@solana/rpc-transformers': 8.2.0(typescript@5.9.3) + '@solana/rpc-types': 8.2.0(typescript@5.9.3) + '@solana/transaction-messages': 8.2.0(typescript@5.9.3) + '@solana/transactions': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/rpc-subscriptions-channel-websocket@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/functional': 6.10.0(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 6.10.0(typescript@5.9.3) + '@solana/subscribable': 6.10.0(typescript@5.9.3) + ws: 8.21.3 + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@solana/rpc-subscriptions-channel-websocket@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/functional': 8.2.0(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 8.2.0(typescript@5.9.3) + '@solana/subscribable': 8.2.0(typescript@5.9.3) + ws: 8.21.3 + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@solana/rpc-subscriptions-spec@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/promises': 6.10.0(typescript@5.9.3) + '@solana/rpc-spec-types': 6.10.0(typescript@5.9.3) + '@solana/subscribable': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/rpc-subscriptions-spec@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/promises': 8.2.0(typescript@5.9.3) + '@solana/rpc-spec-types': 8.2.0(typescript@5.9.3) + '@solana/subscribable': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/rpc-subscriptions@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/fast-stable-stringify': 6.10.0(typescript@5.9.3) + '@solana/functional': 6.10.0(typescript@5.9.3) + '@solana/promises': 6.10.0(typescript@5.9.3) + '@solana/rpc-spec-types': 6.10.0(typescript@5.9.3) + '@solana/rpc-subscriptions-api': 6.10.0(typescript@5.9.3) + '@solana/rpc-subscriptions-channel-websocket': 6.10.0(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 6.10.0(typescript@5.9.3) + '@solana/rpc-transformers': 6.10.0(typescript@5.9.3) + '@solana/rpc-types': 6.10.0(typescript@5.9.3) + '@solana/subscribable': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - bufferutil + - fastestsmallesttextencoderdecoder + - utf-8-validate + + '@solana/rpc-subscriptions@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/fast-stable-stringify': 8.2.0(typescript@5.9.3) + '@solana/functional': 8.2.0(typescript@5.9.3) + '@solana/promises': 8.2.0(typescript@5.9.3) + '@solana/rpc-spec-types': 8.2.0(typescript@5.9.3) + '@solana/rpc-subscriptions-api': 8.2.0(typescript@5.9.3) + '@solana/rpc-subscriptions-channel-websocket': 8.2.0(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 8.2.0(typescript@5.9.3) + '@solana/rpc-transformers': 8.2.0(typescript@5.9.3) + '@solana/rpc-types': 8.2.0(typescript@5.9.3) + '@solana/subscribable': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - bufferutil + - fastestsmallesttextencoderdecoder + - utf-8-validate + + '@solana/rpc-transformers@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/functional': 6.10.0(typescript@5.9.3) + '@solana/nominal-types': 6.10.0(typescript@5.9.3) + '@solana/rpc-spec-types': 6.10.0(typescript@5.9.3) + '@solana/rpc-types': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/rpc-transformers@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/functional': 8.2.0(typescript@5.9.3) + '@solana/nominal-types': 8.2.0(typescript@5.9.3) + '@solana/rpc-spec-types': 8.2.0(typescript@5.9.3) + '@solana/rpc-types': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/rpc-transport-http@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/rpc-spec': 6.10.0(typescript@5.9.3) + '@solana/rpc-spec-types': 6.10.0(typescript@5.9.3) + undici-types: 8.10.1 + optionalDependencies: + typescript: 5.9.3 + + '@solana/rpc-transport-http@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/rpc-spec': 8.2.0(typescript@5.9.3) + '@solana/rpc-spec-types': 8.2.0(typescript@5.9.3) + undici-types: 8.10.1 + optionalDependencies: + typescript: 5.9.3 + + '@solana/rpc-types@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 6.10.0(typescript@5.9.3) + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/codecs-numbers': 6.10.0(typescript@5.9.3) + '@solana/codecs-strings': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/fixed-points': 6.10.0(typescript@5.9.3) + '@solana/nominal-types': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/rpc-types@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.2.0(typescript@5.9.3) + '@solana/codecs-core': 8.2.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.2.0(typescript@5.9.3) + '@solana/codecs-strings': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/fixed-points': 8.2.0(typescript@5.9.3) + '@solana/nominal-types': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/rpc@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/fast-stable-stringify': 6.10.0(typescript@5.9.3) + '@solana/functional': 6.10.0(typescript@5.9.3) + '@solana/rpc-api': 6.10.0(typescript@5.9.3) + '@solana/rpc-spec': 6.10.0(typescript@5.9.3) + '@solana/rpc-spec-types': 6.10.0(typescript@5.9.3) + '@solana/rpc-transformers': 6.10.0(typescript@5.9.3) + '@solana/rpc-transport-http': 6.10.0(typescript@5.9.3) + '@solana/rpc-types': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/rpc@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/fast-stable-stringify': 8.2.0(typescript@5.9.3) + '@solana/functional': 8.2.0(typescript@5.9.3) + '@solana/rpc-api': 8.2.0(typescript@5.9.3) + '@solana/rpc-spec': 8.2.0(typescript@5.9.3) + '@solana/rpc-spec-types': 8.2.0(typescript@5.9.3) + '@solana/rpc-transformers': 8.2.0(typescript@5.9.3) + '@solana/rpc-transport-http': 8.2.0(typescript@5.9.3) + '@solana/rpc-types': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/signers@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 6.10.0(typescript@5.9.3) + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/instructions': 6.10.0(typescript@5.9.3) + '@solana/keys': 6.10.0(typescript@5.9.3) + '@solana/nominal-types': 6.10.0(typescript@5.9.3) + '@solana/offchain-messages': 6.10.0(typescript@5.9.3) + '@solana/transaction-messages': 6.10.0(typescript@5.9.3) + '@solana/transactions': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/signers@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.2.0(typescript@5.9.3) + '@solana/codecs-core': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/instructions': 8.2.0(typescript@5.9.3) + '@solana/keys': 8.2.0(typescript@5.9.3) + '@solana/nominal-types': 8.2.0(typescript@5.9.3) + '@solana/offchain-messages': 8.2.0(typescript@5.9.3) + '@solana/transaction-messages': 8.2.0(typescript@5.9.3) + '@solana/transactions': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/subscribable@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/promises': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/subscribable@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/promises': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/sysvars@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/accounts': 6.10.0(typescript@5.9.3) + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/codecs-data-structures': 6.10.0(typescript@5.9.3) + '@solana/codecs-numbers': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/rpc-types': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/sysvars@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/accounts': 8.2.0(typescript@5.9.3) + '@solana/codecs-core': 8.2.0(typescript@5.9.3) + '@solana/codecs-data-structures': 8.2.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/rpc-types': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/transaction-confirmation@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 6.10.0(typescript@5.9.3) + '@solana/codecs-strings': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/keys': 6.10.0(typescript@5.9.3) + '@solana/promises': 6.10.0(typescript@5.9.3) + '@solana/rpc': 6.10.0(typescript@5.9.3) + '@solana/rpc-subscriptions': 6.10.0(typescript@5.9.3) + '@solana/rpc-types': 6.10.0(typescript@5.9.3) + '@solana/transaction-messages': 6.10.0(typescript@5.9.3) + '@solana/transactions': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - bufferutil + - fastestsmallesttextencoderdecoder + - utf-8-validate + + '@solana/transaction-confirmation@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.2.0(typescript@5.9.3) + '@solana/codecs-strings': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/keys': 8.2.0(typescript@5.9.3) + '@solana/promises': 8.2.0(typescript@5.9.3) + '@solana/rpc': 8.2.0(typescript@5.9.3) + '@solana/rpc-subscriptions': 8.2.0(typescript@5.9.3) + '@solana/rpc-types': 8.2.0(typescript@5.9.3) + '@solana/transaction-messages': 8.2.0(typescript@5.9.3) + '@solana/transactions': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - bufferutil + - fastestsmallesttextencoderdecoder + - utf-8-validate + + '@solana/transaction-introspection@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.2.0(typescript@5.9.3) + '@solana/codecs-core': 8.2.0(typescript@5.9.3) + '@solana/codecs-strings': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/instructions': 8.2.0(typescript@5.9.3) + '@solana/rpc-types': 8.2.0(typescript@5.9.3) + '@solana/transaction-messages': 8.2.0(typescript@5.9.3) + '@solana/transactions': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/transaction-messages@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 6.10.0(typescript@5.9.3) + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/codecs-data-structures': 6.10.0(typescript@5.9.3) + '@solana/codecs-numbers': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/functional': 6.10.0(typescript@5.9.3) + '@solana/instructions': 6.10.0(typescript@5.9.3) + '@solana/nominal-types': 6.10.0(typescript@5.9.3) + '@solana/rpc-types': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/transaction-messages@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.2.0(typescript@5.9.3) + '@solana/codecs-core': 8.2.0(typescript@5.9.3) + '@solana/codecs-data-structures': 8.2.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/functional': 8.2.0(typescript@5.9.3) + '@solana/instructions': 8.2.0(typescript@5.9.3) + '@solana/nominal-types': 8.2.0(typescript@5.9.3) + '@solana/rpc-types': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/transactions@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 6.10.0(typescript@5.9.3) + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/codecs-data-structures': 6.10.0(typescript@5.9.3) + '@solana/codecs-numbers': 6.10.0(typescript@5.9.3) + '@solana/codecs-strings': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/functional': 6.10.0(typescript@5.9.3) + '@solana/instructions': 6.10.0(typescript@5.9.3) + '@solana/keys': 6.10.0(typescript@5.9.3) + '@solana/nominal-types': 6.10.0(typescript@5.9.3) + '@solana/rpc-types': 6.10.0(typescript@5.9.3) + '@solana/transaction-messages': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/transactions@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.2.0(typescript@5.9.3) + '@solana/codecs-core': 8.2.0(typescript@5.9.3) + '@solana/codecs-data-structures': 8.2.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.2.0(typescript@5.9.3) + '@solana/codecs-strings': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/functional': 8.2.0(typescript@5.9.3) + '@solana/instructions': 8.2.0(typescript@5.9.3) + '@solana/keys': 8.2.0(typescript@5.9.3) + '@solana/nominal-types': 8.2.0(typescript@5.9.3) + '@solana/rpc-types': 8.2.0(typescript@5.9.3) + '@solana/transaction-messages': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@types/chai@5.2.3': + dependencies: + '@types/deep-eql': 4.0.2 + assertion-error: 2.0.1 + + '@types/deep-eql@4.0.2': {} + + '@types/estree@1.0.9': {} + + '@types/node@24.13.3': + dependencies: + undici-types: 7.18.2 + + '@vitest/expect@3.2.7': + dependencies: + '@types/chai': 5.2.3 + '@vitest/spy': 3.2.7 + '@vitest/utils': 3.2.7 + chai: 5.3.3 + tinyrainbow: 2.0.0 + + '@vitest/mocker@3.2.7(vite@7.3.6(@types/node@24.13.3))': + dependencies: + '@vitest/spy': 3.2.7 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 7.3.6(@types/node@24.13.3) + + '@vitest/pretty-format@3.2.7': + dependencies: + tinyrainbow: 2.0.0 + + '@vitest/runner@3.2.7': + dependencies: + '@vitest/utils': 3.2.7 + pathe: 2.0.3 + strip-literal: 3.1.0 + + '@vitest/snapshot@3.2.7': + dependencies: + '@vitest/pretty-format': 3.2.7 + magic-string: 0.30.21 + pathe: 2.0.3 + + '@vitest/spy@3.2.7': + dependencies: + tinyspy: 4.0.4 + + '@vitest/utils@3.2.7': + dependencies: + '@vitest/pretty-format': 3.2.7 + loupe: 3.2.1 + tinyrainbow: 2.0.0 + + assertion-error@2.0.1: {} + + cac@6.7.14: {} + + chai@5.3.3: + dependencies: + assertion-error: 2.0.1 + check-error: 2.1.3 + deep-eql: 5.0.2 + loupe: 3.2.1 + pathval: 2.0.1 + + chalk@5.6.2: {} + + check-error@2.1.3: {} + + commander@15.0.0: {} + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + deep-eql@5.0.2: {} + + es-module-lexer@1.7.0: {} + + esbuild@0.28.2: + optionalDependencies: + '@esbuild/aix-ppc64': 0.28.2 + '@esbuild/android-arm': 0.28.2 + '@esbuild/android-arm64': 0.28.2 + '@esbuild/android-x64': 0.28.2 + '@esbuild/darwin-arm64': 0.28.2 + '@esbuild/darwin-x64': 0.28.2 + '@esbuild/freebsd-arm64': 0.28.2 + '@esbuild/freebsd-x64': 0.28.2 + '@esbuild/linux-arm': 0.28.2 + '@esbuild/linux-arm64': 0.28.2 + '@esbuild/linux-ia32': 0.28.2 + '@esbuild/linux-loong64': 0.28.2 + '@esbuild/linux-mips64el': 0.28.2 + '@esbuild/linux-ppc64': 0.28.2 + '@esbuild/linux-riscv64': 0.28.2 + '@esbuild/linux-s390x': 0.28.2 + '@esbuild/linux-x64': 0.28.2 + '@esbuild/netbsd-arm64': 0.28.2 + '@esbuild/netbsd-x64': 0.28.2 + '@esbuild/openbsd-arm64': 0.28.2 + '@esbuild/openbsd-x64': 0.28.2 + '@esbuild/openharmony-arm64': 0.28.2 + '@esbuild/sunos-x64': 0.28.2 + '@esbuild/win32-arm64': 0.28.2 + '@esbuild/win32-ia32': 0.28.2 + '@esbuild/win32-x64': 0.28.2 + + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.9 + + expect-type@1.4.0: {} + + fdir@6.5.0(picomatch@4.0.7): + optionalDependencies: + picomatch: 4.0.7 + + fsevents@2.3.3: + optional: true + + js-tokens@9.0.1: {} + + litesvm-darwin-arm64@1.4.1: + optional: true + + litesvm-darwin-x64@1.4.1: + optional: true + + litesvm-linux-arm64-gnu@1.4.1: + optional: true + + litesvm-linux-arm64-musl@1.4.1: + optional: true + + litesvm-linux-x64-gnu@1.4.1: + optional: true + + litesvm-linux-x64-musl@1.4.1: + optional: true + + litesvm@1.4.1(typescript@5.9.3): + dependencies: + '@solana-program/system': 0.14.0(@solana/kit@8.2.0(typescript@5.9.3)) + '@solana-program/token': 0.16.0(@solana/kit@8.2.0(typescript@5.9.3)) + '@solana/kit': 8.2.0(typescript@5.9.3) + optionalDependencies: + litesvm-darwin-arm64: 1.4.1 + litesvm-darwin-x64: 1.4.1 + litesvm-linux-arm64-gnu: 1.4.1 + litesvm-linux-arm64-musl: 1.4.1 + litesvm-linux-x64-gnu: 1.4.1 + litesvm-linux-x64-musl: 1.4.1 + transitivePeerDependencies: + - bufferutil + - fastestsmallesttextencoderdecoder + - typescript + - utf-8-validate + + loupe@3.2.1: {} + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.6.0 + + ms@2.1.3: {} + + nanoid@3.3.18: {} + + pathe@2.0.3: {} + + pathval@2.0.1: {} + + picocolors@1.1.1: {} + + picomatch@4.0.7: {} + + postcss@8.5.26: + dependencies: + nanoid: 3.3.18 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + rollup@4.63.1: + dependencies: + '@types/estree': 1.0.9 + optionalDependencies: + '@napi-rs/lzma-linux-x64-gnu': 1.5.1 + '@rollup/rollup-android-arm-eabi': 4.63.1 + '@rollup/rollup-android-arm64': 4.63.1 + '@rollup/rollup-darwin-arm64': 4.63.1 + '@rollup/rollup-darwin-x64': 4.63.1 + '@rollup/rollup-freebsd-arm64': 4.63.1 + '@rollup/rollup-freebsd-x64': 4.63.1 + '@rollup/rollup-linux-arm-gnueabihf': 4.63.1 + '@rollup/rollup-linux-arm-musleabihf': 4.63.1 + '@rollup/rollup-linux-arm64-gnu': 4.63.1 + '@rollup/rollup-linux-arm64-musl': 4.63.1 + '@rollup/rollup-linux-loong64-gnu': 4.63.1 + '@rollup/rollup-linux-loong64-musl': 4.63.1 + '@rollup/rollup-linux-ppc64-gnu': 4.63.1 + '@rollup/rollup-linux-ppc64-musl': 4.63.1 + '@rollup/rollup-linux-riscv64-gnu': 4.63.1 + '@rollup/rollup-linux-riscv64-musl': 4.63.1 + '@rollup/rollup-linux-s390x-gnu': 4.63.1 + '@rollup/rollup-linux-x64-gnu': 4.63.1 + '@rollup/rollup-linux-x64-musl': 4.63.1 + '@rollup/rollup-openbsd-x64': 4.63.1 + '@rollup/rollup-openharmony-arm64': 4.63.1 + '@rollup/rollup-win32-arm64-msvc': 4.63.1 + '@rollup/rollup-win32-ia32-msvc': 4.63.1 + '@rollup/rollup-win32-x64-gnu': 4.63.1 + '@rollup/rollup-win32-x64-msvc': 4.63.1 + fsevents: 2.3.3 + + siginfo@2.0.0: {} + + source-map-js@1.2.1: {} + + stackback@0.0.2: {} + + std-env@3.10.0: {} + + strip-literal@3.1.0: + dependencies: + js-tokens: 9.0.1 + + tinybench@2.9.0: {} + + tinyexec@0.3.2: {} + + tinyglobby@0.2.17: + dependencies: + fdir: 6.5.0(picomatch@4.0.7) + picomatch: 4.0.7 + + tinypool@1.1.1: {} + + tinyrainbow@2.0.0: {} + + tinyspy@4.0.4: {} + + typescript@5.9.3: {} + + undici-types@7.18.2: {} + + undici-types@8.10.1: {} + + vite-node@3.2.4(@types/node@24.13.3): + dependencies: + cac: 6.7.14 + debug: 4.4.3 + es-module-lexer: 1.7.0 + pathe: 2.0.3 + vite: 7.3.6(@types/node@24.13.3) + transitivePeerDependencies: + - '@types/node' + - jiti + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml + + vite@7.3.6(@types/node@24.13.3): + dependencies: + esbuild: 0.28.2 + fdir: 6.5.0(picomatch@4.0.7) + picomatch: 4.0.7 + postcss: 8.5.26 + rollup: 4.63.1 + tinyglobby: 0.2.17 + optionalDependencies: + '@types/node': 24.13.3 + fsevents: 2.3.3 + + vitest@3.2.7(@types/node@24.13.3): + dependencies: + '@types/chai': 5.2.3 + '@vitest/expect': 3.2.7 + '@vitest/mocker': 3.2.7(vite@7.3.6(@types/node@24.13.3)) + '@vitest/pretty-format': 3.2.7 + '@vitest/runner': 3.2.7 + '@vitest/snapshot': 3.2.7 + '@vitest/spy': 3.2.7 + '@vitest/utils': 3.2.7 + chai: 5.3.3 + debug: 4.4.3 + expect-type: 1.4.0 + magic-string: 0.30.21 + pathe: 2.0.3 + picomatch: 4.0.7 + std-env: 3.10.0 + tinybench: 2.9.0 + tinyexec: 0.3.2 + tinyglobby: 0.2.17 + tinypool: 1.1.1 + tinyrainbow: 2.0.0 + vite: 7.3.6(@types/node@24.13.3) + vite-node: 3.2.4(@types/node@24.13.3) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 24.13.3 + transitivePeerDependencies: + - jiti + - less + - lightningcss + - msw + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml + + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + + ws@8.21.3: {} diff --git a/programs/settlement/idl/pnpm-lock.yaml b/programs/settlement/idl/pnpm-lock.yaml new file mode 100644 index 0000000..67ad834 --- /dev/null +++ b/programs/settlement/idl/pnpm-lock.yaml @@ -0,0 +1,505 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@codama/nodes-from-anchor': + specifier: ^1.5.2 + version: 1.5.5 + '@codama/renderers-js': + specifier: ^2.3.0 + version: 2.4.0 + codama: + specifier: ^1.9.0 + version: 1.10.2 + +packages: + + '@codama/cli@1.6.2': + resolution: {integrity: sha512-UFrWJxtELsPHOoG8soVuUqv/nSSUebLccaN3WQ43+5J7pFBetscEUsoy20lzV2gxYEfvYf6JqyuIUXGDmtnj9g==} + hasBin: true + + '@codama/errors@1.10.2': + resolution: {integrity: sha512-relp9Inq9QkhZ0JUklKujSFWLkVfQSsn2/ms303vsGVWlFBXQmoEsmZCVKgJ7k5APNBbsD8Hc9GGU4J+P05SLA==} + hasBin: true + + '@codama/fragments@0.1.5': + resolution: {integrity: sha512-aisr+cdayABykLhysE1pcDWMJJZNAAWyi5NEzkMLpyTmQrhIK6Mca14gSJIw3a0uo3E5s5Zc4d6gsxRjfYpLuw==} + + '@codama/node-types@1.10.2': + resolution: {integrity: sha512-qFHqpuCmAoJy9ggkLadtug2Nlmnai6LrEmr+sfsK6dEJVOFGMNBR4dxwheziOu/Sn9oWGfnFfKbzQIdWE0qHHg==} + + '@codama/nodes-from-anchor@1.5.5': + resolution: {integrity: sha512-+HQUKzQpSh8EHm+fwxXVTvhPI46yTm1HzLvRJK1mkTJ1w4bymknhyWsLn1NRVDcAIixPZLsvLKujJTn+8IcoZg==} + + '@codama/nodes@1.10.2': + resolution: {integrity: sha512-wR2LKg6/GQ+ctgOiH9XPVb7ktq+gu7X/WEiCk45d4L1+P/JJh2kJeS/sMbktrgJNimcoO2G1Ms3+eUDjrwfo5g==} + + '@codama/renderers-core@1.4.0': + resolution: {integrity: sha512-JkqKWaN5nKampHgJ3jWh7u6kNPrwp7DB/lpkyS1hpL6NiC45tZGie6foaq8TnSTpaVPtVsL8Q46AP1MZpongpg==} + + '@codama/renderers-js@2.4.0': + resolution: {integrity: sha512-nLmLy8eSaBtnff5OE85SXvdL4rN4QSkCSZfZ4856zwnPndP/UzV/RBNoZOp1+muMj1VIKMZ1gXLzKQjDeYM3EA==} + engines: {node: '>=20.18.0'} + + '@codama/validators@1.10.2': + resolution: {integrity: sha512-Ppf8qcbBMclncrTLZU/bxi2Y5Gf9cTg1SybHTIDankOholgRWzf8wdZ40Vc/BaphY223pHOUBXiEmwZ6eTRX7A==} + + '@codama/visitors-core@1.10.2': + resolution: {integrity: sha512-hxoISIWUUiu9Ma97OxsXl3Db5qvYmqUm9JVCf6MCb/+uE5nd4U/jZuTIKQFLulitiGRWhQr8IJI16YgO79Nuyw==} + + '@codama/visitors@1.10.2': + resolution: {integrity: sha512-DUkpq9TEuevg4mEOW9fyBJiYHGzj6ByNtgVAyLRWcUEz6Mz3Qn8+lRDpqqVyuzRbAdurf9bWsO8ln+zswPP4hg==} + + '@noble/hashes@2.4.0': + resolution: {integrity: sha512-X5XaVWZIBCT7HHZGm5I7ZQXDwLG+bGXuSrMQAW+7Zvl87h1kmc1ZB1VSRJcpUfoUrGQp4Fkoxm5kZ+Ms+aW+eA==} + engines: {node: '>= 20.19.0'} + + '@solana/codecs-core@7.1.1': + resolution: {integrity: sha512-C1UOAQ7LH8RuCTfaij6hthTZeBlpp8GuD2g9Nag/xgiNKJGvAfVrcorb+kO/sufdYI8Lu+BiVvPeKOjQDQiKqg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/codecs-data-structures@7.1.1': + resolution: {integrity: sha512-MO+wMAuaatAQ96N3HhTsd7Uno+79rJw88P+OiU2n+pHK/rZuyu1yB2j12veqK4jUNWPR0aOyCuZ4rB2idrDjpg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/codecs-numbers@7.1.1': + resolution: {integrity: sha512-TWWrQq6Wp5Yf5bSc6RbxDDYCRUBBmRtRgjvUMHGp0P9K+4uFwxllRjSZFzBPHgXj3UTeZmFJdcoD271QhAgibg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/codecs-strings@7.1.1': + resolution: {integrity: sha512-6qWl+atG60D2LmP47GyGapQFhVsG1sVhVrEaM3lV09vwrGOMeOZARZ4ObaQ5m6uQmM04G+f8dY9d17nCMbGHGg==} + engines: {node: '>=20.18.0'} + peerDependencies: + fastestsmallesttextencoderdecoder: ^1.0.22 + typescript: '>=5.4.0' + peerDependenciesMeta: + fastestsmallesttextencoderdecoder: + optional: true + typescript: + optional: true + + '@solana/codecs@7.1.1': + resolution: {integrity: sha512-1ZErMXzbbz7+jusem58dMO1haVWNlvFYKftc2dPhFu9MqlmZRfPS06GiZDjlLnD/6PHHBy7OKFMASoYw+fBAKg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/errors@7.1.1': + resolution: {integrity: sha512-q35qck8rBnNvJlPU00mnHEQm7gWvghzYz8khqVoLhjgodTzGp46VqnIOyI1LXOAF6XDal58bMNDO980MQgq8yw==} + engines: {node: '>=20.18.0'} + hasBin: true + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/fixed-points@7.1.1': + resolution: {integrity: sha512-qPj/V7kcFG/P0kuEa1U529+5L6mbkMwRIwvYBTDgBqPOt6wOdk9/c7Qn2VUQgSV0HgCXWxdHUdwaxBrYqO2ibg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/options@7.1.1': + resolution: {integrity: sha512-iuPpfMbnRFjC4IoAIpKNA9UpizomxjW0E3F1LxUYQHXm1vCoF78kThp4qqgx2V3DmDFbhXGtXGSJPwmDdpLoBg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + call-bind@1.0.9: + resolution: {integrity: sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==} + engines: {node: '>= 0.4'} + + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + + chalk@5.6.2: + resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + + codama@1.10.2: + resolution: {integrity: sha512-fm6bFmgTrd6wPJ8o758wVVCYSEmEOU7Ctvlm8TxZoyPG0DlRS94AqnG3yC0HODXfGMAbai6pCxe9D04n3yl5AQ==} + hasBin: true + + commander@15.0.0: + resolution: {integrity: sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==} + engines: {node: '>=22.12.0'} + + define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-object-atoms@1.1.2: + resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==} + engines: {node: '>= 0.4'} + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + hasown@2.0.4: + resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} + engines: {node: '>= 0.4'} + + isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + + json-stable-stringify@1.3.0: + resolution: {integrity: sha512-qtYiSSFlwot9XHtF9bD9c7rwKjr+RecWT//ZnPvSmEjpV5mmPOCN4j8UjY5hbjNkOwZ/jQv3J6R1/pL7RwgMsg==} + engines: {node: '>= 0.4'} + + jsonify@0.0.1: + resolution: {integrity: sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==} + + kleur@3.0.3: + resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} + engines: {node: '>=6'} + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + prettier@3.9.6: + resolution: {integrity: sha512-OpN0zzVdiaiAhxpuuj5efpIS4sY9j7bY6uR5mnj5yPzGkdkjNKSJeUThPb60Jw29QuAZgA4o+/iB49kFiaBX6g==} + engines: {node: '>=14'} + hasBin: true + + prompts@2.4.2: + resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} + engines: {node: '>= 6'} + + semver@7.8.5: + resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} + engines: {node: '>=10'} + hasBin: true + + set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + + sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + +snapshots: + + '@codama/cli@1.6.2': + dependencies: + '@codama/nodes': 1.10.2 + '@codama/visitors': 1.10.2 + '@codama/visitors-core': 1.10.2 + commander: 15.0.0 + picocolors: 1.1.1 + prompts: 2.4.2 + + '@codama/errors@1.10.2': + dependencies: + '@codama/node-types': 1.10.2 + commander: 15.0.0 + picocolors: 1.1.1 + + '@codama/fragments@0.1.5': + dependencies: + '@codama/errors': 1.10.2 + + '@codama/node-types@1.10.2': {} + + '@codama/nodes-from-anchor@1.5.5': + dependencies: + '@codama/errors': 1.10.2 + '@codama/nodes': 1.10.2 + '@codama/visitors': 1.10.2 + '@noble/hashes': 2.4.0 + '@solana/codecs': 7.1.1 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + - typescript + + '@codama/nodes@1.10.2': + dependencies: + '@codama/errors': 1.10.2 + '@codama/node-types': 1.10.2 + + '@codama/renderers-core@1.4.0': + dependencies: + '@codama/errors': 1.10.2 + '@codama/fragments': 0.1.5 + '@codama/nodes': 1.10.2 + '@codama/visitors-core': 1.10.2 + + '@codama/renderers-js@2.4.0': + dependencies: + '@codama/errors': 1.10.2 + '@codama/nodes': 1.10.2 + '@codama/renderers-core': 1.4.0 + '@codama/visitors-core': 1.10.2 + '@solana/codecs-strings': 7.1.1 + prettier: 3.9.6 + semver: 7.8.5 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + - typescript + + '@codama/validators@1.10.2': + dependencies: + '@codama/errors': 1.10.2 + '@codama/nodes': 1.10.2 + '@codama/visitors-core': 1.10.2 + + '@codama/visitors-core@1.10.2': + dependencies: + '@codama/errors': 1.10.2 + '@codama/nodes': 1.10.2 + json-stable-stringify: 1.3.0 + + '@codama/visitors@1.10.2': + dependencies: + '@codama/errors': 1.10.2 + '@codama/nodes': 1.10.2 + '@codama/visitors-core': 1.10.2 + + '@noble/hashes@2.4.0': {} + + '@solana/codecs-core@7.1.1': + dependencies: + '@solana/errors': 7.1.1 + + '@solana/codecs-data-structures@7.1.1': + dependencies: + '@solana/codecs-core': 7.1.1 + '@solana/codecs-numbers': 7.1.1 + '@solana/errors': 7.1.1 + + '@solana/codecs-numbers@7.1.1': + dependencies: + '@solana/codecs-core': 7.1.1 + '@solana/errors': 7.1.1 + + '@solana/codecs-strings@7.1.1': + dependencies: + '@solana/codecs-core': 7.1.1 + '@solana/codecs-numbers': 7.1.1 + '@solana/errors': 7.1.1 + + '@solana/codecs@7.1.1': + dependencies: + '@solana/codecs-core': 7.1.1 + '@solana/codecs-data-structures': 7.1.1 + '@solana/codecs-numbers': 7.1.1 + '@solana/codecs-strings': 7.1.1 + '@solana/fixed-points': 7.1.1 + '@solana/options': 7.1.1 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/errors@7.1.1': + dependencies: + chalk: 5.6.2 + commander: 15.0.0 + + '@solana/fixed-points@7.1.1': + dependencies: + '@solana/codecs-core': 7.1.1 + '@solana/errors': 7.1.1 + + '@solana/options@7.1.1': + dependencies: + '@solana/codecs-core': 7.1.1 + '@solana/codecs-data-structures': 7.1.1 + '@solana/codecs-numbers': 7.1.1 + '@solana/codecs-strings': 7.1.1 + '@solana/errors': 7.1.1 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bind@1.0.9: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + get-intrinsic: 1.3.0 + set-function-length: 1.2.2 + + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + + chalk@5.6.2: {} + + codama@1.10.2: + dependencies: + '@codama/cli': 1.6.2 + '@codama/errors': 1.10.2 + '@codama/nodes': 1.10.2 + '@codama/validators': 1.10.2 + '@codama/visitors': 1.10.2 + + commander@15.0.0: {} + + define-data-property@1.1.4: + dependencies: + es-define-property: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-object-atoms@1.1.2: + dependencies: + es-errors: 1.3.0 + + function-bind@1.1.2: {} + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.4 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.2 + + gopd@1.2.0: {} + + has-property-descriptors@1.0.2: + dependencies: + es-define-property: 1.0.1 + + has-symbols@1.1.0: {} + + hasown@2.0.4: + dependencies: + function-bind: 1.1.2 + + isarray@2.0.5: {} + + json-stable-stringify@1.3.0: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + isarray: 2.0.5 + jsonify: 0.0.1 + object-keys: 1.1.1 + + jsonify@0.0.1: {} + + kleur@3.0.3: {} + + math-intrinsics@1.1.0: {} + + object-keys@1.1.1: {} + + picocolors@1.1.1: {} + + prettier@3.9.6: {} + + prompts@2.4.2: + dependencies: + kleur: 3.0.3 + sisteransi: 1.0.5 + + semver@7.8.5: {} + + set-function-length@1.2.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.3.0 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + + sisteransi@1.0.5: {} From 9736f868c26ce9f81981ce83313bfd6dd0ddd2ae Mon Sep 17 00:00:00 2001 From: Kaze <230549489+kaze-cow@users.noreply.github.com> Date: Tue, 1 Sep 2026 17:10:43 +0900 Subject: [PATCH 26/43] simplifies and final manual review --- .gitignore | 7 +-- Justfile | 5 +- bench-report.json | 52 ++++++++-------- .../settlement/idl/client/js/src/hooked.ts | 29 +++------ .../settlement/idl/client/js/src/index.ts | 1 + .../settlement/idl/client/js/src/order.ts | 59 +++++++++++++++++++ .../idl/client/js/tests/createOrder.test.ts | 5 +- .../idl/client/js/tests/fixtures.ts | 26 +------- .../idl/client/js/tests/flags.test.ts | 33 +++++++++++ .../settlement/idl/client/js/tsconfig.json | 3 - programs/settlement/idl/generate.mjs | 12 +--- 11 files changed, 134 insertions(+), 98 deletions(-) create mode 100644 programs/settlement/idl/client/js/src/order.ts create mode 100644 programs/settlement/idl/client/js/tests/flags.test.ts diff --git a/.gitignore b/.gitignore index 51b47a2..de89b8d 100644 --- a/.gitignore +++ b/.gitignore @@ -8,11 +8,8 @@ generated/ # Make sure no Solana key is uploaded by accident. *.json !bench-report.json -!programs/settlement/idl/** -# That negation re-includes the whole IDL directory, taking installed dependencies -# and the rendered client — excluded everywhere by the rules at the top — back with -# it. Exclude them again; what the negation has to reach is the IDL, its schema and -# the pnpm lockfiles, which CI installs from and so are committed here on purpose. +# Include IDL, but don't include the generated parts. +!programs/settlement/idl/** programs/settlement/idl/**/node_modules/ programs/settlement/idl/client/js/src/generated/ diff --git a/Justfile b/Justfile index 0315c4a..51d1a70 100644 --- a/Justfile +++ b/Justfile @@ -18,10 +18,7 @@ build: build-program test: build-program build-test-programs cargo test -# The two JS recipes below install with `corepack pnpm`, which runs the pnpm version -# each package.json pins, so neither one needs pnpm installed globally. - -# Render the JS client from the hand-written IDL (the output is kept out of git, so re-render it before use). +# Builds the JS/TS client from IDL. generate-js-client: cd programs/settlement/idl && corepack pnpm install --frozen-lockfile && node generate.mjs diff --git a/bench-report.json b/bench-report.json index 8b69481..04d8ec7 100644 --- a/bench-report.json +++ b/bench-report.json @@ -30,34 +30,34 @@ "transfer_authority/reclaim_authority_can_transfer_itself": 4 }, "compute_units": { - "add_solver/add_with_many_existing_solvers": 5074, - "add_solver/adds_a_solver": 4622, - "create_buffers/happy_path_creates_initialized_buffer_token_account": 7345, - "create_buffers/happy_path_creates_multiple_buffers_in_one_instruction": 17243, - "create_buffers/max_buffers_in_one_instruction": 169540, - "create_order/happy_path_creates_order_pda_with_expected_body": 4985, - "initialize/happy_path_initializes_state_pda_with_expected_data": 4529, - "reclaim_buffer/funded_buffer_is_skipped": 4835, - "reclaim_buffer/happy_path_reclaims_empty_buffer_to_the_authority_itself": 5983, - "reclaim_buffer/max_buffers_in_one_instruction": 124652, - "reclaim_buffer/reclaims_multiple_buffers_skipping_funded": 7582, - "reclaim_order/happy_path_expired_returns_lamports_and_closes_pda": 2202, - "reclaim_order/happy_path_on_chain_order_cancelled_is_reclaimable_before_expiry": 2071, - "reclaim_order/happy_path_on_chain_order_fully_filled_is_reclaimable_before_expiry": 2079, + "add_solver/add_with_many_existing_solvers": 5068, + "add_solver/adds_a_solver": 4616, + "create_buffers/happy_path_creates_initialized_buffer_token_account": 7339, + "create_buffers/happy_path_creates_multiple_buffers_in_one_instruction": 17231, + "create_buffers/max_buffers_in_one_instruction": 169447, + "create_order/happy_path_creates_order_pda_with_expected_body": 4980, + "initialize/happy_path_initializes_state_pda_with_expected_data": 4524, + "reclaim_buffer/funded_buffer_is_skipped": 4828, + "reclaim_buffer/happy_path_reclaims_empty_buffer_to_the_authority_itself": 5979, + "reclaim_buffer/max_buffers_in_one_instruction": 124648, + "reclaim_buffer/reclaims_multiple_buffers_skipping_funded": 7575, + "reclaim_order/happy_path_expired_returns_lamports_and_closes_pda": 2199, + "reclaim_order/happy_path_on_chain_order_cancelled_is_reclaimable_before_expiry": 2068, + "reclaim_order/happy_path_on_chain_order_fully_filled_is_reclaimable_before_expiry": 2076, "reclaim_order/off_chain_order_is_reclaimable_only_once_expired": null, "reclaim_order/on_chain_order_partially_filled_is_not_reclaimable_before_expiry": null, - "settle/finalizes_with_no_pushes": 7154, - "settle/pulls_from_multiple_orders": 20059, - "settle/pulls_funds_to_destination": 13640, - "settle/pulls_to_multiple_destinations": 14781, - "settle/pushes_a_single_order": 12495, - "settle/pushes_several_orders_from_different_buffers": 17767, - "settle/pushes_several_orders_from_one_buffer": 17766, - "settle/settles_a_single_order": 12513, - "settle/settles_multiple_orders": 23086, - "transfer_authority/manager_can_transfer_manager": 3174, - "transfer_authority/manager_can_transfer_reclaim_authority": 3176, - "transfer_authority/reclaim_authority_can_transfer_itself": 3180 + "settle/finalizes_with_no_pushes": 7126, + "settle/pulls_from_multiple_orders": 19994, + "settle/pulls_funds_to_destination": 13593, + "settle/pulls_to_multiple_destinations": 14733, + "settle/pushes_a_single_order": 12449, + "settle/pushes_several_orders_from_different_buffers": 17704, + "settle/pushes_several_orders_from_one_buffer": 17703, + "settle/settles_a_single_order": 12467, + "settle/settles_multiple_orders": 23006, + "transfer_authority/manager_can_transfer_manager": 3171, + "transfer_authority/manager_can_transfer_reclaim_authority": 3173, + "transfer_authority/reclaim_authority_can_transfer_itself": 3177 }, "transaction_bytes": { "add_solver/add_with_many_existing_solvers": 366, diff --git a/programs/settlement/idl/client/js/src/hooked.ts b/programs/settlement/idl/client/js/src/hooked.ts index b4c5177..d324e66 100644 --- a/programs/settlement/idl/client/js/src/hooked.ts +++ b/programs/settlement/idl/client/js/src/hooked.ts @@ -1,24 +1,13 @@ -// Hand-written — Codama's "hooked" convention: functions referenced by a -// `resolverValueNode` default value live here, imported by generated code -// via the fixed "../../hooked" specifier (see generate.mjs). Never touched -// by rendering, which only manages src/generated. -// -// create_order's order PDA is seeded by [SETTLEMENT_SEED, sha256(intent_bytes), "order"]. -// The middle seed is a hash of the whole `intent` argument rather than a plain -// field/account reference, which the Anchor PDA-seed grammar (const / arg / account) -// can't express — see cow_settlement.json's create_order docs — so it's handed off -// to this resolver instead of a plain `pda` node. Codama calls this with a -// `resolverScope` object and splices the returned `{ value }` onto the account -// it's resolving, so its shape is dictated by the renderer, not chosen here. +// This file is automatically loaded by codama for `resolverValueNode` types. For +// cases where the IDL syntax is not enough, custom code can be added to this file +// to retain functionality. import { getProgramDerivedAddress, type Address } from "@solana/kit"; import { getOrderIntentEncoder, type OrderIntentArgs } from "./generated"; import IDL from "./generated/idl.json" with { type: "json" }; /** - * The slice of the IDL this file reads. Annotating the import replaces the shape - * TypeScript infers from the JSON — a union over every instruction, account and - * seed kind — with just the path walked below, on which `pda` is reachable. + * The type definition for the slice of the IDL this file reads. */ type SeedBearingIdl = { instructions: { @@ -30,13 +19,6 @@ type SeedBearingIdl = { }[]; }; -/** - * Prefix seed shared by every PDA this program derives: the ASCII "settlement v" - * followed by the program's major.minor version, right-padded with spaces to a - * fixed 19 bytes. The fixed width keeps one version's seeds from being a prefix - * of another's. These bytes change on every minor version bump, so they're read - * off the IDL — the state PDA's sole const seed — rather than written out here. - */ const SETTLEMENT_SEED: Uint8Array = (() => { const idl: SeedBearingIdl = IDL; const seed = idl.instructions @@ -49,6 +31,9 @@ const SETTLEMENT_SEED: Uint8Array = (() => { return new Uint8Array(seed); })(); +// Used to compute the actual order pda address. Needed +// because the middle field is the hash of the intent, +// which is not an operation that can be expressed in IDL. export async function resolveOrderPda({ programAddress, args, diff --git a/programs/settlement/idl/client/js/src/index.ts b/programs/settlement/idl/client/js/src/index.ts index e84c86c..9aafe37 100644 --- a/programs/settlement/idl/client/js/src/index.ts +++ b/programs/settlement/idl/client/js/src/index.ts @@ -1 +1,2 @@ export * from "./generated"; +export * from "./order"; diff --git a/programs/settlement/idl/client/js/src/order.ts b/programs/settlement/idl/client/js/src/order.ts new file mode 100644 index 0000000..fb5f128 --- /dev/null +++ b/programs/settlement/idl/client/js/src/order.ts @@ -0,0 +1,59 @@ +// Helpers for working with OrderIntent + +import { OrderKind } from "./generated"; + +// re-export +export { OrderKind } from "./generated"; + +// The bit each field occupies +const CREATED_ON_CHAIN = 1 << 0; +const KIND = 1 << 1; +const PARTIALLY_FILLABLE = 1 << 2; + +/** The settings an `OrderIntent`'s `flags` byte packs. */ +export type Flags = { + /** + * How the order is authenticated: `true` if the owner creates it themselves + * with a `create_order` instruction they sign, `false` if it's authenticated + * off-chain by an Ed25519 signature, which lets anyone holding that signature + * create the order. + */ + createdOnChain: boolean; + + /** + * Whether `sellAmount` or `buyAmount` is the exact figure; the other side is + * treated as the limit (minimum to receive for `Sell`, maximum to spend for + * `Buy`). + */ + kind: OrderKind; + + /** + * If `true`, the order may be filled across multiple settlements. If `false`, + * a single settlement must consume the full sell amount (fill-or-kill). + */ + partiallyFillable: boolean; +}; + +/** Packs the settings into the canonical flags byte. Reserved bits are left clear. */ +export function encodeFlags({ + createdOnChain, + kind, + partiallyFillable, +}: Flags): number { + return ( + (createdOnChain ? CREATED_ON_CHAIN : 0) | + (kind === OrderKind.Buy ? KIND : 0) | + (partiallyFillable ? PARTIALLY_FILLABLE : 0) + ); +} + +/** + * Unpacks a flags byte + */ +export function decodeFlags(byte: number): Flags { + return { + createdOnChain: (byte & CREATED_ON_CHAIN) !== 0, + kind: (byte & KIND) === 0 ? OrderKind.Sell : OrderKind.Buy, + partiallyFillable: (byte & PARTIALLY_FILLABLE) !== 0, + }; +} diff --git a/programs/settlement/idl/client/js/tests/createOrder.test.ts b/programs/settlement/idl/client/js/tests/createOrder.test.ts index 081768e..4e45d98 100644 --- a/programs/settlement/idl/client/js/tests/createOrder.test.ts +++ b/programs/settlement/idl/client/js/tests/createOrder.test.ts @@ -45,8 +45,6 @@ describe("createOrder", () => { signTransactionMessageWithSigners, ); - // litesvm returns a native class, not a POJO: `err`/`meta` are methods, so - // `JSON.stringify(result.err)` would print `undefined` and hide the failure. const result = svm.sendTransaction(tx); if ("err" in result) { throw new Error( @@ -58,8 +56,7 @@ describe("createOrder", () => { programAddress: COW_SETTLEMENT_PROGRAM_ADDRESS, args: { intent }, }); - // `getAccount` returns a `MaybeEncodedAccount`, never null: a missing - // account comes back as `{ exists: false }`, so it needs an explicit check. + const account = svm.getAccount(orderPda); expect(account.exists).toBe(true); assertAccountExists(account); diff --git a/programs/settlement/idl/client/js/tests/fixtures.ts b/programs/settlement/idl/client/js/tests/fixtures.ts index 7a80636..8450b73 100644 --- a/programs/settlement/idl/client/js/tests/fixtures.ts +++ b/programs/settlement/idl/client/js/tests/fixtures.ts @@ -1,5 +1,6 @@ import path from "node:path"; import { generateKeyPairSigner, type Address } from "@solana/kit"; +import { encodeFlags } from "../src/order"; import { OrderKind, type OrderIntentArgs } from "../src/generated"; export const COW_SETTLEMENT_SO_PATH = path.join( @@ -7,31 +8,10 @@ export const COW_SETTLEMENT_SO_PATH = path.join( "../../../../../../target/deploy/cow_settlement.so", ); -/** - * Assembles the intent's `flags` byte from the settings it packs: bit 0 is - * created_on_chain, bit 1 the order kind, bit 2 partially_fillable. Reserved - * bits are left clear — the program rejects a byte carrying one. - */ -export function encodeFlags({ - createdOnChain, - kind, - partiallyFillable, -}: { - createdOnChain: boolean; - kind: OrderKind; - partiallyFillable: boolean; -}): number { - return ( - (createdOnChain ? 1 << 0 : 0) | - (kind === OrderKind.Buy ? 1 << 1 : 0) | - (partiallyFillable ? 1 << 2 : 0) - ); -} - export async function buildOrderIntent( overrides: Partial & { owner: Address }, ): Promise { - // create_order doesn't touch the token accounts or mints the intent names, so + // create_order doesn't actually check the token accounts or mints the intent names, so // they only have to be distinct addresses. const [buyTokenAccount, buyMint, sellTokenAccount, sellMint] = await Promise.all([ @@ -48,8 +28,6 @@ export async function buildOrderIntent( sellAmount: 1_000_000n, buyAmount: 2_000_000n, validTo: Math.floor(Date.now() / 1000) + 3600, - // This is the on-chain creation flow, so created_on_chain has to be set: - // create_order rejects an intent whose bit is clear. flags: encodeFlags({ createdOnChain: true, kind: OrderKind.Sell, diff --git a/programs/settlement/idl/client/js/tests/flags.test.ts b/programs/settlement/idl/client/js/tests/flags.test.ts new file mode 100644 index 0000000..810a3ae --- /dev/null +++ b/programs/settlement/idl/client/js/tests/flags.test.ts @@ -0,0 +1,33 @@ +import { describe, expect, it } from "vitest"; +import { decodeFlags, encodeFlags, type Flags } from "../src/order"; +import { OrderKind } from "../src/generated"; + +// Every combination of the three settings, with the byte the program's +// `Flags` encoding gives it. +const CASES: [Flags, number][] = [ + [{ createdOnChain: false, kind: OrderKind.Sell, partiallyFillable: false }, 0b000], + [{ createdOnChain: true, kind: OrderKind.Sell, partiallyFillable: false }, 0b001], + [{ createdOnChain: false, kind: OrderKind.Buy, partiallyFillable: false }, 0b010], + [{ createdOnChain: true, kind: OrderKind.Buy, partiallyFillable: false }, 0b011], + [{ createdOnChain: false, kind: OrderKind.Sell, partiallyFillable: true }, 0b100], + [{ createdOnChain: true, kind: OrderKind.Sell, partiallyFillable: true }, 0b101], + [{ createdOnChain: false, kind: OrderKind.Buy, partiallyFillable: true }, 0b110], + [{ createdOnChain: true, kind: OrderKind.Buy, partiallyFillable: true }, 0b111], +]; + +describe("flags", () => { + it.each(CASES)("encodes %j as %d", (flags, byte) => { + expect(encodeFlags(flags)).toBe(byte); + }); + + it.each(CASES)("decodes %j from %d", (flags, byte) => { + expect(decodeFlags(byte)).toEqual(flags); + }); + + it.each([0b1000, 0b1_0000, 0b1000_0000, 0xff])( + "rejects the reserved bits in %d", + (byte) => { + expect(() => decodeFlags(byte)).toThrow(/reserved bit/); + }, + ); +}); diff --git a/programs/settlement/idl/client/js/tsconfig.json b/programs/settlement/idl/client/js/tsconfig.json index 3da9187..44730bd 100644 --- a/programs/settlement/idl/client/js/tsconfig.json +++ b/programs/settlement/idl/client/js/tsconfig.json @@ -1,9 +1,6 @@ { "compilerOptions": { "target": "ES2022", - // The package ships TS sources (see package.json's `main`) and is consumed - // through a bundler, as vitest does here: extensionless relative specifiers - // — which is all codama's renderer emits — only resolve under this pair. "module": "Preserve", "moduleResolution": "bundler", "strict": true, diff --git a/programs/settlement/idl/generate.mjs b/programs/settlement/idl/generate.mjs index f40f276..7112538 100644 --- a/programs/settlement/idl/generate.mjs +++ b/programs/settlement/idl/generate.mjs @@ -25,22 +25,14 @@ codama.update( ]), ); +// build the TS library codama.accept( renderVisitor("./client/js", { - // resolveOrderPda hashes with crypto.subtle.digest, which is async, so - // codama must await it and only wire it into the *Async instruction - // builder rather than the sync one. asyncResolvers: ["resolveOrderPda"], }), ); -// codama inlines each PDA's const seeds into the function that derives it and -// exports no constant for them, so resolveOrderPda — which builds the order PDA -// seeds by hand — has nothing to import. Ship the IDL itself alongside the -// rendered client and let the resolver read the seed it needs off it, so the -// version-dependent bytes keep exactly one source and follow it across version -// bumps. Copied after the render because renderVisitor wipes its output -// directory first. +// add a copy of the IDl JSON to the generated output. Useful for resolved node hooks. mkdirSync("./client/js/src/generated", { recursive: true }); copyFileSync("./cow_settlement.json", "./client/js/src/generated/idl.json"); From f9f996b586f967e72123bd78225f121d88d0efdc Mon Sep 17 00:00:00 2001 From: Kaze <230549489+kaze-cow@users.noreply.github.com> Date: Tue, 1 Sep 2026 18:15:00 +0900 Subject: [PATCH 27/43] fixes from pre-review --- Justfile | 12 +++-- README.md | 16 +++++- bench-report.json | 52 +++++++++---------- .../settlement/idl/client/js/src/order.ts | 2 +- .../idl/client/js/tests/flags.test.ts | 7 --- 5 files changed, 51 insertions(+), 38 deletions(-) diff --git a/Justfile b/Justfile index 51d1a70..1a2d4fc 100644 --- a/Justfile +++ b/Justfile @@ -14,14 +14,20 @@ build-test-programs: build: build-program cargo build -# Run the test suite (builds the program first so the .so exists). -test: build-program build-test-programs - cargo test +# Runs all the generated code jobs +generate: generate-js-client # Builds the JS/TS client from IDL. generate-js-client: cd programs/settlement/idl && corepack pnpm install --frozen-lockfile && node generate.mjs +# Run the test suite (builds the program first so the .so exists). +test: build-program build-test-programs + cargo test + +# Run tests from the generated clients from the IDL +test-idl-generated: test-js-client + # Run the JS client's tests, which drive the real program through litesvm (needs the .so and a freshly rendered client). test-js-client: build-program generate-js-client cd programs/settlement/idl/client/js && corepack pnpm install --frozen-lockfile && corepack pnpm exec vitest run diff --git a/README.md b/README.md index 9b58760..e4240e0 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,8 @@ The repository is a Cargo workspace following the program / client / interface s - [`interface/`](./interface): shared types and the `Instruction` builders. Depends only on the lightweight crates so it can be consumed from both on-chain and off-chain code. - [`programs/settlement/`](./programs/settlement): the on-chain settlement program. + - [`programs/settlement/idl/`](./programs/settlement/idl): the IDL of the settlement program and its generated associated client libraries. + - [`programs/settlement/idl/client/js/`](./programs/settlement/idl/client/js/): A Typescript client generated from the IDL - [`client/`](./client): off-chain client helpers that re-export the builders from `interface` and add small convenience wrappers. @@ -37,18 +39,30 @@ Build the on-chain program (produces `target/deploy/settlement.so`): just build-program ``` -Build everything (workspace crates plus the on-chain program): +Build everything except IDL client libraries (workspace crates plus the on-chain program): ```sh just build ``` +The IDL client libraries can be generated with: + +```sh +just generate +``` + ### How to test ```sh just test ``` +The IDL client libraries can be tested with: + +```sh +just test-idl-generated +``` + ### Benchmarks `just bench` runs the test suite and regenerates `bench-report.json`: diff --git a/bench-report.json b/bench-report.json index 04d8ec7..8b69481 100644 --- a/bench-report.json +++ b/bench-report.json @@ -30,34 +30,34 @@ "transfer_authority/reclaim_authority_can_transfer_itself": 4 }, "compute_units": { - "add_solver/add_with_many_existing_solvers": 5068, - "add_solver/adds_a_solver": 4616, - "create_buffers/happy_path_creates_initialized_buffer_token_account": 7339, - "create_buffers/happy_path_creates_multiple_buffers_in_one_instruction": 17231, - "create_buffers/max_buffers_in_one_instruction": 169447, - "create_order/happy_path_creates_order_pda_with_expected_body": 4980, - "initialize/happy_path_initializes_state_pda_with_expected_data": 4524, - "reclaim_buffer/funded_buffer_is_skipped": 4828, - "reclaim_buffer/happy_path_reclaims_empty_buffer_to_the_authority_itself": 5979, - "reclaim_buffer/max_buffers_in_one_instruction": 124648, - "reclaim_buffer/reclaims_multiple_buffers_skipping_funded": 7575, - "reclaim_order/happy_path_expired_returns_lamports_and_closes_pda": 2199, - "reclaim_order/happy_path_on_chain_order_cancelled_is_reclaimable_before_expiry": 2068, - "reclaim_order/happy_path_on_chain_order_fully_filled_is_reclaimable_before_expiry": 2076, + "add_solver/add_with_many_existing_solvers": 5074, + "add_solver/adds_a_solver": 4622, + "create_buffers/happy_path_creates_initialized_buffer_token_account": 7345, + "create_buffers/happy_path_creates_multiple_buffers_in_one_instruction": 17243, + "create_buffers/max_buffers_in_one_instruction": 169540, + "create_order/happy_path_creates_order_pda_with_expected_body": 4985, + "initialize/happy_path_initializes_state_pda_with_expected_data": 4529, + "reclaim_buffer/funded_buffer_is_skipped": 4835, + "reclaim_buffer/happy_path_reclaims_empty_buffer_to_the_authority_itself": 5983, + "reclaim_buffer/max_buffers_in_one_instruction": 124652, + "reclaim_buffer/reclaims_multiple_buffers_skipping_funded": 7582, + "reclaim_order/happy_path_expired_returns_lamports_and_closes_pda": 2202, + "reclaim_order/happy_path_on_chain_order_cancelled_is_reclaimable_before_expiry": 2071, + "reclaim_order/happy_path_on_chain_order_fully_filled_is_reclaimable_before_expiry": 2079, "reclaim_order/off_chain_order_is_reclaimable_only_once_expired": null, "reclaim_order/on_chain_order_partially_filled_is_not_reclaimable_before_expiry": null, - "settle/finalizes_with_no_pushes": 7126, - "settle/pulls_from_multiple_orders": 19994, - "settle/pulls_funds_to_destination": 13593, - "settle/pulls_to_multiple_destinations": 14733, - "settle/pushes_a_single_order": 12449, - "settle/pushes_several_orders_from_different_buffers": 17704, - "settle/pushes_several_orders_from_one_buffer": 17703, - "settle/settles_a_single_order": 12467, - "settle/settles_multiple_orders": 23006, - "transfer_authority/manager_can_transfer_manager": 3171, - "transfer_authority/manager_can_transfer_reclaim_authority": 3173, - "transfer_authority/reclaim_authority_can_transfer_itself": 3177 + "settle/finalizes_with_no_pushes": 7154, + "settle/pulls_from_multiple_orders": 20059, + "settle/pulls_funds_to_destination": 13640, + "settle/pulls_to_multiple_destinations": 14781, + "settle/pushes_a_single_order": 12495, + "settle/pushes_several_orders_from_different_buffers": 17767, + "settle/pushes_several_orders_from_one_buffer": 17766, + "settle/settles_a_single_order": 12513, + "settle/settles_multiple_orders": 23086, + "transfer_authority/manager_can_transfer_manager": 3174, + "transfer_authority/manager_can_transfer_reclaim_authority": 3176, + "transfer_authority/reclaim_authority_can_transfer_itself": 3180 }, "transaction_bytes": { "add_solver/add_with_many_existing_solvers": 366, diff --git a/programs/settlement/idl/client/js/src/order.ts b/programs/settlement/idl/client/js/src/order.ts index fb5f128..c01166c 100644 --- a/programs/settlement/idl/client/js/src/order.ts +++ b/programs/settlement/idl/client/js/src/order.ts @@ -34,7 +34,7 @@ export type Flags = { partiallyFillable: boolean; }; -/** Packs the settings into the canonical flags byte. Reserved bits are left clear. */ +/** Packs the settings into a valid canonical flags byte. */ export function encodeFlags({ createdOnChain, kind, diff --git a/programs/settlement/idl/client/js/tests/flags.test.ts b/programs/settlement/idl/client/js/tests/flags.test.ts index 810a3ae..1d9861d 100644 --- a/programs/settlement/idl/client/js/tests/flags.test.ts +++ b/programs/settlement/idl/client/js/tests/flags.test.ts @@ -23,11 +23,4 @@ describe("flags", () => { it.each(CASES)("decodes %j from %d", (flags, byte) => { expect(decodeFlags(byte)).toEqual(flags); }); - - it.each([0b1000, 0b1_0000, 0b1000_0000, 0xff])( - "rejects the reserved bits in %d", - (byte) => { - expect(() => decodeFlags(byte)).toThrow(/reserved bit/); - }, - ); }); From 54699c302d0c9babad89e3309e86296c68d6e2ce Mon Sep 17 00:00:00 2001 From: Denis Makarov Date: Tue, 1 Sep 2026 15:58:27 +0400 Subject: [PATCH 28/43] feat: add publish github flow --- .github/workflows/ci.yml | 27 + .github/workflows/publish-npm.yml | 128 + .gitignore | 5 +- Justfile | 12 + README.md | 12 +- .../settlement/idl/client/js/package.json | 34 +- .../settlement/idl/client/js/pnpm-lock.yaml | 3460 +++++++++++++++++ .../idl/client/js/tsconfig.build.json | 7 + programs/settlement/idl/pnpm-lock.yaml | 505 +++ 9 files changed, 4177 insertions(+), 13 deletions(-) create mode 100644 .github/workflows/publish-npm.yml create mode 100644 programs/settlement/idl/client/js/pnpm-lock.yaml create mode 100644 programs/settlement/idl/client/js/tsconfig.build.json create mode 100644 programs/settlement/idl/pnpm-lock.yaml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 524acc5..92d43e1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -81,6 +81,33 @@ jobs: - name: Dev docs run: just doc-dev + js-client: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 + with: + persist-credentials: false + + - uses: ./.github/actions/setup-solana + - uses: ./.github/actions/setup-just + - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 + + - uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6.0.10 + with: + version: 10 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + with: + node-version: 22 + cache: pnpm + cache-dependency-path: | + programs/settlement/idl/pnpm-lock.yaml + programs/settlement/idl/client/js/pnpm-lock.yaml + + - name: Build JS client + run: just build-js-client + - name: Test JS client + run: just test-js-client + build-verified: runs-on: ubuntu-latest steps: diff --git a/.github/workflows/publish-npm.yml b/.github/workflows/publish-npm.yml new file mode 100644 index 0000000..28e1bbe --- /dev/null +++ b/.github/workflows/publish-npm.yml @@ -0,0 +1,128 @@ +name: Publish npm package + +on: + release: + types: [published] + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + outputs: + package-name: ${{ steps.pkg.outputs.name }} + package-version: ${{ steps.pkg.outputs.version }} + steps: + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 + with: + persist-credentials: false + + - uses: ./.github/actions/setup-solana + - uses: ./.github/actions/setup-just + - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 + + - uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6.0.10 + with: + version: 10 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + with: + node-version: 22 + cache: pnpm + cache-dependency-path: | + programs/settlement/idl/pnpm-lock.yaml + programs/settlement/idl/client/js/pnpm-lock.yaml + + - name: Build JS client + run: just build-js-client + - name: Test JS client + run: just test-js-client + + - name: Read package metadata + id: pkg + working-directory: programs/settlement/idl/client/js + run: | + echo "name=$(node -p 'require("./package.json").name')" >> "$GITHUB_OUTPUT" + echo "version=$(node -p 'require("./package.json").version')" >> "$GITHUB_OUTPUT" + + - name: Version must match the release tag + if: github.event_name == 'release' + working-directory: programs/settlement/idl/client/js + run: | + # Existing tags (v0.2, v0.3) are major.minor only, while npm/Cargo need + # full semver (0.3.0), so pad any missing patch component before comparing. + tag="${GITHUB_REF_NAME#v}" + IFS='.' read -r major minor patch <<< "$tag" + normalized_tag="${major}.${minor:-0}.${patch:-0}" + pkg_version="${{ steps.pkg.outputs.version }}" + if [ "$normalized_tag" != "$pkg_version" ]; then + echo "::error::Release tag $GITHUB_REF_NAME (normalized: $normalized_tag) does not match package.json version $pkg_version. Bump programs/settlement/idl/client/js/package.json's version as part of the release PR before publishing." >&2 + exit 1 + fi + + - name: Write publish summary + working-directory: programs/settlement/idl/client/js + run: | + { + echo "## npm publish review" + echo + echo "Before approving, confirm:" + echo "1. The tarball contents below only include expected files (no stray secrets, keys, or debug output)." + echo "2. The dependency diff below has no unexpected new/changed packages." + echo "3. Package \`${{ steps.pkg.outputs.name }}\` is being published at version \`${{ steps.pkg.outputs.version }}\`, matching release \`${{ github.event.release.tag_name || github.ref_name }}\`." + echo + echo "### Tarball contents (\`npm pack --dry-run\`)" + echo '```' + npm pack --dry-run 2>&1 + echo '```' + echo + echo "### Dependency diff vs. previously published version" + name="${{ steps.pkg.outputs.name }}" + if ! npm view "$name" version >/dev/null 2>&1; then + echo "_First publish of this package — nothing to diff against._" + else + prev_deps_json=$(npm view "$name" dependencies --json 2>/dev/null); [ -z "$prev_deps_json" ] && prev_deps_json='null' + prev_peer_json=$(npm view "$name" peerDependencies --json 2>/dev/null); [ -z "$prev_peer_json" ] && prev_peer_json='null' + node -e ' + const fs = require("fs"); + const [prevDeps, prevPeer] = process.argv.slice(1).map((s) => JSON.parse(s)); + const curr = require("./package.json"); + fs.writeFileSync("/tmp/prev-deps.json", JSON.stringify({dependencies: prevDeps, peerDependencies: prevPeer}, null, 2) + "\n"); + fs.writeFileSync("/tmp/curr-deps.json", JSON.stringify({dependencies: curr.dependencies ?? null, peerDependencies: curr.peerDependencies ?? null}, null, 2) + "\n"); + ' "$prev_deps_json" "$prev_peer_json" + echo '```diff' + diff -u /tmp/prev-deps.json /tmp/curr-deps.json || true + echo '```' + fi + } >> "$GITHUB_STEP_SUMMARY" + + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: npm-package + path: | + programs/settlement/idl/client/js/dist + programs/settlement/idl/client/js/package.json + + publish: + needs: build + runs-on: ubuntu-latest + # Configure this environment in repo Settings > Environments with required + # reviewers: whoever approves is confirming the checklist in the `build` + # job's step summary, not just that CI is green. + environment: npm-publish + permissions: + id-token: write # for npm provenance + steps: + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: npm-package + path: package + + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + with: + node-version: 22 + registry-url: https://registry.npmjs.org + + - name: Publish ${{ needs.build.outputs.package-name }}@${{ needs.build.outputs.package-version }} + working-directory: package + run: npm publish --provenance --access public + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.gitignore b/.gitignore index 2ded9aa..10936ba 100644 --- a/.gitignore +++ b/.gitignore @@ -2,10 +2,11 @@ proptest-regressions/ .cargo-root/ node_modules/ -pnpm-lock.yaml generated/ +dist/ +.idea/ # Make sure no Solana key is uploaded by accident. *.json !bench-report.json -!programs/settlement/idl/** +!programs/settlement/idl/**/*.json diff --git a/Justfile b/Justfile index a58e79a..cbcd258 100644 --- a/Justfile +++ b/Justfile @@ -61,6 +61,18 @@ doc *args: doc-dev *args: cargo doc --workspace --no-deps --all-features --document-private-items --config 'build.rustdocflags=["--deny=warnings"]' {{ args }} +# Generate the TS/JS client from the IDL using Codama. +gen-js-client: + cd programs/settlement/idl && pnpm install --frozen-lockfile && node generate.mjs + +# Build the publishable TS/JS client package (bundles the Codama-generated code plus hand-written wrappers). +build-js-client: gen-js-client + cd programs/settlement/idl/client/js && pnpm install --frozen-lockfile && pnpm run build + +# Run the TS/JS client's test suite against the compiled settlement program. +test-js-client: build-program gen-js-client + cd programs/settlement/idl/client/js && pnpm install --frozen-lockfile && pnpm test + # Build the settlement program using solana-verify's reproducible Docker build. # Installs solana-verify via cargo if not already present (same as CI). build-verified: diff --git a/README.md b/README.md index 9b58760..5422bd1 100644 --- a/README.md +++ b/README.md @@ -109,6 +109,12 @@ Then, all packages can published in one go: cargo publish ``` +### Publishing the npm package + +The TS/JS client (`@cowprotocol/cow-settlement-client-js`, generated from `programs/settlement/idl/cow_settlement.json` via Codama) is published automatically by [`publish-npm.yml`](.github/workflows/publish-npm.yml) whenever a GitHub release is cut — its version must already match the release tag (see [Bumping the crate version](#bumping-the-crate-version), which bumps it alongside the crates). + +Publishing itself requires a manual approval in the `npm-publish` GitHub Environment. Before approving, check the job summary the workflow posts: it lists the exact tarball contents about to be published and a dependency diff against the previously published version. Approve only if both look as expected for the changes in this release. + ### Devnet example ```sh @@ -140,7 +146,7 @@ You can use the settle CLI for a smoke test of the programs after a release. See - Make sure the package installs without errors: run `cargo install --path /mnt/lima-solana/repos/solana-programs/solana-program-workbench/test-cli --locked` (it depends on all other packages). - Create a PR with the changes and wait for approval. - [Publish the cargo packages](#publishing-the-cargo-packages). -- Create a [new GitHub release](https://github.com/cowprotocol/solana-programs/releases/new); in doing so, create a new tag like `v0.42`; title "Alpha release, v0.42". +- Create a [new GitHub release](https://github.com/cowprotocol/solana-programs/releases/new); in doing so, create a new tag like `v0.42`; title "Alpha release, v0.42". This is also what triggers the npm package publish workflow — see [Publishing the npm package](#publishing-the-npm-package). ### Patch update @@ -150,10 +156,11 @@ You can use the settle CLI for a smoke test of the programs after a release. See - Create a PR with the changes and wait for approval. - [Update the programs](#how-to-deploy). The deployer keypair and the program keypair are in 1password (stored respectively under "Solana Deployer" and "Settlement account by version"). - [Publish the cargo packages](#publishing-the-cargo-packages). +- Create a [new GitHub release](https://github.com/cowprotocol/solana-programs/releases/new); in doing so, create a new tag including the patch number, like `v0.42.1` (unlike breaking-change releases, the patch digit here is non-zero, so it must be included to avoid colliding with the `v0.42` tag); title "Alpha release, v0.42.1". This is also what triggers the npm package publish workflow — see [Publishing the npm package](#publishing-the-npm-package). ### Bumping the crate version -You need to update Cargo's toml and lock file. +You need to update Cargo's toml and lock file, and the npm package's version (kept in lockstep so a release tag maps to one version everywhere). Here is a list of commands to help bumping all relevant strings: ```sh @@ -162,6 +169,7 @@ perl -i -pe ' s/^version = ".*"/version = "$ENV{VERSION}"/; s/(path = "[^"]*", version = )"[^"]*"/$1"$ENV{VERSION}"/; ' ./Cargo.toml +perl -i -pe 's/^(\s*"version": )".*"/$1"$ENV{VERSION}"/' ./programs/settlement/idl/client/js/package.json just build ``` diff --git a/programs/settlement/idl/client/js/package.json b/programs/settlement/idl/client/js/package.json index 298012c..1ba6542 100644 --- a/programs/settlement/idl/client/js/package.json +++ b/programs/settlement/idl/client/js/package.json @@ -1,18 +1,33 @@ { - "name": "js-client", - "version": "1.0.0", - "description": "", - "main": "src/index.ts", + "name": "@cowprotocol/cow-settlement-client-js", + "version": "0.3.0", + "description": "TypeScript/JavaScript client for the CoW Protocol Solana settlement program, generated from its IDL.", + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", + "license": "MIT OR Apache-2.0", + "author": "CoW Protocol", + "repository": { + "type": "git", + "url": "https://github.com/cowprotocol/solana-programs.git", + "directory": "programs/settlement/idl/client/js" + }, + "publishConfig": { + "access": "public" + }, "files": [ - "./dist/src", - "./dist/types", - "./src/" + "dist/**" ], "scripts": { + "build": "tsup src/index.ts --format esm --dts --out-dir dist --tsconfig tsconfig.build.json", "test": "vitest run" }, - "keywords": [], - "author": "", + "keywords": [ + "solana", + "cow-protocol", + "defi", + "settlement" + ], "peerDependencies": { "@solana/kit": "^6.10.0" }, @@ -23,6 +38,7 @@ "@solana/kit": "^6.10.0", "@types/node": "^24.10.0", "litesvm": "^1.3.0", + "tsup": "^8.5.1", "typescript": "^5.7.0", "vitest": "^3.0.0" } diff --git a/programs/settlement/idl/client/js/pnpm-lock.yaml b/programs/settlement/idl/client/js/pnpm-lock.yaml new file mode 100644 index 0000000..f80048b --- /dev/null +++ b/programs/settlement/idl/client/js/pnpm-lock.yaml @@ -0,0 +1,3460 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@solana/program-client-core': + specifier: ^6.10.0 + version: 6.10.0(typescript@5.9.3) + devDependencies: + '@solana/kit': + specifier: ^6.10.0 + version: 6.10.0(typescript@5.9.3) + '@types/node': + specifier: ^24.10.0 + version: 24.13.3 + litesvm: + specifier: ^1.3.0 + version: 1.4.1(typescript@5.9.3) + tsup: + specifier: ^8.5.1 + version: 8.5.1(postcss@8.5.26)(typescript@5.9.3) + typescript: + specifier: ^5.7.0 + version: 5.9.3 + vitest: + specifier: ^3.0.0 + version: 3.2.7(@types/node@24.13.3) + +packages: + + '@esbuild/aix-ppc64@0.27.7': + resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/aix-ppc64@0.28.2': + resolution: {integrity: sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.27.7': + resolution: {integrity: sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm64@0.28.2': + resolution: {integrity: sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.27.7': + resolution: {integrity: sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-arm@0.28.2': + resolution: {integrity: sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.27.7': + resolution: {integrity: sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/android-x64@0.28.2': + resolution: {integrity: sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.27.7': + resolution: {integrity: sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-arm64@0.28.2': + resolution: {integrity: sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.27.7': + resolution: {integrity: sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/darwin-x64@0.28.2': + resolution: {integrity: sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.27.7': + resolution: {integrity: sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-arm64@0.28.2': + resolution: {integrity: sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.27.7': + resolution: {integrity: sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.28.2': + resolution: {integrity: sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.27.7': + resolution: {integrity: sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm64@0.28.2': + resolution: {integrity: sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.27.7': + resolution: {integrity: sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-arm@0.28.2': + resolution: {integrity: sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.27.7': + resolution: {integrity: sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-ia32@0.28.2': + resolution: {integrity: sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.27.7': + resolution: {integrity: sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-loong64@0.28.2': + resolution: {integrity: sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.27.7': + resolution: {integrity: sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-mips64el@0.28.2': + resolution: {integrity: sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.27.7': + resolution: {integrity: sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-ppc64@0.28.2': + resolution: {integrity: sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.27.7': + resolution: {integrity: sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-riscv64@0.28.2': + resolution: {integrity: sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.27.7': + resolution: {integrity: sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-s390x@0.28.2': + resolution: {integrity: sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.27.7': + resolution: {integrity: sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/linux-x64@0.28.2': + resolution: {integrity: sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.27.7': + resolution: {integrity: sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-arm64@0.28.2': + resolution: {integrity: sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.27.7': + resolution: {integrity: sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.28.2': + resolution: {integrity: sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.27.7': + resolution: {integrity: sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-arm64@0.28.2': + resolution: {integrity: sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.27.7': + resolution: {integrity: sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.28.2': + resolution: {integrity: sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.27.7': + resolution: {integrity: sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/openharmony-arm64@0.28.2': + resolution: {integrity: sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.27.7': + resolution: {integrity: sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/sunos-x64@0.28.2': + resolution: {integrity: sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.27.7': + resolution: {integrity: sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-arm64@0.28.2': + resolution: {integrity: sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.27.7': + resolution: {integrity: sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-ia32@0.28.2': + resolution: {integrity: sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.27.7': + resolution: {integrity: sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@esbuild/win32-x64@0.28.2': + resolution: {integrity: sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.6.0': + resolution: {integrity: sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@napi-rs/lzma-linux-x64-gnu@1.5.1': + resolution: {integrity: sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ==} + engines: {node: ^22.20 || ^24.12 || >=25} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-android-arm-eabi@4.63.1': + resolution: {integrity: sha512-UZ8sUxPTiHWYX9QNdJedb1kDZSpS1t/VPWBWGSgqHNi9w3Cu6IXvu2mzbhiTiPvtrqgTQJ+zqiAq2iPIPilpaQ==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.63.1': + resolution: {integrity: sha512-cQ4nFQABN5cDvDpbvJ7bMStCpnaVxynZrRMfUJYgxcIk9Sh54FIO1vtfkg0B69REjER77ioZ/ov+eAApx/KmLQ==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.63.1': + resolution: {integrity: sha512-FQNqd1lRy/0QhDk3xeRIkSBiCpXCiDnZO3YLVdcDKN1UBiKToNftCzcXYNLshmPDUMlu2TdeS8tGcsU6f3YF1Q==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.63.1': + resolution: {integrity: sha512-pvD16V939D3CloK0+qikpGaxiPrDUXTe7Y5cWOMkMSy7m1cawa8EGy/kXYi/G/cKAC4HDAbSnzCIk1WmsoOKXg==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.63.1': + resolution: {integrity: sha512-pcFGeL2345VwdTnJhA6zLbew+YgWB0qBG2+dMtXjCicf6+rm6kO6cOoh5VnTe0ZMrMRgRyuHmCJxZWrIdzYuOw==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.63.1': + resolution: {integrity: sha512-mRJlqSRulVzcKq/LKA6ICSIc3K/l4fzlVn/gePn2nXIHy8seRi5z/eeRE0d/XMBxcMldiXtQTSpRj0tkkC3g8Q==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.63.1': + resolution: {integrity: sha512-YDUNvVM85TI3g/1OpnqKP1h4NeW/j64DfWMf+G3M809xNk1bJSnpFp4sh83NpmVE5DXnkh8ULor4LTVZKoYLHw==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-arm-musleabihf@4.63.1': + resolution: {integrity: sha512-7Mcn71p9ZuQFAj+h+dhQXy/yeLePRS2yKRnmW1DijA9thKO5qap0GNOIQK4yQ6iP3SU0Mrb/yWo8h8vgRba8lw==} + cpu: [arm] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-arm64-gnu@4.63.1': + resolution: {integrity: sha512-4YiLQTX6U4CSl0L9cluep9A9W6UmTfqBDc2/CH6wlu54pl4E7Jn3cOD8oxzvBDEGk/JMKgJ47C8g+radF7mwvg==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-arm64-musl@4.63.1': + resolution: {integrity: sha512-2ra8F7w8OquwZN9z2/fKFnli69wa8PLwaVzRMIPGb13ByMJwC28Fbp8YcVGoUhlYMTt7j5j9bNgpysrN2UM+vw==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-loong64-gnu@4.63.1': + resolution: {integrity: sha512-Sy20ncyhjmBP0Ml+UvQbimjlk6VFgjW5uNP+qqwHB00mTE8Bl2C1TuHTlRwK2YoXeZbee5lP2XevBWVkAQAtSQ==} + cpu: [loong64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-loong64-musl@4.63.1': + resolution: {integrity: sha512-noITLp8oNjYliPnGWmLyelIHwULGqbHloQHGw1rtxbWhTuWooRpnZarZQJ1y9EUC4szuCusCc+HEpUtxpIwYvA==} + cpu: [loong64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-ppc64-gnu@4.63.1': + resolution: {integrity: sha512-hlxxXd+F1mWiAcaFR7Sv9ZQT6m6UfI8+Vy/kFJzztq2pDMU/0wZ9sish0iszNZvsQDo8Gc0i5yuFEOz5dDf6fA==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-ppc64-musl@4.63.1': + resolution: {integrity: sha512-EF7OpqQTQ/BvGqLzUi4rEHuagCV9MugAUXSHemwPW5vxZ75RR+jxO/2j95Ph2dalMpFHSVECjRoioHZgA9zOYA==} + cpu: [ppc64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-riscv64-gnu@4.63.1': + resolution: {integrity: sha512-wQO3JesW9PRkwlabQ27y7sPfVOOTLRG73I4F2UYHG5PXun3J9U3y+b7ezVKSYbsvSKGQ1k1cq8Qlun4C9kLt3w==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-riscv64-musl@4.63.1': + resolution: {integrity: sha512-ouAGwhO6wHRXdnOVCOsB0tRFkA7nhNB2Nwax6oECXN0YiN8EYUTBAOudADOB1PI+yDL61TeNx/u7MVCzksNbkQ==} + cpu: [riscv64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-s390x-gnu@4.63.1': + resolution: {integrity: sha512-q2R38Sn+1J8RxhfJ+T54wSWmyKXWec+9jgDfqO2AtArEqHO5R2aeayp5H5OYLr5UYDVGsVaZPEFUooMhYCdz5A==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-x64-gnu@4.63.1': + resolution: {integrity: sha512-gfI5T24WLLuFfSKw7Go/zDXjAAV0fny0swTaDv+WjK7vqcw4cRhFfdsyKL1n+ukI+ooBxn3bVQnyrn06WpI50w==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-x64-musl@4.63.1': + resolution: {integrity: sha512-4h6XqthmB4Hspji84wvgk+ElodTsGj+dbZqHJHHtKxj4mYq0ANSEEPX9ys3moJueqsRjwpaJYH7874Itwnj2ow==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rollup/rollup-openbsd-x64@4.63.1': + resolution: {integrity: sha512-dlfCOa87o1VAYegLQ9EKilx2JCeRofiyPGhTCmqnuXZ6bMPiycO1rq1+sKoulAp7pGLIsTIw+1x5R+zgh5LhhA==} + cpu: [x64] + os: [openbsd] + + '@rollup/rollup-openharmony-arm64@4.63.1': + resolution: {integrity: sha512-cjkLbOlfcm3QGhMM1J5zaZjsw1GggbN6rw9UTSSRrPrR1KkcXnN7Uq9rPw34xImQ9VOY9GN+6u2Zj80B9ptkcw==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.63.1': + resolution: {integrity: sha512-Li1KdUnWGE4N3e1F/B4RTB1ms+nG4WBgjByO46pkeBVX/2UBsY53xf5vK9WygVmnH3RwncIST7lkSdLSY6P9lg==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.63.1': + resolution: {integrity: sha512-t4ZYOSoLTgwhuFMrmTMLx/+i1DQVK7HYqMc6kY46EApwi8X0nIVphzdNoThU3xt6n+N5urG1/gxBdCaKDLavfg==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.63.1': + resolution: {integrity: sha512-RgroPfMmKlD1RzSDxvwgcPiy2HNQKoYV7OmwIXDsk73uKW5t6B/V8KIy27SMv/FNXFo/oSBtWc9J0X7t91ezZg==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.63.1': + resolution: {integrity: sha512-at8QVep6S3h5Y6gSbdGU06bRY5WJkf6WUduM9YtvYMbYhB1MOFfUgc6kehitQXzOtMSaT70q7f9ydPhpqu821w==} + cpu: [x64] + os: [win32] + + '@solana-program/system@0.14.0': + resolution: {integrity: sha512-Pjs2RINZHYmk/pqWNBCuQmfNjZT9woPJ/w7QkzzCSwcqcokbARtxsnIdgj4lJVxvr1DuxG8JGIbKnq6z1QRY6Q==} + peerDependencies: + '@solana/kit': ^8.0.0 + + '@solana-program/token@0.16.0': + resolution: {integrity: sha512-VuFIu5vXsw1zwqls4/sGB88234oucmpuig553A33UnrbYnPZ8yXmqLYULBD92/k1pCGnMK+NMLWvsKzlZQ/1Kw==} + engines: {node: '>=24.0.0'} + peerDependencies: + '@solana/kit': ^8.0.0 + + '@solana/accounts@6.10.0': + resolution: {integrity: sha512-+FxfDOrnifoPlBkF+fr8eeQdgM6xtIgAg9xKMu3WnIz60oZd4Xnry6+ff6t+ePPoZZp397FSg9ZJet68VCWm5Q==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/accounts@8.2.0': + resolution: {integrity: sha512-An3BICrQJQ7jR5EIgXzYnaKyCE7+ZusW9xX8m6Vj7U2cKo8t6Y3PTQ+aMjEajwzsQfxEL8QnpClFC9hdoIu7MA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/addresses@6.10.0': + resolution: {integrity: sha512-vEoCGBTxG0HCERAn84KXkrJjl+pDaNzOpZ0qbgcPS98fYxP5yzbKB8SNOY2bzrbkRUmmw5Q3hqTRERemUN2Gcw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/addresses@8.2.0': + resolution: {integrity: sha512-7Okh8u7d3QrKu7ltJa3PASniUhasn1cdbcMQ/8gpGsmHQNCvdtAmvw18xSTdr4m62RJ/0cI/DtTVQyNwooeAXQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/assertions@6.10.0': + resolution: {integrity: sha512-lKSAdVo+P/6Lp4vs6shstXmFOpvxrABwn4o1462tb7sKkNapk6o9pPFVPGw4DUgPS3WqWRs1j2tmpuVjhQRntg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/assertions@8.2.0': + resolution: {integrity: sha512-izrnF8ZsviZDK0WCKl9ha5Ht4TNDHoU2QzMrPYOqkSkKkVh15p3MjTRXVFnM4CA+Xigtu8y8OPu2UnQNcAUVHQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/codecs-core@6.10.0': + resolution: {integrity: sha512-nfAl9OMGo4HanIMxGsQoVB7BxMoqBCYEUxl8oEAZZ09pDxnaXQZkTRXEwPPccag37XfW1ciPd1vWPKwB2b0HHQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/codecs-core@8.2.0': + resolution: {integrity: sha512-ORwzswFXbqNqlyVigogFIrn3Ge5cpDQkuMY0u3M40HBwHcC6a79uqM87DpoZypncKJDWA1DfJ/3w9hhTGumYAw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/codecs-data-structures@6.10.0': + resolution: {integrity: sha512-CNasJW3bq5u+632Zt5aJ8rOjAjv2HyenpV8o9kAIqdmV4CBpjCCoBnKn8LkuR/sbeREZxJYfhKTXO/9ruAkw7A==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/codecs-data-structures@8.2.0': + resolution: {integrity: sha512-uq59oSAXM9QR+cO7R3JmSTxBiNNJnayVWz2VHBdhhCQS8DEmd6hhqY1RVmPTpFtE0Jix5MkRV3Bu5GTmf6Y66A==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/codecs-numbers@6.10.0': + resolution: {integrity: sha512-CcM+wX4zOiA9zkh8A7t1787A0Ehgmu5+6Z2tKoHew6cNw/dkaUTPa8JnNHbvfsLC8dfHC1BhAEJl86sKmRsfkQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/codecs-numbers@8.2.0': + resolution: {integrity: sha512-GTOYzyk0SxQJS7MAN9zsyax4RFUtQDYzkVcpRf0Zo7eOy2/hPfuih09VJL2YdLPBJBcg8satdAYBYxxC282PYQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/codecs-strings@6.10.0': + resolution: {integrity: sha512-zlaqkg7K6F6IN4V/Ec8TWkTn054gxv7ZLagvGkuEyAdPQ6BzzsehOm2TqCuyXgJJTCGPLY1bEk6yH9NxANe0kA==} + engines: {node: '>=20.18.0'} + peerDependencies: + fastestsmallesttextencoderdecoder: ^1.0.22 + typescript: '>=5.4.0' + peerDependenciesMeta: + fastestsmallesttextencoderdecoder: + optional: true + typescript: + optional: true + + '@solana/codecs-strings@8.2.0': + resolution: {integrity: sha512-Dt/+rJ6gmH/OcOtvrhm6CtbB9jtVOGMxcIXoi62eNXw39Z1kJyN1gkqTjzBSS8Xb+X5lfkL70GHE9EDBb1JmqA==} + engines: {node: '>=20.18.0'} + peerDependencies: + fastestsmallesttextencoderdecoder: ^1.0.22 + typescript: '>=5.4.0' + peerDependenciesMeta: + fastestsmallesttextencoderdecoder: + optional: true + typescript: + optional: true + + '@solana/codecs@6.10.0': + resolution: {integrity: sha512-lLVuxod4ChWp9i7OvpgIykYG8Q9OGPVXKnHM9VlzDDLylsx7Y1FoQL00sHa7PqFkJVmkBufaA6dcGbQ7FU+lAQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/codecs@8.2.0': + resolution: {integrity: sha512-kn2esyzFznx6Pbb+8FUe3YNKYRZUB8H81pCiXSIe1+0WJ44lRhZHMo0s4L3FQMKhWHOnlV30sWeIg8taHLVW7g==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/errors@6.10.0': + resolution: {integrity: sha512-KBLAxCtAXr357JNhCyIDQXWbuSj5vN6w+28FSfcYY6OOSiphmXLAV3V58jgV0C6iNbIzFJFi6yatFyDTdeJsNg==} + engines: {node: '>=20.18.0'} + hasBin: true + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/errors@8.2.0': + resolution: {integrity: sha512-BXc9mafl3SOnRL542jY02ezBSXHgqQOUCzREN/vvh1ASUPrUB3iorOEc62cSxFdDU4aDVMcugowJawmVNTXXSg==} + engines: {node: '>=20.18.0'} + hasBin: true + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/fast-stable-stringify@6.10.0': + resolution: {integrity: sha512-iCNed27wk6PKSS3QUtHovRfMWF/jbVWogs2vB4tukKUCsqG4rDfDInIwZ6ur/nY6XTrgi2gMMdZq9GAUlWsbfw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/fast-stable-stringify@8.2.0': + resolution: {integrity: sha512-OND76Qsng/fiTVSUvaNZFv0WKEULlwcGRtgeIE2keA2xYoHYNTSoD6mxv4iWANfeDo4EH7D/HnOwnGEFXMjr9w==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/fixed-points@6.10.0': + resolution: {integrity: sha512-ZkKL0alXH3L7/wMiVG8YUuG8qBKunlM810+YBD7nUPRhifiGsX1zwADViHLYNqLr/jUk0mTYFUcKznTpB/K+Gg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/fixed-points@8.2.0': + resolution: {integrity: sha512-w19JKErcbbENZzw4B+oBGwJXVKMIOi8TC7WxBawmpuv0XJSk6LP6surosg+XeoBHhtEsVCNHDtizi0mAS6OmMw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/functional@6.10.0': + resolution: {integrity: sha512-P8cevu4mAqHTXC37h1TVoOh8zhWB2tlOI/R9vWjYPpcLwcyWf8p2qq4LEGHl5kY+1C+4PNX39HsmCocXOPCDkQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/functional@8.2.0': + resolution: {integrity: sha512-+oTPl9yRZBbppUZU8qs4eu93iWPvs4Ij+HELPHISxLFo/cuG2YZGTDcWBVEzc8XEw0DUwwBOvou/wP7v1SnH+A==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/instruction-plans@6.10.0': + resolution: {integrity: sha512-YG7mo4zykzdc6ZTV0BuN6pveK9qeBySzlYYerq578A4eQu3xcypMAYRGAvhMZtWTanjjmD6CKtM0M7kVp0TNxg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/instruction-plans@8.2.0': + resolution: {integrity: sha512-DDVHBAPifG3Q0s5e2hiBbfvrruLb3AhumTupDK+3f3f7MDc0Dth6rX054HtIINloqbFIw15f6/A3Z4VTh74CTg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/instructions@6.10.0': + resolution: {integrity: sha512-0TToYF+8LXQ3ofPMx+yF6yaM9l4YJvcAPMy0qV5JsrBUFlWXBSANRuudKBQLHMvb+a3OiUTq5X7omuorKMBB3A==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/instructions@8.2.0': + resolution: {integrity: sha512-SFts84wW6hDXGSrLK5spl8nbKxKns2aR+S2ar0Zi3I0bl007heyoO7UKyxAoUvhfhObIfEIMuy2/qLoo6vDcjQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/keys@6.10.0': + resolution: {integrity: sha512-26IRfdm/hTUCmM7MeEeX0ULSbCM6OzkZTkfkrPircqmRM7xyNqP4hq7u0P7wjb9dl7NfgyG6K7cdvUxrj2e3mA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/keys@8.2.0': + resolution: {integrity: sha512-DezFZ0/ya98nILq+eSeq9fu9onVfqQYb7mtuDctdWxY1QFJvix562zkkFuFqnjOLL7XMEpdVPMxxQOzZ33wGCg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/kit@6.10.0': + resolution: {integrity: sha512-/WnnQp3uARh2JCFSfAakejTAqwmXVuMVTcRn5r2yDwY2yzZ4R6mt/Cl59VPimVLNSoTyN/KsEwhv9omr3ERazQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/kit@8.2.0': + resolution: {integrity: sha512-1BfmnYmWe17u3RRX3HuNxjWkr2/n9Bai+yIG/XjMpgviobF3n8zsisZBJHPH2uORqvjkTFnOqGXoEQC8vUZHzw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/nominal-types@6.10.0': + resolution: {integrity: sha512-9ykyBBvnkInH7fCacjJi7zu2PJyd+OCt+VTjIISv070fHzKIMFqZqJJ/dJ0SRH2aHwfB3n86iVsmtBtuxi4KKA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/nominal-types@8.2.0': + resolution: {integrity: sha512-iuDE6ewgT7LJOSVC6UK4HR6n8INujujbglYVVFWNK/xWKi5p1y8JCOEEWAl/htK26LhLC51A1nMNfmBmTjP3ZQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/offchain-messages@6.10.0': + resolution: {integrity: sha512-RiEgAueeMkFMC1suOXBIcmCZgtXRxy24yk0DldPB37bB4zwOF1SAaRjNRPjIkGK8RhCYrEpPosnzLyavw9ueRg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/offchain-messages@8.2.0': + resolution: {integrity: sha512-yXfVtK1VoQ/Eyz2jH/1+avixhYcpCPkGkXuiXxA3Vf73WCvniC8mNVQ5ppsV+OqCNw62mxaFMmNiVgiAQapKuw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/options@6.10.0': + resolution: {integrity: sha512-RO9UT3UYD8/Cu2uM6ZXbKvLeMnVD42+g9JRds7Pfs4AhiOyg4R4TJrQUAppTgavPTO3PBRlWtWOC05ZH/yAIbg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/options@8.2.0': + resolution: {integrity: sha512-b3//UzZe/uBaIpw4fT/nvCOghh5IHoNkW7FCMA/nzvQ48A16n8qpLki9/+lLHi0V0o7/Jz5Sof0UYc0aSf1Dig==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/plugin-core@6.10.0': + resolution: {integrity: sha512-JE70YTQOfFACVFGvoJon4Scc/eHUWjMu8Ovo35CcV2kHTAHYMCd4UkBd2gmlhK0vRMMomsQi1ZLPlAlTq0OoUQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/plugin-core@8.2.0': + resolution: {integrity: sha512-V7oSIhYXbUzjd5LUY4tbSUnyBka1hmULPFKuqxNzYxeY4eLI7S8GmTOg7xg6tOC0bJ+HLPvv64asuMXAn/PklQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/plugin-interfaces@6.10.0': + resolution: {integrity: sha512-vr0/l9wcM4orwGr8cjkFWaJ9A4HvzuAv00jMFNMg0Spd0GZqnwnpW+D/fXa1lIJnTRaF3EeEjLh4VjKU037T0Q==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/plugin-interfaces@8.2.0': + resolution: {integrity: sha512-goOhGI493Fq+xhZ8JKl9/FDVFd0SJdkv5Lh0L2ubqekzUiGRCvHNwgXL8nVS7fso2UxIssDQmYKwXvubfhBVhw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/program-client-core@6.10.0': + resolution: {integrity: sha512-4PPbTLdC1ylHIuvhOFDP8RnSkXPCFjNFWGslzc+UFKnoR4ajzBcByX94jmaruDMk5ncxgj7tr9pzJTvfGHIaMA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/program-client-core@8.2.0': + resolution: {integrity: sha512-miQ7qKW0d0etaa2YAehGU3heV5Y4ip5BBCwZXb/yg8yWndTt4d4E+8z+5Q/oS5kOuFraOFYr+Uev7SQKngNXBg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/programs@6.10.0': + resolution: {integrity: sha512-qn/HeLP5KGUJXVub3fyGe69/rWaLX4jzwm6V/1pNxJDbdF+MBdgn18hP6F+VmhfdNmwK0lue3J/1HQ1UTMuQeQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/programs@8.2.0': + resolution: {integrity: sha512-yttl6ps7G9vM83pdfekyregTIqmRThFpdcrCIZ3y2qOLZ63KVxVMhNJ8kn8FrX3MyWh5rr/hTWdWKc4/U12Epg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/promises@6.10.0': + resolution: {integrity: sha512-oJSIn+VBBMWDo8oqw7RV3tI6Jih+Ieup6FcQLYLDUriaeo7+8l1Zdezl8zh7SIfeU4lOfAbRg6mR0huaS/Lltg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/promises@8.2.0': + resolution: {integrity: sha512-i33ll+en6/Qcjw10gPeikCmU687W1pQNZPxirEuRWO/+PhE2qDQ9ZODgEakVi/1k+vSwL8sK941qfWig+3D0dQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-api@6.10.0': + resolution: {integrity: sha512-RjPIVsAb/85P1ptoO3WpC0x7QG6gG/e4q/3lo6gbSznUZOcoM+8sSBnCX7BwP1ZkCDS6NK/ClXLnhhhYZx+OGg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-api@8.2.0': + resolution: {integrity: sha512-lGvk1xeOo4cbypuD/5AAkJPHv5E3g7lqbzRIxZhsQPBkK+knVuEb7e3UncOnjuWkijZoFiB/k+Rfk83gmlhdpg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-parsed-types@6.10.0': + resolution: {integrity: sha512-5275mvSV1mxhwvrMVa+K7BU/nAetpHfcb+8Ql9rtA8RRf6DyiimFQFZUukE4Ez6XJihEpCHNy98yhkgai9wytQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-parsed-types@8.2.0': + resolution: {integrity: sha512-JJ4BfUlX8eCIUh3zm8jTkHkNLf6HyY9UjJmi4GPicFPJZ5MXSUeh42eaSxvHszXUoS7u9V30kTt1hznwfF5fqA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-spec-types@6.10.0': + resolution: {integrity: sha512-NDZrKyZrJk4HaMFhTE/lAiMB824cWAodKqDHyKi0UteHU9pyRmil3BN1jt7e+j08mwMWwfklSgyrTaq52g6DIQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-spec-types@8.2.0': + resolution: {integrity: sha512-pKOezoP0vuVwyjUKcS4Ewl3Mm/owv/16n7RocqFC3nx94qtk5FpSOAtielUHzBQ3JUgRLJrSKonw2yWxqgtVFg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-spec@6.10.0': + resolution: {integrity: sha512-yQdbWw5mZEWrwsunHR9NHkuhMXIB9sPOObwm18D53v5tAJnxTB0IcHvO647XqFDLTK/yQ4AdDtlYD1vsY07AMQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-spec@8.2.0': + resolution: {integrity: sha512-fR0hv/NP3K4WNePK9+97GYrDjzoN7kF0hlffRlSygksAC0FKvtKQ5lPBMg0ptWtswInp8Kk7Cz1zTCf6S+wLUQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-subscriptions-api@6.10.0': + resolution: {integrity: sha512-CRPQoTtT1cOwOQUsqS7jgo7wYdAj7jB5ab/UmMPWVpecf2FNMhWhgvxP2s82M7VkDGTGl13qaQ0WySmi7Egrlg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-subscriptions-api@8.2.0': + resolution: {integrity: sha512-37UHtjFmBUagtRw9NeWViTqSJlExyuI2j88m3jJSw9c6WRw7lLzUJIRGA51ArYyhAyhtAoGjXpUZiODKSE9lEw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-subscriptions-channel-websocket@6.10.0': + resolution: {integrity: sha512-KkqP1186HELPlJftA88SNAT2znR8knCVzsUipXVzY4zfW8sN3LOa0ePMzh9VZ/V+J+raTt55laR87ovAO0n+zw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-subscriptions-channel-websocket@8.2.0': + resolution: {integrity: sha512-R9pk8Lq030M1+bAz6e2qKv6ldGLmICFYJOaLxVifyDE4VBb1BGV3Tt1VTAaFIfHyYucmFmxGRmPFmedA3Kysqw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-subscriptions-spec@6.10.0': + resolution: {integrity: sha512-nWMwGaG4ulzeX2sskY5TywXF3cwEd8FDmUpLe2JBWxE8XDAOGOKcsYPYFcBgb8ee9KqfPT2PTNdcz9jOhJf34w==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-subscriptions-spec@8.2.0': + resolution: {integrity: sha512-ajcncAnQ7XzE85MZ8uajjO9E7NyLwLWFVUYG+y82vb04ZWFRN3DrMswIC4T5m14OkU3RY/Z2WGxC9nT1W4wPWw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-subscriptions@6.10.0': + resolution: {integrity: sha512-6mfuHp/K7unFKCOTCCBC9ziEGnxe2tyJ74EbR51QUnBeCUdYD7Hhdpxic1WRSJ3UeNW/mG4OzFM6z8Wi64Eh9Q==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-subscriptions@8.2.0': + resolution: {integrity: sha512-pHf/RiDqIHeGp2blseYRVjzWz4WUAY/5vkOya+BQhjx+7Odr/J19G3ZVDwExgtU95UhCDL9gVHPyAgKr0mNcUg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-transformers@6.10.0': + resolution: {integrity: sha512-2nFUrVTiE720pJOY4XKx3HuYmishw0of/4oScu76YGm6O8wsmvFvPNAkrEinmieWXQkfpBfRvLZmpl8PaAy+ug==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-transformers@8.2.0': + resolution: {integrity: sha512-tiMdJ9ZRgqANBNxlXK7OSDbwixAy7K1MzowzO7vNdlJbV+0WN0Lm/X5hEhKnlU42AD+clC6t9qZjVbg7BhQrqw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-transport-http@6.10.0': + resolution: {integrity: sha512-JrdNuYi0nBbD3X8JUtgX1dQJwIwz/WJvmigDdELysXfGB2bTJpfjqGDLhCLOz2sRl66FASIEqgG/LVa2C9VXcA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-transport-http@8.2.0': + resolution: {integrity: sha512-eOkgv52ZSMFLYNQaCsvxmPciZeXplWaPjbEcl9iZkGOAp3B2bO6KyMg8trEjaZNfcLC15+CpXMOZpMArXXSBCg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-types@6.10.0': + resolution: {integrity: sha512-zaSecTfCPvz/vcoAmKD6XoRstGHTr1EKJBD8T9UcpEFFB6CtF6DxerDB+wrzkamuT6msmnR2DWXMrYOGDAsgIg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-types@8.2.0': + resolution: {integrity: sha512-rGF2vB8Bk0G2DYNxgEbDlANk+KirQGHVS1qRLxsi6OxACrgsSrGqrp0Onb5J8HLRMTEF+QrbbORDz9TQ5Q71fQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc@6.10.0': + resolution: {integrity: sha512-EwxsqoD+NXV+m+iobnWNtATD93gTgaNsOiQOzYB1/2e+8S6fl6obdNPB55yfXgtl4jt6GV6/ae4xuPhLv76vvg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc@8.2.0': + resolution: {integrity: sha512-Of/2KqDf728HxKzJlwlZRvRSrgpHoDAg5+t/3RwdXWBoRQ1r3FXqwBXOrBT2g47w+fUy1iJcy5XZ7LXnXBXPIg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/signers@6.10.0': + resolution: {integrity: sha512-+vtCc+mT1FpGxrA5oL2aaMxSHiMJ2hH5PcDIfjo2XJkHz2klZiCZyT5F9+zpltc9vdi1QTElQq59Sfplmtd33A==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/signers@8.2.0': + resolution: {integrity: sha512-wfLiDhtPMnE9Mn8IeSAJ0RMfCyHUqeNZllFLfgDY3RUsCf5s9EgMC5U+HNSvtEWJ8ABGWWR5nYyWMXTWiMeuPA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/subscribable@6.10.0': + resolution: {integrity: sha512-VsR6XMwkiDBkZJUcoGkEOhf397pOV75gKCL9Bx8bpi2T3Bbs0CxUpMn4yaUgAnRba3eXmjbXMNCXjttfa6sKbw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/subscribable@8.2.0': + resolution: {integrity: sha512-ATJBeJkaCUIxU3JWUcgfOjnOM3nn9qDfTigEkr0Cp3xFzIHnIVwis3W4Hcc/de1z0uvOXQOIYroahDr8H+djOg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/sysvars@6.10.0': + resolution: {integrity: sha512-cG13p1+onxz+20iWjwWQr1Z1jQwPm0fnjoW75fqZq7p4rVCie3L2sXvaJsYPjWKrUvpOzOIEHnqZGkG05rCpjg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/sysvars@8.2.0': + resolution: {integrity: sha512-kwhOwBfUvUGuGGGnwTGHtNVQ02O3YCfXpp4xwUhe6bjUyp9M9wEmf70up6I9x2D4uB1nHaZRfco1CXfxhcH8sg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/transaction-confirmation@6.10.0': + resolution: {integrity: sha512-ULvtg65qfenh4T/GYcIlKSUv5EqDcng9UN0dxbHU4kuZdR2e0B8HN2xDC4WhcFQVeFJSbTZmaYFkeTY/Y4gfGQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/transaction-confirmation@8.2.0': + resolution: {integrity: sha512-3L1LlMQ00l2kb3pcejvQ7vMKzyFayFhc6PqvZyh3M0/FNPfsc4z46yUf35I79SI6cuFWy2VkzA+a2ylOuCNC7w==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/transaction-introspection@8.2.0': + resolution: {integrity: sha512-unha6ugKrZa1TcB5Slnxisa/uQC56fyYi7BDvfCVI60OLEowtOTTvmJMKe35ETMzbimjBEPE/B5EgbydOHVBnQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/transaction-messages@6.10.0': + resolution: {integrity: sha512-s7v8G3BTxGlKYIj3eWCG0g1296v+1LBt16mVnlRH5FuyaJ5AdhlhtRho5HUDpdwE8EXun+y1c48V6uhcZ8wdbQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/transaction-messages@8.2.0': + resolution: {integrity: sha512-+0U4iR/WRb8UiBXRhJJUY0+BmAOv+bQj7fifUF6o7x/IPg/K2Y4CmH4m7dOT2yhcg0KDzZPkXidXLm6saBX0Hw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/transactions@6.10.0': + resolution: {integrity: sha512-VADSqP9OTYmhrox4pcgDd4+RjVmednXSE0+8Y7SPK4PN1pK5Az2RJ0nSsy0xcTnaOr8mF/crwFktqPrRQwSbQA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/transactions@8.2.0': + resolution: {integrity: sha512-WfbzFTf2BvpW14OIOin/9Mj29XE5GJVORAnziDK+GEiTPnruNzNkHBrd2kt/ACg12dh12kmutDj5WI3pzrN3Bw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@types/chai@5.2.3': + resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} + + '@types/deep-eql@4.0.2': + resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + + '@types/estree@1.0.9': + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} + + '@types/node@24.13.3': + resolution: {integrity: sha512-Dh8vAsV36ig5wa9OX4pXvMc9D3Veibfw2wix0CUwYODLD8nkj9UsLjASr49nPg+2eKzxhBV+v7L8pXvT4e639Q==} + + '@vitest/expect@3.2.7': + resolution: {integrity: sha512-E8eBXaKibuvH2pSZErOjdVb5vF4PbKYcrnluBTYxEk1l/VhhwZg1kZQsdtjq+CsF5CFydf2Rdkz7jDHKSisi3w==} + + '@vitest/mocker@3.2.7': + resolution: {integrity: sha512-Trr0hYO9CM3Wj6ksWHRhK9IZpIY6wTMO5u/MqXurMxT57sWBaOPEtP3Oq60ihZuh5JsiagKfz95OcxdEP6dBrA==} + peerDependencies: + msw: ^2.4.9 + vite: ^5.0.0 || ^6.0.0 || ^7.0.0-0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + '@vitest/pretty-format@3.2.7': + resolution: {integrity: sha512-KUHlwqVu0sRlhCdyPdQ/wBoTfRahjUky1MubOmYw9fWfIZy1gNoHpuaaQBPAaMaVYdQYHJLurzj8ECCj5OwTqA==} + + '@vitest/runner@3.2.7': + resolution: {integrity: sha512-sB9y4ovltoQP+WaUPwmSxO9WIg9Ig694Di5PalVPsYHklAdE027mehpWF2SQSVq+k6sFgaivbTjTJwZLSHbedA==} + + '@vitest/snapshot@3.2.7': + resolution: {integrity: sha512-7C+MwShwtBSI5Buwoyg3s/iY1eHL9PKAf+O1wVh/TdnjXUtkoL/9YQtre90i4MtNXM6edP1wJ2zOBpfCyhIS7g==} + + '@vitest/spy@3.2.7': + resolution: {integrity: sha512-Q2eQGI6d2L/hBtZ0qNuKcAGid68XK6cv1xsoaIma6PaJhHPoqcEJhYpXZ/5myCMqkNgtP6UKuBhbc0nHKnrkuQ==} + + '@vitest/utils@3.2.7': + resolution: {integrity: sha512-x6BDOd7dyo3PFLY3I9/HJ25X/6OurhGXk2/B9gOZNPF7XDVjeBK4k01lQE5uvDpbuheErh91qYuE1E2OEjK3Rw==} + + acorn@8.18.0: + resolution: {integrity: sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==} + engines: {node: '>=0.4.0'} + hasBin: true + + any-promise@1.3.0: + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + + bundle-require@5.1.0: + resolution: {integrity: sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + peerDependencies: + esbuild: '>=0.18' + + cac@6.7.14: + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} + engines: {node: '>=8'} + + chai@5.3.3: + resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==} + engines: {node: '>=18'} + + chalk@5.6.2: + resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + + check-error@2.1.3: + resolution: {integrity: sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==} + engines: {node: '>= 16'} + + chokidar@4.0.3: + resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} + engines: {node: '>= 14.16.0'} + + commander@15.0.0: + resolution: {integrity: sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==} + engines: {node: '>=22.12.0'} + + commander@4.1.1: + resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} + engines: {node: '>= 6'} + + confbox@0.1.8: + resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + + consola@3.4.2: + resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} + engines: {node: ^14.18.0 || >=16.10.0} + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + deep-eql@5.0.2: + resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} + engines: {node: '>=6'} + + es-module-lexer@1.7.0: + resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + + esbuild@0.27.7: + resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==} + engines: {node: '>=18'} + hasBin: true + + esbuild@0.28.2: + resolution: {integrity: sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==} + engines: {node: '>=18'} + hasBin: true + + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + + expect-type@1.4.0: + resolution: {integrity: sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==} + engines: {node: '>=12.0.0'} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + fix-dts-default-cjs-exports@1.0.1: + resolution: {integrity: sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg==} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + joycon@3.1.1: + resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} + engines: {node: '>=10'} + + js-tokens@9.0.1: + resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} + + lilconfig@3.1.3: + resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} + engines: {node: '>=14'} + + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + + litesvm-darwin-arm64@1.4.1: + resolution: {integrity: sha512-6dofWLOxtknSL0W6N9W3f/kdnitsJ3xR0oE1W37CLcfd5kX4qCMVbaejZWJkLo4G2JzAk+hFZi965Z2OPyJACg==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [darwin] + + litesvm-darwin-x64@1.4.1: + resolution: {integrity: sha512-Rjyg6SfnSKAO5/vMpnZpIHTcBWEUzjFj/GshXwzdyiWorrpC0poQjK3OJ9RJneJW2YDd+oUsGZCfwAplTXPGfg==} + engines: {node: '>= 20'} + cpu: [x64] + os: [darwin] + + litesvm-linux-arm64-gnu@1.4.1: + resolution: {integrity: sha512-hyL/tcuFisAwNEwVzDGjtDRuLYDc+8PoX9QZU/M46vsLrdU2WCBU3g4WdV5z0z1nPl16TzcHVboqydyBy3ImFQ==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + litesvm-linux-arm64-musl@1.4.1: + resolution: {integrity: sha512-Folc4nWAXwkWvwK5iqf3C74eNAPRERg8Yn2QGVW+6pMgCXtaQt77PuIB9m32mLo+W+LZxiU+t3et0ZiFEm4YgQ==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + libc: [musl] + + litesvm-linux-x64-gnu@1.4.1: + resolution: {integrity: sha512-sAKax22lAMS0DpWQcT6ICt8vs6phEjRJXT84LhhftnlNkcU03b0RJziFDr34LUTrkY5SMi/uqZEy0T86Xokg+w==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + libc: [glibc] + + litesvm-linux-x64-musl@1.4.1: + resolution: {integrity: sha512-kKsOVhF7o8/sMiP6mgZCoIYr7zWEzwOBQdC0WrWp29JvOJpKOOgz3jioFdgWv/LnSYfkbJ+wZNWI8tMhAkmNOw==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + libc: [musl] + + litesvm@1.4.1: + resolution: {integrity: sha512-SGMdN6c44m5Deo27nZX7GIn42e/OlfQ4jIv0JIVxR3F5vU8ZbbjsLRGUj3b/r5jCITyN22u14JnuP+mhDyNLlg==} + engines: {node: '>= 20'} + + load-tsconfig@0.2.5: + resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + loupe@3.2.1: + resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + mlly@1.8.2: + resolution: {integrity: sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + mz@2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + + nanoid@3.3.18: + resolution: {integrity: sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + + pathval@2.0.1: + resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==} + engines: {node: '>= 14.16'} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@4.0.7: + resolution: {integrity: sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==} + engines: {node: '>=12'} + + pirates@4.0.7: + resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} + engines: {node: '>= 6'} + + pkg-types@1.3.1: + resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} + + postcss-load-config@6.0.1: + resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==} + engines: {node: '>= 18'} + peerDependencies: + jiti: '>=1.21.0' + postcss: '>=8.0.9' + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + jiti: + optional: true + postcss: + optional: true + tsx: + optional: true + yaml: + optional: true + + postcss@8.5.26: + resolution: {integrity: sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==} + engines: {node: ^10 || ^12 || >=14} + + readdirp@4.1.2: + resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} + engines: {node: '>= 14.18.0'} + + resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + + rollup@4.63.1: + resolution: {integrity: sha512-3Df9jsstwhccuEfmAMi9l8XUh/GOkVObmFTU7CCVBysEbcOZLl84jCtaAZMcPiMz2EGKsATzQcU+Xr3n/wU6cg==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + source-map@0.7.6: + resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} + engines: {node: '>= 12'} + + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + + std-env@3.10.0: + resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + + strip-literal@3.1.0: + resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==} + + sucrase@3.35.1: + resolution: {integrity: sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + + thenify-all@1.6.0: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} + + thenify@3.3.1: + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + + tinyexec@0.3.2: + resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + + tinyglobby@0.2.17: + resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} + engines: {node: '>=12.0.0'} + + tinypool@1.1.1: + resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==} + engines: {node: ^18.0.0 || >=20.0.0} + + tinyrainbow@2.0.0: + resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==} + engines: {node: '>=14.0.0'} + + tinyspy@4.0.4: + resolution: {integrity: sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==} + engines: {node: '>=14.0.0'} + + tree-kill@1.2.2: + resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} + hasBin: true + + ts-interface-checker@0.1.13: + resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + + tsup@8.5.1: + resolution: {integrity: sha512-xtgkqwdhpKWr3tKPmCkvYmS9xnQK3m3XgxZHwSUjvfTjp7YfXe5tT3GgWi0F2N+ZSMsOeWeZFh7ZZFg5iPhing==} + engines: {node: '>=18'} + hasBin: true + peerDependencies: + '@microsoft/api-extractor': ^7.36.0 + '@swc/core': ^1 + postcss: ^8.4.12 + typescript: '>=4.5.0' + peerDependenciesMeta: + '@microsoft/api-extractor': + optional: true + '@swc/core': + optional: true + postcss: + optional: true + typescript: + optional: true + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + ufo@1.6.4: + resolution: {integrity: sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==} + + undici-types@7.18.2: + resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} + + undici-types@8.10.0: + resolution: {integrity: sha512-ibvdovq3nCFs8Msrd95BW+zUOq+aOVbT+wpHUoPWhztbHEoPc6oof51iFDB6Es8lTKvNvVW9jNSAB8dwrKTMGg==} + + vite-node@3.2.4: + resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + + vite@7.3.6: + resolution: {integrity: sha512-4XP60spRGjSZFf1qYH+dJIkK2znL3zQfl9KkOV9MkkRR/3Dls0dxaBsQPTloEc5BLXWPL9vsOxopxyKoMmDueg==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + jiti: '>=1.21.0' + less: ^4.0.0 + lightningcss: ^1.21.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vitest@3.2.7: + resolution: {integrity: sha512-KrxIJ62Fd89gfysR4WotlgZABiz2dqFPgqGzX7s+CwsqLFomRH7777ZcrOD6+WVAh7khPQP41A+BKbpcJFrdEg==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@types/debug': ^4.1.12 + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + '@vitest/browser': 3.2.7 + '@vitest/ui': 3.2.7 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@types/debug': + optional: true + '@types/node': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + + ws@8.21.3: + resolution: {integrity: sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + +snapshots: + + '@esbuild/aix-ppc64@0.27.7': + optional: true + + '@esbuild/aix-ppc64@0.28.2': + optional: true + + '@esbuild/android-arm64@0.27.7': + optional: true + + '@esbuild/android-arm64@0.28.2': + optional: true + + '@esbuild/android-arm@0.27.7': + optional: true + + '@esbuild/android-arm@0.28.2': + optional: true + + '@esbuild/android-x64@0.27.7': + optional: true + + '@esbuild/android-x64@0.28.2': + optional: true + + '@esbuild/darwin-arm64@0.27.7': + optional: true + + '@esbuild/darwin-arm64@0.28.2': + optional: true + + '@esbuild/darwin-x64@0.27.7': + optional: true + + '@esbuild/darwin-x64@0.28.2': + optional: true + + '@esbuild/freebsd-arm64@0.27.7': + optional: true + + '@esbuild/freebsd-arm64@0.28.2': + optional: true + + '@esbuild/freebsd-x64@0.27.7': + optional: true + + '@esbuild/freebsd-x64@0.28.2': + optional: true + + '@esbuild/linux-arm64@0.27.7': + optional: true + + '@esbuild/linux-arm64@0.28.2': + optional: true + + '@esbuild/linux-arm@0.27.7': + optional: true + + '@esbuild/linux-arm@0.28.2': + optional: true + + '@esbuild/linux-ia32@0.27.7': + optional: true + + '@esbuild/linux-ia32@0.28.2': + optional: true + + '@esbuild/linux-loong64@0.27.7': + optional: true + + '@esbuild/linux-loong64@0.28.2': + optional: true + + '@esbuild/linux-mips64el@0.27.7': + optional: true + + '@esbuild/linux-mips64el@0.28.2': + optional: true + + '@esbuild/linux-ppc64@0.27.7': + optional: true + + '@esbuild/linux-ppc64@0.28.2': + optional: true + + '@esbuild/linux-riscv64@0.27.7': + optional: true + + '@esbuild/linux-riscv64@0.28.2': + optional: true + + '@esbuild/linux-s390x@0.27.7': + optional: true + + '@esbuild/linux-s390x@0.28.2': + optional: true + + '@esbuild/linux-x64@0.27.7': + optional: true + + '@esbuild/linux-x64@0.28.2': + optional: true + + '@esbuild/netbsd-arm64@0.27.7': + optional: true + + '@esbuild/netbsd-arm64@0.28.2': + optional: true + + '@esbuild/netbsd-x64@0.27.7': + optional: true + + '@esbuild/netbsd-x64@0.28.2': + optional: true + + '@esbuild/openbsd-arm64@0.27.7': + optional: true + + '@esbuild/openbsd-arm64@0.28.2': + optional: true + + '@esbuild/openbsd-x64@0.27.7': + optional: true + + '@esbuild/openbsd-x64@0.28.2': + optional: true + + '@esbuild/openharmony-arm64@0.27.7': + optional: true + + '@esbuild/openharmony-arm64@0.28.2': + optional: true + + '@esbuild/sunos-x64@0.27.7': + optional: true + + '@esbuild/sunos-x64@0.28.2': + optional: true + + '@esbuild/win32-arm64@0.27.7': + optional: true + + '@esbuild/win32-arm64@0.28.2': + optional: true + + '@esbuild/win32-ia32@0.27.7': + optional: true + + '@esbuild/win32-ia32@0.28.2': + optional: true + + '@esbuild/win32-x64@0.27.7': + optional: true + + '@esbuild/win32-x64@0.28.2': + optional: true + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.6.0 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.6.0': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.6.0 + + '@napi-rs/lzma-linux-x64-gnu@1.5.1': + optional: true + + '@rollup/rollup-android-arm-eabi@4.63.1': + optional: true + + '@rollup/rollup-android-arm64@4.63.1': + optional: true + + '@rollup/rollup-darwin-arm64@4.63.1': + optional: true + + '@rollup/rollup-darwin-x64@4.63.1': + optional: true + + '@rollup/rollup-freebsd-arm64@4.63.1': + optional: true + + '@rollup/rollup-freebsd-x64@4.63.1': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.63.1': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.63.1': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.63.1': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.63.1': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.63.1': + optional: true + + '@rollup/rollup-linux-loong64-musl@4.63.1': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.63.1': + optional: true + + '@rollup/rollup-linux-ppc64-musl@4.63.1': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.63.1': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.63.1': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.63.1': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.63.1': + optional: true + + '@rollup/rollup-linux-x64-musl@4.63.1': + optional: true + + '@rollup/rollup-openbsd-x64@4.63.1': + optional: true + + '@rollup/rollup-openharmony-arm64@4.63.1': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.63.1': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.63.1': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.63.1': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.63.1': + optional: true + + '@solana-program/system@0.14.0(@solana/kit@8.2.0(typescript@5.9.3))': + dependencies: + '@solana/kit': 8.2.0(typescript@5.9.3) + + '@solana-program/token@0.16.0(@solana/kit@8.2.0(typescript@5.9.3))': + dependencies: + '@solana-program/system': 0.14.0(@solana/kit@8.2.0(typescript@5.9.3)) + '@solana/kit': 8.2.0(typescript@5.9.3) + + '@solana/accounts@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 6.10.0(typescript@5.9.3) + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/codecs-strings': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/rpc-spec': 6.10.0(typescript@5.9.3) + '@solana/rpc-types': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/accounts@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.2.0(typescript@5.9.3) + '@solana/codecs-core': 8.2.0(typescript@5.9.3) + '@solana/codecs-strings': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/rpc-spec': 8.2.0(typescript@5.9.3) + '@solana/rpc-types': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/addresses@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/assertions': 6.10.0(typescript@5.9.3) + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/codecs-strings': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/nominal-types': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/addresses@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/assertions': 8.2.0(typescript@5.9.3) + '@solana/codecs-core': 8.2.0(typescript@5.9.3) + '@solana/codecs-strings': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/nominal-types': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/assertions@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/assertions@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/codecs-core@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/codecs-core@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/codecs-data-structures@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/codecs-numbers': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/codecs-data-structures@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 8.2.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/codecs-numbers@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/codecs-numbers@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/codecs-strings@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/codecs-numbers': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/codecs-strings@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 8.2.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/codecs@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/codecs-data-structures': 6.10.0(typescript@5.9.3) + '@solana/codecs-numbers': 6.10.0(typescript@5.9.3) + '@solana/codecs-strings': 6.10.0(typescript@5.9.3) + '@solana/fixed-points': 6.10.0(typescript@5.9.3) + '@solana/options': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/codecs@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 8.2.0(typescript@5.9.3) + '@solana/codecs-data-structures': 8.2.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.2.0(typescript@5.9.3) + '@solana/codecs-strings': 8.2.0(typescript@5.9.3) + '@solana/fixed-points': 8.2.0(typescript@5.9.3) + '@solana/options': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/errors@6.10.0(typescript@5.9.3)': + dependencies: + chalk: 5.6.2 + commander: 15.0.0 + optionalDependencies: + typescript: 5.9.3 + + '@solana/errors@8.2.0(typescript@5.9.3)': + dependencies: + chalk: 5.6.2 + commander: 15.0.0 + optionalDependencies: + typescript: 5.9.3 + + '@solana/fast-stable-stringify@6.10.0(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + + '@solana/fast-stable-stringify@8.2.0(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + + '@solana/fixed-points@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/fixed-points@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/functional@6.10.0(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + + '@solana/functional@8.2.0(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + + '@solana/instruction-plans@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/instructions': 6.10.0(typescript@5.9.3) + '@solana/keys': 6.10.0(typescript@5.9.3) + '@solana/promises': 6.10.0(typescript@5.9.3) + '@solana/transaction-messages': 6.10.0(typescript@5.9.3) + '@solana/transactions': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/instruction-plans@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/instructions': 8.2.0(typescript@5.9.3) + '@solana/keys': 8.2.0(typescript@5.9.3) + '@solana/promises': 8.2.0(typescript@5.9.3) + '@solana/transaction-messages': 8.2.0(typescript@5.9.3) + '@solana/transactions': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/instructions@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/instructions@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/keys@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/assertions': 6.10.0(typescript@5.9.3) + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/codecs-strings': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/nominal-types': 6.10.0(typescript@5.9.3) + '@solana/promises': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/keys@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/assertions': 8.2.0(typescript@5.9.3) + '@solana/codecs-core': 8.2.0(typescript@5.9.3) + '@solana/codecs-strings': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/nominal-types': 8.2.0(typescript@5.9.3) + '@solana/promises': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/kit@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/accounts': 6.10.0(typescript@5.9.3) + '@solana/addresses': 6.10.0(typescript@5.9.3) + '@solana/codecs': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/functional': 6.10.0(typescript@5.9.3) + '@solana/instruction-plans': 6.10.0(typescript@5.9.3) + '@solana/instructions': 6.10.0(typescript@5.9.3) + '@solana/keys': 6.10.0(typescript@5.9.3) + '@solana/offchain-messages': 6.10.0(typescript@5.9.3) + '@solana/plugin-core': 6.10.0(typescript@5.9.3) + '@solana/plugin-interfaces': 6.10.0(typescript@5.9.3) + '@solana/program-client-core': 6.10.0(typescript@5.9.3) + '@solana/programs': 6.10.0(typescript@5.9.3) + '@solana/rpc': 6.10.0(typescript@5.9.3) + '@solana/rpc-api': 6.10.0(typescript@5.9.3) + '@solana/rpc-parsed-types': 6.10.0(typescript@5.9.3) + '@solana/rpc-spec-types': 6.10.0(typescript@5.9.3) + '@solana/rpc-subscriptions': 6.10.0(typescript@5.9.3) + '@solana/rpc-types': 6.10.0(typescript@5.9.3) + '@solana/signers': 6.10.0(typescript@5.9.3) + '@solana/subscribable': 6.10.0(typescript@5.9.3) + '@solana/sysvars': 6.10.0(typescript@5.9.3) + '@solana/transaction-confirmation': 6.10.0(typescript@5.9.3) + '@solana/transaction-messages': 6.10.0(typescript@5.9.3) + '@solana/transactions': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - bufferutil + - fastestsmallesttextencoderdecoder + - utf-8-validate + + '@solana/kit@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/accounts': 8.2.0(typescript@5.9.3) + '@solana/addresses': 8.2.0(typescript@5.9.3) + '@solana/codecs': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/functional': 8.2.0(typescript@5.9.3) + '@solana/instruction-plans': 8.2.0(typescript@5.9.3) + '@solana/instructions': 8.2.0(typescript@5.9.3) + '@solana/keys': 8.2.0(typescript@5.9.3) + '@solana/offchain-messages': 8.2.0(typescript@5.9.3) + '@solana/plugin-core': 8.2.0(typescript@5.9.3) + '@solana/plugin-interfaces': 8.2.0(typescript@5.9.3) + '@solana/program-client-core': 8.2.0(typescript@5.9.3) + '@solana/programs': 8.2.0(typescript@5.9.3) + '@solana/promises': 8.2.0(typescript@5.9.3) + '@solana/rpc': 8.2.0(typescript@5.9.3) + '@solana/rpc-api': 8.2.0(typescript@5.9.3) + '@solana/rpc-parsed-types': 8.2.0(typescript@5.9.3) + '@solana/rpc-spec-types': 8.2.0(typescript@5.9.3) + '@solana/rpc-subscriptions': 8.2.0(typescript@5.9.3) + '@solana/rpc-types': 8.2.0(typescript@5.9.3) + '@solana/signers': 8.2.0(typescript@5.9.3) + '@solana/subscribable': 8.2.0(typescript@5.9.3) + '@solana/sysvars': 8.2.0(typescript@5.9.3) + '@solana/transaction-confirmation': 8.2.0(typescript@5.9.3) + '@solana/transaction-introspection': 8.2.0(typescript@5.9.3) + '@solana/transaction-messages': 8.2.0(typescript@5.9.3) + '@solana/transactions': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - bufferutil + - fastestsmallesttextencoderdecoder + - utf-8-validate + + '@solana/nominal-types@6.10.0(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + + '@solana/nominal-types@8.2.0(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + + '@solana/offchain-messages@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 6.10.0(typescript@5.9.3) + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/codecs-data-structures': 6.10.0(typescript@5.9.3) + '@solana/codecs-numbers': 6.10.0(typescript@5.9.3) + '@solana/codecs-strings': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/keys': 6.10.0(typescript@5.9.3) + '@solana/nominal-types': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/offchain-messages@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.2.0(typescript@5.9.3) + '@solana/codecs-core': 8.2.0(typescript@5.9.3) + '@solana/codecs-data-structures': 8.2.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.2.0(typescript@5.9.3) + '@solana/codecs-strings': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/keys': 8.2.0(typescript@5.9.3) + '@solana/nominal-types': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/options@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/codecs-data-structures': 6.10.0(typescript@5.9.3) + '@solana/codecs-numbers': 6.10.0(typescript@5.9.3) + '@solana/codecs-strings': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/options@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 8.2.0(typescript@5.9.3) + '@solana/codecs-data-structures': 8.2.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.2.0(typescript@5.9.3) + '@solana/codecs-strings': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/plugin-core@6.10.0(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + + '@solana/plugin-core@8.2.0(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + + '@solana/plugin-interfaces@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 6.10.0(typescript@5.9.3) + '@solana/instruction-plans': 6.10.0(typescript@5.9.3) + '@solana/keys': 6.10.0(typescript@5.9.3) + '@solana/rpc-spec': 6.10.0(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 6.10.0(typescript@5.9.3) + '@solana/rpc-types': 6.10.0(typescript@5.9.3) + '@solana/signers': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/plugin-interfaces@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/accounts': 8.2.0(typescript@5.9.3) + '@solana/addresses': 8.2.0(typescript@5.9.3) + '@solana/instruction-plans': 8.2.0(typescript@5.9.3) + '@solana/keys': 8.2.0(typescript@5.9.3) + '@solana/rpc-spec': 8.2.0(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 8.2.0(typescript@5.9.3) + '@solana/rpc-types': 8.2.0(typescript@5.9.3) + '@solana/signers': 8.2.0(typescript@5.9.3) + '@solana/transactions': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/program-client-core@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/accounts': 6.10.0(typescript@5.9.3) + '@solana/addresses': 6.10.0(typescript@5.9.3) + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/instruction-plans': 6.10.0(typescript@5.9.3) + '@solana/instructions': 6.10.0(typescript@5.9.3) + '@solana/plugin-interfaces': 6.10.0(typescript@5.9.3) + '@solana/rpc-api': 6.10.0(typescript@5.9.3) + '@solana/signers': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/program-client-core@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/accounts': 8.2.0(typescript@5.9.3) + '@solana/addresses': 8.2.0(typescript@5.9.3) + '@solana/codecs-core': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/instruction-plans': 8.2.0(typescript@5.9.3) + '@solana/instructions': 8.2.0(typescript@5.9.3) + '@solana/plugin-interfaces': 8.2.0(typescript@5.9.3) + '@solana/rpc-api': 8.2.0(typescript@5.9.3) + '@solana/signers': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/programs@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/programs@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/promises@6.10.0(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + + '@solana/promises@8.2.0(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + + '@solana/rpc-api@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 6.10.0(typescript@5.9.3) + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/codecs-strings': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/keys': 6.10.0(typescript@5.9.3) + '@solana/rpc-parsed-types': 6.10.0(typescript@5.9.3) + '@solana/rpc-spec': 6.10.0(typescript@5.9.3) + '@solana/rpc-transformers': 6.10.0(typescript@5.9.3) + '@solana/rpc-types': 6.10.0(typescript@5.9.3) + '@solana/transaction-messages': 6.10.0(typescript@5.9.3) + '@solana/transactions': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/rpc-api@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.2.0(typescript@5.9.3) + '@solana/codecs-core': 8.2.0(typescript@5.9.3) + '@solana/codecs-strings': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/keys': 8.2.0(typescript@5.9.3) + '@solana/rpc-parsed-types': 8.2.0(typescript@5.9.3) + '@solana/rpc-spec': 8.2.0(typescript@5.9.3) + '@solana/rpc-transformers': 8.2.0(typescript@5.9.3) + '@solana/rpc-types': 8.2.0(typescript@5.9.3) + '@solana/transaction-messages': 8.2.0(typescript@5.9.3) + '@solana/transactions': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/rpc-parsed-types@6.10.0(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + + '@solana/rpc-parsed-types@8.2.0(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + + '@solana/rpc-spec-types@6.10.0(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + + '@solana/rpc-spec-types@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/rpc-spec@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/rpc-spec-types': 6.10.0(typescript@5.9.3) + '@solana/subscribable': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/rpc-spec@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/rpc-spec-types': 8.2.0(typescript@5.9.3) + '@solana/subscribable': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/rpc-subscriptions-api@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 6.10.0(typescript@5.9.3) + '@solana/keys': 6.10.0(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 6.10.0(typescript@5.9.3) + '@solana/rpc-transformers': 6.10.0(typescript@5.9.3) + '@solana/rpc-types': 6.10.0(typescript@5.9.3) + '@solana/transaction-messages': 6.10.0(typescript@5.9.3) + '@solana/transactions': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/rpc-subscriptions-api@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.2.0(typescript@5.9.3) + '@solana/keys': 8.2.0(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 8.2.0(typescript@5.9.3) + '@solana/rpc-transformers': 8.2.0(typescript@5.9.3) + '@solana/rpc-types': 8.2.0(typescript@5.9.3) + '@solana/transaction-messages': 8.2.0(typescript@5.9.3) + '@solana/transactions': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/rpc-subscriptions-channel-websocket@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/functional': 6.10.0(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 6.10.0(typescript@5.9.3) + '@solana/subscribable': 6.10.0(typescript@5.9.3) + ws: 8.21.3 + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@solana/rpc-subscriptions-channel-websocket@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/functional': 8.2.0(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 8.2.0(typescript@5.9.3) + '@solana/subscribable': 8.2.0(typescript@5.9.3) + ws: 8.21.3 + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@solana/rpc-subscriptions-spec@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/promises': 6.10.0(typescript@5.9.3) + '@solana/rpc-spec-types': 6.10.0(typescript@5.9.3) + '@solana/subscribable': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/rpc-subscriptions-spec@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/promises': 8.2.0(typescript@5.9.3) + '@solana/rpc-spec-types': 8.2.0(typescript@5.9.3) + '@solana/subscribable': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/rpc-subscriptions@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/fast-stable-stringify': 6.10.0(typescript@5.9.3) + '@solana/functional': 6.10.0(typescript@5.9.3) + '@solana/promises': 6.10.0(typescript@5.9.3) + '@solana/rpc-spec-types': 6.10.0(typescript@5.9.3) + '@solana/rpc-subscriptions-api': 6.10.0(typescript@5.9.3) + '@solana/rpc-subscriptions-channel-websocket': 6.10.0(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 6.10.0(typescript@5.9.3) + '@solana/rpc-transformers': 6.10.0(typescript@5.9.3) + '@solana/rpc-types': 6.10.0(typescript@5.9.3) + '@solana/subscribable': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - bufferutil + - fastestsmallesttextencoderdecoder + - utf-8-validate + + '@solana/rpc-subscriptions@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/fast-stable-stringify': 8.2.0(typescript@5.9.3) + '@solana/functional': 8.2.0(typescript@5.9.3) + '@solana/promises': 8.2.0(typescript@5.9.3) + '@solana/rpc-spec-types': 8.2.0(typescript@5.9.3) + '@solana/rpc-subscriptions-api': 8.2.0(typescript@5.9.3) + '@solana/rpc-subscriptions-channel-websocket': 8.2.0(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 8.2.0(typescript@5.9.3) + '@solana/rpc-transformers': 8.2.0(typescript@5.9.3) + '@solana/rpc-types': 8.2.0(typescript@5.9.3) + '@solana/subscribable': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - bufferutil + - fastestsmallesttextencoderdecoder + - utf-8-validate + + '@solana/rpc-transformers@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/functional': 6.10.0(typescript@5.9.3) + '@solana/nominal-types': 6.10.0(typescript@5.9.3) + '@solana/rpc-spec-types': 6.10.0(typescript@5.9.3) + '@solana/rpc-types': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/rpc-transformers@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/functional': 8.2.0(typescript@5.9.3) + '@solana/nominal-types': 8.2.0(typescript@5.9.3) + '@solana/rpc-spec-types': 8.2.0(typescript@5.9.3) + '@solana/rpc-types': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/rpc-transport-http@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/rpc-spec': 6.10.0(typescript@5.9.3) + '@solana/rpc-spec-types': 6.10.0(typescript@5.9.3) + undici-types: 8.10.0 + optionalDependencies: + typescript: 5.9.3 + + '@solana/rpc-transport-http@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/rpc-spec': 8.2.0(typescript@5.9.3) + '@solana/rpc-spec-types': 8.2.0(typescript@5.9.3) + undici-types: 8.10.0 + optionalDependencies: + typescript: 5.9.3 + + '@solana/rpc-types@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 6.10.0(typescript@5.9.3) + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/codecs-numbers': 6.10.0(typescript@5.9.3) + '@solana/codecs-strings': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/fixed-points': 6.10.0(typescript@5.9.3) + '@solana/nominal-types': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/rpc-types@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.2.0(typescript@5.9.3) + '@solana/codecs-core': 8.2.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.2.0(typescript@5.9.3) + '@solana/codecs-strings': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/fixed-points': 8.2.0(typescript@5.9.3) + '@solana/nominal-types': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/rpc@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/fast-stable-stringify': 6.10.0(typescript@5.9.3) + '@solana/functional': 6.10.0(typescript@5.9.3) + '@solana/rpc-api': 6.10.0(typescript@5.9.3) + '@solana/rpc-spec': 6.10.0(typescript@5.9.3) + '@solana/rpc-spec-types': 6.10.0(typescript@5.9.3) + '@solana/rpc-transformers': 6.10.0(typescript@5.9.3) + '@solana/rpc-transport-http': 6.10.0(typescript@5.9.3) + '@solana/rpc-types': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/rpc@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/fast-stable-stringify': 8.2.0(typescript@5.9.3) + '@solana/functional': 8.2.0(typescript@5.9.3) + '@solana/rpc-api': 8.2.0(typescript@5.9.3) + '@solana/rpc-spec': 8.2.0(typescript@5.9.3) + '@solana/rpc-spec-types': 8.2.0(typescript@5.9.3) + '@solana/rpc-transformers': 8.2.0(typescript@5.9.3) + '@solana/rpc-transport-http': 8.2.0(typescript@5.9.3) + '@solana/rpc-types': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/signers@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 6.10.0(typescript@5.9.3) + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/instructions': 6.10.0(typescript@5.9.3) + '@solana/keys': 6.10.0(typescript@5.9.3) + '@solana/nominal-types': 6.10.0(typescript@5.9.3) + '@solana/offchain-messages': 6.10.0(typescript@5.9.3) + '@solana/transaction-messages': 6.10.0(typescript@5.9.3) + '@solana/transactions': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/signers@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.2.0(typescript@5.9.3) + '@solana/codecs-core': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/instructions': 8.2.0(typescript@5.9.3) + '@solana/keys': 8.2.0(typescript@5.9.3) + '@solana/nominal-types': 8.2.0(typescript@5.9.3) + '@solana/offchain-messages': 8.2.0(typescript@5.9.3) + '@solana/transaction-messages': 8.2.0(typescript@5.9.3) + '@solana/transactions': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/subscribable@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/promises': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/subscribable@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/promises': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/sysvars@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/accounts': 6.10.0(typescript@5.9.3) + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/codecs-data-structures': 6.10.0(typescript@5.9.3) + '@solana/codecs-numbers': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/rpc-types': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/sysvars@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/accounts': 8.2.0(typescript@5.9.3) + '@solana/codecs-core': 8.2.0(typescript@5.9.3) + '@solana/codecs-data-structures': 8.2.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/rpc-types': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/transaction-confirmation@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 6.10.0(typescript@5.9.3) + '@solana/codecs-strings': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/keys': 6.10.0(typescript@5.9.3) + '@solana/promises': 6.10.0(typescript@5.9.3) + '@solana/rpc': 6.10.0(typescript@5.9.3) + '@solana/rpc-subscriptions': 6.10.0(typescript@5.9.3) + '@solana/rpc-types': 6.10.0(typescript@5.9.3) + '@solana/transaction-messages': 6.10.0(typescript@5.9.3) + '@solana/transactions': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - bufferutil + - fastestsmallesttextencoderdecoder + - utf-8-validate + + '@solana/transaction-confirmation@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.2.0(typescript@5.9.3) + '@solana/codecs-strings': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/keys': 8.2.0(typescript@5.9.3) + '@solana/promises': 8.2.0(typescript@5.9.3) + '@solana/rpc': 8.2.0(typescript@5.9.3) + '@solana/rpc-subscriptions': 8.2.0(typescript@5.9.3) + '@solana/rpc-types': 8.2.0(typescript@5.9.3) + '@solana/transaction-messages': 8.2.0(typescript@5.9.3) + '@solana/transactions': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - bufferutil + - fastestsmallesttextencoderdecoder + - utf-8-validate + + '@solana/transaction-introspection@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.2.0(typescript@5.9.3) + '@solana/codecs-core': 8.2.0(typescript@5.9.3) + '@solana/codecs-strings': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/instructions': 8.2.0(typescript@5.9.3) + '@solana/rpc-types': 8.2.0(typescript@5.9.3) + '@solana/transaction-messages': 8.2.0(typescript@5.9.3) + '@solana/transactions': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/transaction-messages@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 6.10.0(typescript@5.9.3) + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/codecs-data-structures': 6.10.0(typescript@5.9.3) + '@solana/codecs-numbers': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/functional': 6.10.0(typescript@5.9.3) + '@solana/instructions': 6.10.0(typescript@5.9.3) + '@solana/nominal-types': 6.10.0(typescript@5.9.3) + '@solana/rpc-types': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/transaction-messages@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.2.0(typescript@5.9.3) + '@solana/codecs-core': 8.2.0(typescript@5.9.3) + '@solana/codecs-data-structures': 8.2.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/functional': 8.2.0(typescript@5.9.3) + '@solana/instructions': 8.2.0(typescript@5.9.3) + '@solana/nominal-types': 8.2.0(typescript@5.9.3) + '@solana/rpc-types': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/transactions@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 6.10.0(typescript@5.9.3) + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/codecs-data-structures': 6.10.0(typescript@5.9.3) + '@solana/codecs-numbers': 6.10.0(typescript@5.9.3) + '@solana/codecs-strings': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/functional': 6.10.0(typescript@5.9.3) + '@solana/instructions': 6.10.0(typescript@5.9.3) + '@solana/keys': 6.10.0(typescript@5.9.3) + '@solana/nominal-types': 6.10.0(typescript@5.9.3) + '@solana/rpc-types': 6.10.0(typescript@5.9.3) + '@solana/transaction-messages': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/transactions@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.2.0(typescript@5.9.3) + '@solana/codecs-core': 8.2.0(typescript@5.9.3) + '@solana/codecs-data-structures': 8.2.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.2.0(typescript@5.9.3) + '@solana/codecs-strings': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/functional': 8.2.0(typescript@5.9.3) + '@solana/instructions': 8.2.0(typescript@5.9.3) + '@solana/keys': 8.2.0(typescript@5.9.3) + '@solana/nominal-types': 8.2.0(typescript@5.9.3) + '@solana/rpc-types': 8.2.0(typescript@5.9.3) + '@solana/transaction-messages': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@types/chai@5.2.3': + dependencies: + '@types/deep-eql': 4.0.2 + assertion-error: 2.0.1 + + '@types/deep-eql@4.0.2': {} + + '@types/estree@1.0.9': {} + + '@types/node@24.13.3': + dependencies: + undici-types: 7.18.2 + + '@vitest/expect@3.2.7': + dependencies: + '@types/chai': 5.2.3 + '@vitest/spy': 3.2.7 + '@vitest/utils': 3.2.7 + chai: 5.3.3 + tinyrainbow: 2.0.0 + + '@vitest/mocker@3.2.7(vite@7.3.6(@types/node@24.13.3))': + dependencies: + '@vitest/spy': 3.2.7 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 7.3.6(@types/node@24.13.3) + + '@vitest/pretty-format@3.2.7': + dependencies: + tinyrainbow: 2.0.0 + + '@vitest/runner@3.2.7': + dependencies: + '@vitest/utils': 3.2.7 + pathe: 2.0.3 + strip-literal: 3.1.0 + + '@vitest/snapshot@3.2.7': + dependencies: + '@vitest/pretty-format': 3.2.7 + magic-string: 0.30.21 + pathe: 2.0.3 + + '@vitest/spy@3.2.7': + dependencies: + tinyspy: 4.0.4 + + '@vitest/utils@3.2.7': + dependencies: + '@vitest/pretty-format': 3.2.7 + loupe: 3.2.1 + tinyrainbow: 2.0.0 + + acorn@8.18.0: {} + + any-promise@1.3.0: {} + + assertion-error@2.0.1: {} + + bundle-require@5.1.0(esbuild@0.27.7): + dependencies: + esbuild: 0.27.7 + load-tsconfig: 0.2.5 + + cac@6.7.14: {} + + chai@5.3.3: + dependencies: + assertion-error: 2.0.1 + check-error: 2.1.3 + deep-eql: 5.0.2 + loupe: 3.2.1 + pathval: 2.0.1 + + chalk@5.6.2: {} + + check-error@2.1.3: {} + + chokidar@4.0.3: + dependencies: + readdirp: 4.1.2 + + commander@15.0.0: {} + + commander@4.1.1: {} + + confbox@0.1.8: {} + + consola@3.4.2: {} + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + deep-eql@5.0.2: {} + + es-module-lexer@1.7.0: {} + + esbuild@0.27.7: + optionalDependencies: + '@esbuild/aix-ppc64': 0.27.7 + '@esbuild/android-arm': 0.27.7 + '@esbuild/android-arm64': 0.27.7 + '@esbuild/android-x64': 0.27.7 + '@esbuild/darwin-arm64': 0.27.7 + '@esbuild/darwin-x64': 0.27.7 + '@esbuild/freebsd-arm64': 0.27.7 + '@esbuild/freebsd-x64': 0.27.7 + '@esbuild/linux-arm': 0.27.7 + '@esbuild/linux-arm64': 0.27.7 + '@esbuild/linux-ia32': 0.27.7 + '@esbuild/linux-loong64': 0.27.7 + '@esbuild/linux-mips64el': 0.27.7 + '@esbuild/linux-ppc64': 0.27.7 + '@esbuild/linux-riscv64': 0.27.7 + '@esbuild/linux-s390x': 0.27.7 + '@esbuild/linux-x64': 0.27.7 + '@esbuild/netbsd-arm64': 0.27.7 + '@esbuild/netbsd-x64': 0.27.7 + '@esbuild/openbsd-arm64': 0.27.7 + '@esbuild/openbsd-x64': 0.27.7 + '@esbuild/openharmony-arm64': 0.27.7 + '@esbuild/sunos-x64': 0.27.7 + '@esbuild/win32-arm64': 0.27.7 + '@esbuild/win32-ia32': 0.27.7 + '@esbuild/win32-x64': 0.27.7 + + esbuild@0.28.2: + optionalDependencies: + '@esbuild/aix-ppc64': 0.28.2 + '@esbuild/android-arm': 0.28.2 + '@esbuild/android-arm64': 0.28.2 + '@esbuild/android-x64': 0.28.2 + '@esbuild/darwin-arm64': 0.28.2 + '@esbuild/darwin-x64': 0.28.2 + '@esbuild/freebsd-arm64': 0.28.2 + '@esbuild/freebsd-x64': 0.28.2 + '@esbuild/linux-arm': 0.28.2 + '@esbuild/linux-arm64': 0.28.2 + '@esbuild/linux-ia32': 0.28.2 + '@esbuild/linux-loong64': 0.28.2 + '@esbuild/linux-mips64el': 0.28.2 + '@esbuild/linux-ppc64': 0.28.2 + '@esbuild/linux-riscv64': 0.28.2 + '@esbuild/linux-s390x': 0.28.2 + '@esbuild/linux-x64': 0.28.2 + '@esbuild/netbsd-arm64': 0.28.2 + '@esbuild/netbsd-x64': 0.28.2 + '@esbuild/openbsd-arm64': 0.28.2 + '@esbuild/openbsd-x64': 0.28.2 + '@esbuild/openharmony-arm64': 0.28.2 + '@esbuild/sunos-x64': 0.28.2 + '@esbuild/win32-arm64': 0.28.2 + '@esbuild/win32-ia32': 0.28.2 + '@esbuild/win32-x64': 0.28.2 + + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.9 + + expect-type@1.4.0: {} + + fdir@6.5.0(picomatch@4.0.7): + optionalDependencies: + picomatch: 4.0.7 + + fix-dts-default-cjs-exports@1.0.1: + dependencies: + magic-string: 0.30.21 + mlly: 1.8.2 + rollup: 4.63.1 + + fsevents@2.3.3: + optional: true + + joycon@3.1.1: {} + + js-tokens@9.0.1: {} + + lilconfig@3.1.3: {} + + lines-and-columns@1.2.4: {} + + litesvm-darwin-arm64@1.4.1: + optional: true + + litesvm-darwin-x64@1.4.1: + optional: true + + litesvm-linux-arm64-gnu@1.4.1: + optional: true + + litesvm-linux-arm64-musl@1.4.1: + optional: true + + litesvm-linux-x64-gnu@1.4.1: + optional: true + + litesvm-linux-x64-musl@1.4.1: + optional: true + + litesvm@1.4.1(typescript@5.9.3): + dependencies: + '@solana-program/system': 0.14.0(@solana/kit@8.2.0(typescript@5.9.3)) + '@solana-program/token': 0.16.0(@solana/kit@8.2.0(typescript@5.9.3)) + '@solana/kit': 8.2.0(typescript@5.9.3) + optionalDependencies: + litesvm-darwin-arm64: 1.4.1 + litesvm-darwin-x64: 1.4.1 + litesvm-linux-arm64-gnu: 1.4.1 + litesvm-linux-arm64-musl: 1.4.1 + litesvm-linux-x64-gnu: 1.4.1 + litesvm-linux-x64-musl: 1.4.1 + transitivePeerDependencies: + - bufferutil + - fastestsmallesttextencoderdecoder + - typescript + - utf-8-validate + + load-tsconfig@0.2.5: {} + + loupe@3.2.1: {} + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.6.0 + + mlly@1.8.2: + dependencies: + acorn: 8.18.0 + pathe: 2.0.3 + pkg-types: 1.3.1 + ufo: 1.6.4 + + ms@2.1.3: {} + + mz@2.7.0: + dependencies: + any-promise: 1.3.0 + object-assign: 4.1.1 + thenify-all: 1.6.0 + + nanoid@3.3.18: {} + + object-assign@4.1.1: {} + + pathe@2.0.3: {} + + pathval@2.0.1: {} + + picocolors@1.1.1: {} + + picomatch@4.0.7: {} + + pirates@4.0.7: {} + + pkg-types@1.3.1: + dependencies: + confbox: 0.1.8 + mlly: 1.8.2 + pathe: 2.0.3 + + postcss-load-config@6.0.1(postcss@8.5.26): + dependencies: + lilconfig: 3.1.3 + optionalDependencies: + postcss: 8.5.26 + + postcss@8.5.26: + dependencies: + nanoid: 3.3.18 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + readdirp@4.1.2: {} + + resolve-from@5.0.0: {} + + rollup@4.63.1: + dependencies: + '@types/estree': 1.0.9 + optionalDependencies: + '@napi-rs/lzma-linux-x64-gnu': 1.5.1 + '@rollup/rollup-android-arm-eabi': 4.63.1 + '@rollup/rollup-android-arm64': 4.63.1 + '@rollup/rollup-darwin-arm64': 4.63.1 + '@rollup/rollup-darwin-x64': 4.63.1 + '@rollup/rollup-freebsd-arm64': 4.63.1 + '@rollup/rollup-freebsd-x64': 4.63.1 + '@rollup/rollup-linux-arm-gnueabihf': 4.63.1 + '@rollup/rollup-linux-arm-musleabihf': 4.63.1 + '@rollup/rollup-linux-arm64-gnu': 4.63.1 + '@rollup/rollup-linux-arm64-musl': 4.63.1 + '@rollup/rollup-linux-loong64-gnu': 4.63.1 + '@rollup/rollup-linux-loong64-musl': 4.63.1 + '@rollup/rollup-linux-ppc64-gnu': 4.63.1 + '@rollup/rollup-linux-ppc64-musl': 4.63.1 + '@rollup/rollup-linux-riscv64-gnu': 4.63.1 + '@rollup/rollup-linux-riscv64-musl': 4.63.1 + '@rollup/rollup-linux-s390x-gnu': 4.63.1 + '@rollup/rollup-linux-x64-gnu': 4.63.1 + '@rollup/rollup-linux-x64-musl': 4.63.1 + '@rollup/rollup-openbsd-x64': 4.63.1 + '@rollup/rollup-openharmony-arm64': 4.63.1 + '@rollup/rollup-win32-arm64-msvc': 4.63.1 + '@rollup/rollup-win32-ia32-msvc': 4.63.1 + '@rollup/rollup-win32-x64-gnu': 4.63.1 + '@rollup/rollup-win32-x64-msvc': 4.63.1 + fsevents: 2.3.3 + + siginfo@2.0.0: {} + + source-map-js@1.2.1: {} + + source-map@0.7.6: {} + + stackback@0.0.2: {} + + std-env@3.10.0: {} + + strip-literal@3.1.0: + dependencies: + js-tokens: 9.0.1 + + sucrase@3.35.1: + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + commander: 4.1.1 + lines-and-columns: 1.2.4 + mz: 2.7.0 + pirates: 4.0.7 + tinyglobby: 0.2.17 + ts-interface-checker: 0.1.13 + + thenify-all@1.6.0: + dependencies: + thenify: 3.3.1 + + thenify@3.3.1: + dependencies: + any-promise: 1.3.0 + + tinybench@2.9.0: {} + + tinyexec@0.3.2: {} + + tinyglobby@0.2.17: + dependencies: + fdir: 6.5.0(picomatch@4.0.7) + picomatch: 4.0.7 + + tinypool@1.1.1: {} + + tinyrainbow@2.0.0: {} + + tinyspy@4.0.4: {} + + tree-kill@1.2.2: {} + + ts-interface-checker@0.1.13: {} + + tsup@8.5.1(postcss@8.5.26)(typescript@5.9.3): + dependencies: + bundle-require: 5.1.0(esbuild@0.27.7) + cac: 6.7.14 + chokidar: 4.0.3 + consola: 3.4.2 + debug: 4.4.3 + esbuild: 0.27.7 + fix-dts-default-cjs-exports: 1.0.1 + joycon: 3.1.1 + picocolors: 1.1.1 + postcss-load-config: 6.0.1(postcss@8.5.26) + resolve-from: 5.0.0 + rollup: 4.63.1 + source-map: 0.7.6 + sucrase: 3.35.1 + tinyexec: 0.3.2 + tinyglobby: 0.2.17 + tree-kill: 1.2.2 + optionalDependencies: + postcss: 8.5.26 + typescript: 5.9.3 + transitivePeerDependencies: + - jiti + - supports-color + - tsx + - yaml + + typescript@5.9.3: {} + + ufo@1.6.4: {} + + undici-types@7.18.2: {} + + undici-types@8.10.0: {} + + vite-node@3.2.4(@types/node@24.13.3): + dependencies: + cac: 6.7.14 + debug: 4.4.3 + es-module-lexer: 1.7.0 + pathe: 2.0.3 + vite: 7.3.6(@types/node@24.13.3) + transitivePeerDependencies: + - '@types/node' + - jiti + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml + + vite@7.3.6(@types/node@24.13.3): + dependencies: + esbuild: 0.28.2 + fdir: 6.5.0(picomatch@4.0.7) + picomatch: 4.0.7 + postcss: 8.5.26 + rollup: 4.63.1 + tinyglobby: 0.2.17 + optionalDependencies: + '@types/node': 24.13.3 + fsevents: 2.3.3 + + vitest@3.2.7(@types/node@24.13.3): + dependencies: + '@types/chai': 5.2.3 + '@vitest/expect': 3.2.7 + '@vitest/mocker': 3.2.7(vite@7.3.6(@types/node@24.13.3)) + '@vitest/pretty-format': 3.2.7 + '@vitest/runner': 3.2.7 + '@vitest/snapshot': 3.2.7 + '@vitest/spy': 3.2.7 + '@vitest/utils': 3.2.7 + chai: 5.3.3 + debug: 4.4.3 + expect-type: 1.4.0 + magic-string: 0.30.21 + pathe: 2.0.3 + picomatch: 4.0.7 + std-env: 3.10.0 + tinybench: 2.9.0 + tinyexec: 0.3.2 + tinyglobby: 0.2.17 + tinypool: 1.1.1 + tinyrainbow: 2.0.0 + vite: 7.3.6(@types/node@24.13.3) + vite-node: 3.2.4(@types/node@24.13.3) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 24.13.3 + transitivePeerDependencies: + - jiti + - less + - lightningcss + - msw + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml + + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + + ws@8.21.3: {} diff --git a/programs/settlement/idl/client/js/tsconfig.build.json b/programs/settlement/idl/client/js/tsconfig.build.json new file mode 100644 index 0000000..4643414 --- /dev/null +++ b/programs/settlement/idl/client/js/tsconfig.build.json @@ -0,0 +1,7 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "module": "ESNext", + "moduleResolution": "bundler" + } +} diff --git a/programs/settlement/idl/pnpm-lock.yaml b/programs/settlement/idl/pnpm-lock.yaml new file mode 100644 index 0000000..67ad834 --- /dev/null +++ b/programs/settlement/idl/pnpm-lock.yaml @@ -0,0 +1,505 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@codama/nodes-from-anchor': + specifier: ^1.5.2 + version: 1.5.5 + '@codama/renderers-js': + specifier: ^2.3.0 + version: 2.4.0 + codama: + specifier: ^1.9.0 + version: 1.10.2 + +packages: + + '@codama/cli@1.6.2': + resolution: {integrity: sha512-UFrWJxtELsPHOoG8soVuUqv/nSSUebLccaN3WQ43+5J7pFBetscEUsoy20lzV2gxYEfvYf6JqyuIUXGDmtnj9g==} + hasBin: true + + '@codama/errors@1.10.2': + resolution: {integrity: sha512-relp9Inq9QkhZ0JUklKujSFWLkVfQSsn2/ms303vsGVWlFBXQmoEsmZCVKgJ7k5APNBbsD8Hc9GGU4J+P05SLA==} + hasBin: true + + '@codama/fragments@0.1.5': + resolution: {integrity: sha512-aisr+cdayABykLhysE1pcDWMJJZNAAWyi5NEzkMLpyTmQrhIK6Mca14gSJIw3a0uo3E5s5Zc4d6gsxRjfYpLuw==} + + '@codama/node-types@1.10.2': + resolution: {integrity: sha512-qFHqpuCmAoJy9ggkLadtug2Nlmnai6LrEmr+sfsK6dEJVOFGMNBR4dxwheziOu/Sn9oWGfnFfKbzQIdWE0qHHg==} + + '@codama/nodes-from-anchor@1.5.5': + resolution: {integrity: sha512-+HQUKzQpSh8EHm+fwxXVTvhPI46yTm1HzLvRJK1mkTJ1w4bymknhyWsLn1NRVDcAIixPZLsvLKujJTn+8IcoZg==} + + '@codama/nodes@1.10.2': + resolution: {integrity: sha512-wR2LKg6/GQ+ctgOiH9XPVb7ktq+gu7X/WEiCk45d4L1+P/JJh2kJeS/sMbktrgJNimcoO2G1Ms3+eUDjrwfo5g==} + + '@codama/renderers-core@1.4.0': + resolution: {integrity: sha512-JkqKWaN5nKampHgJ3jWh7u6kNPrwp7DB/lpkyS1hpL6NiC45tZGie6foaq8TnSTpaVPtVsL8Q46AP1MZpongpg==} + + '@codama/renderers-js@2.4.0': + resolution: {integrity: sha512-nLmLy8eSaBtnff5OE85SXvdL4rN4QSkCSZfZ4856zwnPndP/UzV/RBNoZOp1+muMj1VIKMZ1gXLzKQjDeYM3EA==} + engines: {node: '>=20.18.0'} + + '@codama/validators@1.10.2': + resolution: {integrity: sha512-Ppf8qcbBMclncrTLZU/bxi2Y5Gf9cTg1SybHTIDankOholgRWzf8wdZ40Vc/BaphY223pHOUBXiEmwZ6eTRX7A==} + + '@codama/visitors-core@1.10.2': + resolution: {integrity: sha512-hxoISIWUUiu9Ma97OxsXl3Db5qvYmqUm9JVCf6MCb/+uE5nd4U/jZuTIKQFLulitiGRWhQr8IJI16YgO79Nuyw==} + + '@codama/visitors@1.10.2': + resolution: {integrity: sha512-DUkpq9TEuevg4mEOW9fyBJiYHGzj6ByNtgVAyLRWcUEz6Mz3Qn8+lRDpqqVyuzRbAdurf9bWsO8ln+zswPP4hg==} + + '@noble/hashes@2.4.0': + resolution: {integrity: sha512-X5XaVWZIBCT7HHZGm5I7ZQXDwLG+bGXuSrMQAW+7Zvl87h1kmc1ZB1VSRJcpUfoUrGQp4Fkoxm5kZ+Ms+aW+eA==} + engines: {node: '>= 20.19.0'} + + '@solana/codecs-core@7.1.1': + resolution: {integrity: sha512-C1UOAQ7LH8RuCTfaij6hthTZeBlpp8GuD2g9Nag/xgiNKJGvAfVrcorb+kO/sufdYI8Lu+BiVvPeKOjQDQiKqg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/codecs-data-structures@7.1.1': + resolution: {integrity: sha512-MO+wMAuaatAQ96N3HhTsd7Uno+79rJw88P+OiU2n+pHK/rZuyu1yB2j12veqK4jUNWPR0aOyCuZ4rB2idrDjpg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/codecs-numbers@7.1.1': + resolution: {integrity: sha512-TWWrQq6Wp5Yf5bSc6RbxDDYCRUBBmRtRgjvUMHGp0P9K+4uFwxllRjSZFzBPHgXj3UTeZmFJdcoD271QhAgibg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/codecs-strings@7.1.1': + resolution: {integrity: sha512-6qWl+atG60D2LmP47GyGapQFhVsG1sVhVrEaM3lV09vwrGOMeOZARZ4ObaQ5m6uQmM04G+f8dY9d17nCMbGHGg==} + engines: {node: '>=20.18.0'} + peerDependencies: + fastestsmallesttextencoderdecoder: ^1.0.22 + typescript: '>=5.4.0' + peerDependenciesMeta: + fastestsmallesttextencoderdecoder: + optional: true + typescript: + optional: true + + '@solana/codecs@7.1.1': + resolution: {integrity: sha512-1ZErMXzbbz7+jusem58dMO1haVWNlvFYKftc2dPhFu9MqlmZRfPS06GiZDjlLnD/6PHHBy7OKFMASoYw+fBAKg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/errors@7.1.1': + resolution: {integrity: sha512-q35qck8rBnNvJlPU00mnHEQm7gWvghzYz8khqVoLhjgodTzGp46VqnIOyI1LXOAF6XDal58bMNDO980MQgq8yw==} + engines: {node: '>=20.18.0'} + hasBin: true + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/fixed-points@7.1.1': + resolution: {integrity: sha512-qPj/V7kcFG/P0kuEa1U529+5L6mbkMwRIwvYBTDgBqPOt6wOdk9/c7Qn2VUQgSV0HgCXWxdHUdwaxBrYqO2ibg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/options@7.1.1': + resolution: {integrity: sha512-iuPpfMbnRFjC4IoAIpKNA9UpizomxjW0E3F1LxUYQHXm1vCoF78kThp4qqgx2V3DmDFbhXGtXGSJPwmDdpLoBg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + call-bind@1.0.9: + resolution: {integrity: sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==} + engines: {node: '>= 0.4'} + + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + + chalk@5.6.2: + resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + + codama@1.10.2: + resolution: {integrity: sha512-fm6bFmgTrd6wPJ8o758wVVCYSEmEOU7Ctvlm8TxZoyPG0DlRS94AqnG3yC0HODXfGMAbai6pCxe9D04n3yl5AQ==} + hasBin: true + + commander@15.0.0: + resolution: {integrity: sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==} + engines: {node: '>=22.12.0'} + + define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-object-atoms@1.1.2: + resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==} + engines: {node: '>= 0.4'} + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + hasown@2.0.4: + resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} + engines: {node: '>= 0.4'} + + isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + + json-stable-stringify@1.3.0: + resolution: {integrity: sha512-qtYiSSFlwot9XHtF9bD9c7rwKjr+RecWT//ZnPvSmEjpV5mmPOCN4j8UjY5hbjNkOwZ/jQv3J6R1/pL7RwgMsg==} + engines: {node: '>= 0.4'} + + jsonify@0.0.1: + resolution: {integrity: sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==} + + kleur@3.0.3: + resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} + engines: {node: '>=6'} + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + prettier@3.9.6: + resolution: {integrity: sha512-OpN0zzVdiaiAhxpuuj5efpIS4sY9j7bY6uR5mnj5yPzGkdkjNKSJeUThPb60Jw29QuAZgA4o+/iB49kFiaBX6g==} + engines: {node: '>=14'} + hasBin: true + + prompts@2.4.2: + resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} + engines: {node: '>= 6'} + + semver@7.8.5: + resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} + engines: {node: '>=10'} + hasBin: true + + set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + + sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + +snapshots: + + '@codama/cli@1.6.2': + dependencies: + '@codama/nodes': 1.10.2 + '@codama/visitors': 1.10.2 + '@codama/visitors-core': 1.10.2 + commander: 15.0.0 + picocolors: 1.1.1 + prompts: 2.4.2 + + '@codama/errors@1.10.2': + dependencies: + '@codama/node-types': 1.10.2 + commander: 15.0.0 + picocolors: 1.1.1 + + '@codama/fragments@0.1.5': + dependencies: + '@codama/errors': 1.10.2 + + '@codama/node-types@1.10.2': {} + + '@codama/nodes-from-anchor@1.5.5': + dependencies: + '@codama/errors': 1.10.2 + '@codama/nodes': 1.10.2 + '@codama/visitors': 1.10.2 + '@noble/hashes': 2.4.0 + '@solana/codecs': 7.1.1 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + - typescript + + '@codama/nodes@1.10.2': + dependencies: + '@codama/errors': 1.10.2 + '@codama/node-types': 1.10.2 + + '@codama/renderers-core@1.4.0': + dependencies: + '@codama/errors': 1.10.2 + '@codama/fragments': 0.1.5 + '@codama/nodes': 1.10.2 + '@codama/visitors-core': 1.10.2 + + '@codama/renderers-js@2.4.0': + dependencies: + '@codama/errors': 1.10.2 + '@codama/nodes': 1.10.2 + '@codama/renderers-core': 1.4.0 + '@codama/visitors-core': 1.10.2 + '@solana/codecs-strings': 7.1.1 + prettier: 3.9.6 + semver: 7.8.5 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + - typescript + + '@codama/validators@1.10.2': + dependencies: + '@codama/errors': 1.10.2 + '@codama/nodes': 1.10.2 + '@codama/visitors-core': 1.10.2 + + '@codama/visitors-core@1.10.2': + dependencies: + '@codama/errors': 1.10.2 + '@codama/nodes': 1.10.2 + json-stable-stringify: 1.3.0 + + '@codama/visitors@1.10.2': + dependencies: + '@codama/errors': 1.10.2 + '@codama/nodes': 1.10.2 + '@codama/visitors-core': 1.10.2 + + '@noble/hashes@2.4.0': {} + + '@solana/codecs-core@7.1.1': + dependencies: + '@solana/errors': 7.1.1 + + '@solana/codecs-data-structures@7.1.1': + dependencies: + '@solana/codecs-core': 7.1.1 + '@solana/codecs-numbers': 7.1.1 + '@solana/errors': 7.1.1 + + '@solana/codecs-numbers@7.1.1': + dependencies: + '@solana/codecs-core': 7.1.1 + '@solana/errors': 7.1.1 + + '@solana/codecs-strings@7.1.1': + dependencies: + '@solana/codecs-core': 7.1.1 + '@solana/codecs-numbers': 7.1.1 + '@solana/errors': 7.1.1 + + '@solana/codecs@7.1.1': + dependencies: + '@solana/codecs-core': 7.1.1 + '@solana/codecs-data-structures': 7.1.1 + '@solana/codecs-numbers': 7.1.1 + '@solana/codecs-strings': 7.1.1 + '@solana/fixed-points': 7.1.1 + '@solana/options': 7.1.1 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/errors@7.1.1': + dependencies: + chalk: 5.6.2 + commander: 15.0.0 + + '@solana/fixed-points@7.1.1': + dependencies: + '@solana/codecs-core': 7.1.1 + '@solana/errors': 7.1.1 + + '@solana/options@7.1.1': + dependencies: + '@solana/codecs-core': 7.1.1 + '@solana/codecs-data-structures': 7.1.1 + '@solana/codecs-numbers': 7.1.1 + '@solana/codecs-strings': 7.1.1 + '@solana/errors': 7.1.1 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bind@1.0.9: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + get-intrinsic: 1.3.0 + set-function-length: 1.2.2 + + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + + chalk@5.6.2: {} + + codama@1.10.2: + dependencies: + '@codama/cli': 1.6.2 + '@codama/errors': 1.10.2 + '@codama/nodes': 1.10.2 + '@codama/validators': 1.10.2 + '@codama/visitors': 1.10.2 + + commander@15.0.0: {} + + define-data-property@1.1.4: + dependencies: + es-define-property: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-object-atoms@1.1.2: + dependencies: + es-errors: 1.3.0 + + function-bind@1.1.2: {} + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.4 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.2 + + gopd@1.2.0: {} + + has-property-descriptors@1.0.2: + dependencies: + es-define-property: 1.0.1 + + has-symbols@1.1.0: {} + + hasown@2.0.4: + dependencies: + function-bind: 1.1.2 + + isarray@2.0.5: {} + + json-stable-stringify@1.3.0: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + isarray: 2.0.5 + jsonify: 0.0.1 + object-keys: 1.1.1 + + jsonify@0.0.1: {} + + kleur@3.0.3: {} + + math-intrinsics@1.1.0: {} + + object-keys@1.1.1: {} + + picocolors@1.1.1: {} + + prettier@3.9.6: {} + + prompts@2.4.2: + dependencies: + kleur: 3.0.3 + sisteransi: 1.0.5 + + semver@7.8.5: {} + + set-function-length@1.2.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.3.0 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + + sisteransi@1.0.5: {} From 0d79022b29b4121ed92072c806411184ea2ab962 Mon Sep 17 00:00:00 2001 From: Denis Makarov Date: Tue, 1 Sep 2026 16:20:00 +0400 Subject: [PATCH 29/43] feat: prevent token leak + rename the package --- .github/workflows/publish-npm.yml | 20 ++++++++++++++----- README.md | 2 +- .../settlement/idl/client/js/package.json | 2 +- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/.github/workflows/publish-npm.yml b/.github/workflows/publish-npm.yml index 28e1bbe..a99cac0 100644 --- a/.github/workflows/publish-npm.yml +++ b/.github/workflows/publish-npm.yml @@ -69,15 +69,22 @@ jobs: echo "2. The dependency diff below has no unexpected new/changed packages." echo "3. Package \`${{ steps.pkg.outputs.name }}\` is being published at version \`${{ steps.pkg.outputs.version }}\`, matching release \`${{ github.event.release.tag_name || github.ref_name }}\`." echo - echo "### Tarball contents (\`npm pack --dry-run\`)" + echo "### Tarball contents (\`npm pack --dry-run --ignore-scripts\`)" echo '```' - npm pack --dry-run 2>&1 + npm pack --dry-run --ignore-scripts 2>&1 echo '```' echo echo "### Dependency diff vs. previously published version" name="${{ steps.pkg.outputs.name }}" - if ! npm view "$name" version >/dev/null 2>&1; then - echo "_First publish of this package — nothing to diff against._" + view_err=$(mktemp) + if ! npm view "$name" version >/dev/null 2>"$view_err"; then + if grep -q "code E404" "$view_err"; then + echo "_First publish of this package — nothing to diff against._" + else + echo "::error::Failed to look up $name on the npm registry (not a 404 — could be auth, network, or an outage). Refusing to treat this as a first publish." >&2 + cat "$view_err" >&2 + exit 1 + fi else prev_deps_json=$(npm view "$name" dependencies --json 2>/dev/null); [ -z "$prev_deps_json" ] && prev_deps_json='null' prev_peer_json=$(npm view "$name" peerDependencies --json 2>/dev/null); [ -z "$prev_peer_json" ] && prev_peer_json='null' @@ -123,6 +130,9 @@ jobs: - name: Publish ${{ needs.build.outputs.package-name }}@${{ needs.build.outputs.package-version }} working-directory: package - run: npm publish --provenance --access public + # --ignore-scripts: the artifact was already built and reviewed in the `build` + # job; no lifecycle script should run at this point with access to NPM_TOKEN + # or a chance to alter dist after it's been reviewed. + run: npm publish --provenance --access public --ignore-scripts env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/README.md b/README.md index 5422bd1..3667c80 100644 --- a/README.md +++ b/README.md @@ -111,7 +111,7 @@ cargo publish ### Publishing the npm package -The TS/JS client (`@cowprotocol/cow-settlement-client-js`, generated from `programs/settlement/idl/cow_settlement.json` via Codama) is published automatically by [`publish-npm.yml`](.github/workflows/publish-npm.yml) whenever a GitHub release is cut — its version must already match the release tag (see [Bumping the crate version](#bumping-the-crate-version), which bumps it alongside the crates). +The TS/JS client (`@cowprotocol/solana-settlement-client`, generated from `programs/settlement/idl/cow_settlement.json` via Codama) is published automatically by [`publish-npm.yml`](.github/workflows/publish-npm.yml) whenever a GitHub release is cut — its version must already match the release tag (see [Bumping the crate version](#bumping-the-crate-version), which bumps it alongside the crates). Publishing itself requires a manual approval in the `npm-publish` GitHub Environment. Before approving, check the job summary the workflow posts: it lists the exact tarball contents about to be published and a dependency diff against the previously published version. Approve only if both look as expected for the changes in this release. diff --git a/programs/settlement/idl/client/js/package.json b/programs/settlement/idl/client/js/package.json index 1ba6542..6304723 100644 --- a/programs/settlement/idl/client/js/package.json +++ b/programs/settlement/idl/client/js/package.json @@ -1,5 +1,5 @@ { - "name": "@cowprotocol/cow-settlement-client-js", + "name": "@cowprotocol/solana-settlement-client", "version": "0.3.0", "description": "TypeScript/JavaScript client for the CoW Protocol Solana settlement program, generated from its IDL.", "type": "module", From 1208a2a835b9680cfe0b07e04b1c862d4a2560a2 Mon Sep 17 00:00:00 2001 From: Kaze <230549489+kaze-cow@users.noreply.github.com> Date: Wed, 2 Sep 2026 15:57:55 +0900 Subject: [PATCH 30/43] clean up lock file --- .gitignore | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index de89b8d..b9301d0 100644 --- a/.gitignore +++ b/.gitignore @@ -2,14 +2,9 @@ proptest-regressions/ .cargo-root/ node_modules/ -pnpm-lock.yaml generated/ # Make sure no Solana key is uploaded by accident. *.json !bench-report.json - -# Include IDL, but don't include the generated parts. -!programs/settlement/idl/** -programs/settlement/idl/**/node_modules/ -programs/settlement/idl/client/js/src/generated/ +!programs/settlement/idl/**/*.json \ No newline at end of file From 85b4c2f9eaa3175a12bd1be414820ede76b8591d Mon Sep 17 00:00:00 2001 From: Kaze <230549489+kaze-cow@users.noreply.github.com> Date: Wed, 2 Sep 2026 16:04:21 +0900 Subject: [PATCH 31/43] Update Justfile Co-authored-by: Federico Giacon <58218759+fedgiac@users.noreply.github.com> --- Justfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Justfile b/Justfile index 1a2d4fc..4c5f499 100644 --- a/Justfile +++ b/Justfile @@ -28,7 +28,7 @@ test: build-program build-test-programs # Run tests from the generated clients from the IDL test-idl-generated: test-js-client -# Run the JS client's tests, which drive the real program through litesvm (needs the .so and a freshly rendered client). +# Run the JS client's tests test-js-client: build-program generate-js-client cd programs/settlement/idl/client/js && corepack pnpm install --frozen-lockfile && corepack pnpm exec vitest run From be8833680b969f9ce055cd2170d357d8d2c42a50 Mon Sep 17 00:00:00 2001 From: Kaze <230549489+kaze-cow@users.noreply.github.com> Date: Wed, 2 Sep 2026 16:51:26 +0900 Subject: [PATCH 32/43] misc fixes from review --- README.md | 2 ++ programs/settlement/idl/client/js/package.json | 15 ++++++++------- programs/settlement/idl/package.json | 6 +++--- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index e4240e0..4e38ccf 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,8 @@ It contains a high-level technical description of what the program does and poin Install the Solana toolchain (Rust, Solana CLI, and friends) by following the [Solana quick setup](https://solana.com/docs/intro/installation). +A Node.JS runtime is also necessary for generating client libraries from the IDL. + Common dev tasks are exposed via [`just`](https://just.systems/) recipes (see `Justfile`). Most package managers provide this package, see [list of available Just packages](https://just.systems/man/en/packages.html). Run `just --list` to see what's available. diff --git a/programs/settlement/idl/client/js/package.json b/programs/settlement/idl/client/js/package.json index 3073b26..0febb15 100644 --- a/programs/settlement/idl/client/js/package.json +++ b/programs/settlement/idl/client/js/package.json @@ -1,9 +1,10 @@ { - "name": "js-client", - "version": "1.0.0", + "name": "cow-solana-settlement-client", + "version": "0.3.0", "type": "module", "packageManager": "pnpm@10.30.3", - "description": "", + "description": "A library for interacting with CoW Protocol on Solana", + "license": "(MIT OR Apache-2.0)", "main": "src/index.ts", "files": [ "./dist/src", @@ -14,15 +15,15 @@ "test": "vitest run" }, "keywords": [], - "author": "", + "author": "CoW ", "peerDependencies": { - "@solana/kit": "^6.10.0" + "@solana/kit": "*" }, "dependencies": { - "@solana/program-client-core": "^6.10.0" + "@solana/program-client-core": "^8.x" }, "devDependencies": { - "@solana/kit": "^6.10.0", + "@solana/kit": "^8.0.0", "@types/node": "^24.10.0", "litesvm": "^1.3.0", "typescript": "^5.7.0", diff --git a/programs/settlement/idl/package.json b/programs/settlement/idl/package.json index 3179784..1c65c58 100644 --- a/programs/settlement/idl/package.json +++ b/programs/settlement/idl/package.json @@ -2,13 +2,13 @@ "name": "idl", "version": "1.0.0", "description": "", - "main": "index.js", + "private": true, "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "generate": "node generate.mjs" }, "keywords": [], "author": "", - "license": "ISC", + "license": "MIT OR Apache-2.0", "packageManager": "pnpm@10.30.3", "dependencies": { "@codama/nodes-from-anchor": "^1.5.2", From 5434c205536a18e497dc03c18a97614d6a9abab2 Mon Sep 17 00:00:00 2001 From: Kaze <230549489+kaze-cow@users.noreply.github.com> Date: Wed, 2 Sep 2026 16:56:21 +0900 Subject: [PATCH 33/43] update package manager and solana kit version --- .../settlement/idl/client/js/package.json | 4 +- .../settlement/idl/client/js/pnpm-lock.yaml | 913 +----------------- programs/settlement/idl/package.json | 2 +- 3 files changed, 33 insertions(+), 886 deletions(-) diff --git a/programs/settlement/idl/client/js/package.json b/programs/settlement/idl/client/js/package.json index 0febb15..059c7ed 100644 --- a/programs/settlement/idl/client/js/package.json +++ b/programs/settlement/idl/client/js/package.json @@ -2,7 +2,7 @@ "name": "cow-solana-settlement-client", "version": "0.3.0", "type": "module", - "packageManager": "pnpm@10.30.3", + "packageManager": "pnpm@11.25.0", "description": "A library for interacting with CoW Protocol on Solana", "license": "(MIT OR Apache-2.0)", "main": "src/index.ts", @@ -17,7 +17,7 @@ "keywords": [], "author": "CoW ", "peerDependencies": { - "@solana/kit": "*" + "@solana/kit": "^6.10.0" }, "dependencies": { "@solana/program-client-core": "^8.x" diff --git a/programs/settlement/idl/client/js/pnpm-lock.yaml b/programs/settlement/idl/client/js/pnpm-lock.yaml index 2c71e9c..990526b 100644 --- a/programs/settlement/idl/client/js/pnpm-lock.yaml +++ b/programs/settlement/idl/client/js/pnpm-lock.yaml @@ -9,12 +9,12 @@ importers: .: dependencies: '@solana/program-client-core': - specifier: ^6.10.0 - version: 6.10.0(typescript@5.9.3) + specifier: ^8.x + version: 8.2.0(typescript@5.9.3) devDependencies: '@solana/kit': - specifier: ^6.10.0 - version: 6.10.0(typescript@5.9.3) + specifier: ^8.0.0 + version: 8.2.0(typescript@5.9.3) '@types/node': specifier: ^24.10.0 version: 24.13.3 @@ -345,15 +345,6 @@ packages: peerDependencies: '@solana/kit': ^8.0.0 - '@solana/accounts@6.10.0': - resolution: {integrity: sha512-+FxfDOrnifoPlBkF+fr8eeQdgM6xtIgAg9xKMu3WnIz60oZd4Xnry6+ff6t+ePPoZZp397FSg9ZJet68VCWm5Q==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.4.0' - peerDependenciesMeta: - typescript: - optional: true - '@solana/accounts@8.2.0': resolution: {integrity: sha512-An3BICrQJQ7jR5EIgXzYnaKyCE7+ZusW9xX8m6Vj7U2cKo8t6Y3PTQ+aMjEajwzsQfxEL8QnpClFC9hdoIu7MA==} engines: {node: '>=20.18.0'} @@ -363,15 +354,6 @@ packages: typescript: optional: true - '@solana/addresses@6.10.0': - resolution: {integrity: sha512-vEoCGBTxG0HCERAn84KXkrJjl+pDaNzOpZ0qbgcPS98fYxP5yzbKB8SNOY2bzrbkRUmmw5Q3hqTRERemUN2Gcw==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.4.0' - peerDependenciesMeta: - typescript: - optional: true - '@solana/addresses@8.2.0': resolution: {integrity: sha512-7Okh8u7d3QrKu7ltJa3PASniUhasn1cdbcMQ/8gpGsmHQNCvdtAmvw18xSTdr4m62RJ/0cI/DtTVQyNwooeAXQ==} engines: {node: '>=20.18.0'} @@ -381,15 +363,6 @@ packages: typescript: optional: true - '@solana/assertions@6.10.0': - resolution: {integrity: sha512-lKSAdVo+P/6Lp4vs6shstXmFOpvxrABwn4o1462tb7sKkNapk6o9pPFVPGw4DUgPS3WqWRs1j2tmpuVjhQRntg==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.4.0' - peerDependenciesMeta: - typescript: - optional: true - '@solana/assertions@8.2.0': resolution: {integrity: sha512-izrnF8ZsviZDK0WCKl9ha5Ht4TNDHoU2QzMrPYOqkSkKkVh15p3MjTRXVFnM4CA+Xigtu8y8OPu2UnQNcAUVHQ==} engines: {node: '>=20.18.0'} @@ -399,15 +372,6 @@ packages: typescript: optional: true - '@solana/codecs-core@6.10.0': - resolution: {integrity: sha512-nfAl9OMGo4HanIMxGsQoVB7BxMoqBCYEUxl8oEAZZ09pDxnaXQZkTRXEwPPccag37XfW1ciPd1vWPKwB2b0HHQ==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.4.0' - peerDependenciesMeta: - typescript: - optional: true - '@solana/codecs-core@8.2.0': resolution: {integrity: sha512-ORwzswFXbqNqlyVigogFIrn3Ge5cpDQkuMY0u3M40HBwHcC6a79uqM87DpoZypncKJDWA1DfJ/3w9hhTGumYAw==} engines: {node: '>=20.18.0'} @@ -417,15 +381,6 @@ packages: typescript: optional: true - '@solana/codecs-data-structures@6.10.0': - resolution: {integrity: sha512-CNasJW3bq5u+632Zt5aJ8rOjAjv2HyenpV8o9kAIqdmV4CBpjCCoBnKn8LkuR/sbeREZxJYfhKTXO/9ruAkw7A==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.4.0' - peerDependenciesMeta: - typescript: - optional: true - '@solana/codecs-data-structures@8.2.0': resolution: {integrity: sha512-uq59oSAXM9QR+cO7R3JmSTxBiNNJnayVWz2VHBdhhCQS8DEmd6hhqY1RVmPTpFtE0Jix5MkRV3Bu5GTmf6Y66A==} engines: {node: '>=20.18.0'} @@ -435,15 +390,6 @@ packages: typescript: optional: true - '@solana/codecs-numbers@6.10.0': - resolution: {integrity: sha512-CcM+wX4zOiA9zkh8A7t1787A0Ehgmu5+6Z2tKoHew6cNw/dkaUTPa8JnNHbvfsLC8dfHC1BhAEJl86sKmRsfkQ==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.4.0' - peerDependenciesMeta: - typescript: - optional: true - '@solana/codecs-numbers@8.2.0': resolution: {integrity: sha512-GTOYzyk0SxQJS7MAN9zsyax4RFUtQDYzkVcpRf0Zo7eOy2/hPfuih09VJL2YdLPBJBcg8satdAYBYxxC282PYQ==} engines: {node: '>=20.18.0'} @@ -453,18 +399,6 @@ packages: typescript: optional: true - '@solana/codecs-strings@6.10.0': - resolution: {integrity: sha512-zlaqkg7K6F6IN4V/Ec8TWkTn054gxv7ZLagvGkuEyAdPQ6BzzsehOm2TqCuyXgJJTCGPLY1bEk6yH9NxANe0kA==} - engines: {node: '>=20.18.0'} - peerDependencies: - fastestsmallesttextencoderdecoder: ^1.0.22 - typescript: '>=5.4.0' - peerDependenciesMeta: - fastestsmallesttextencoderdecoder: - optional: true - typescript: - optional: true - '@solana/codecs-strings@8.2.0': resolution: {integrity: sha512-Dt/+rJ6gmH/OcOtvrhm6CtbB9jtVOGMxcIXoi62eNXw39Z1kJyN1gkqTjzBSS8Xb+X5lfkL70GHE9EDBb1JmqA==} engines: {node: '>=20.18.0'} @@ -477,15 +411,6 @@ packages: typescript: optional: true - '@solana/codecs@6.10.0': - resolution: {integrity: sha512-lLVuxod4ChWp9i7OvpgIykYG8Q9OGPVXKnHM9VlzDDLylsx7Y1FoQL00sHa7PqFkJVmkBufaA6dcGbQ7FU+lAQ==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.4.0' - peerDependenciesMeta: - typescript: - optional: true - '@solana/codecs@8.2.0': resolution: {integrity: sha512-kn2esyzFznx6Pbb+8FUe3YNKYRZUB8H81pCiXSIe1+0WJ44lRhZHMo0s4L3FQMKhWHOnlV30sWeIg8taHLVW7g==} engines: {node: '>=20.18.0'} @@ -495,16 +420,6 @@ packages: typescript: optional: true - '@solana/errors@6.10.0': - resolution: {integrity: sha512-KBLAxCtAXr357JNhCyIDQXWbuSj5vN6w+28FSfcYY6OOSiphmXLAV3V58jgV0C6iNbIzFJFi6yatFyDTdeJsNg==} - engines: {node: '>=20.18.0'} - hasBin: true - peerDependencies: - typescript: '>=5.4.0' - peerDependenciesMeta: - typescript: - optional: true - '@solana/errors@8.2.0': resolution: {integrity: sha512-BXc9mafl3SOnRL542jY02ezBSXHgqQOUCzREN/vvh1ASUPrUB3iorOEc62cSxFdDU4aDVMcugowJawmVNTXXSg==} engines: {node: '>=20.18.0'} @@ -515,15 +430,6 @@ packages: typescript: optional: true - '@solana/fast-stable-stringify@6.10.0': - resolution: {integrity: sha512-iCNed27wk6PKSS3QUtHovRfMWF/jbVWogs2vB4tukKUCsqG4rDfDInIwZ6ur/nY6XTrgi2gMMdZq9GAUlWsbfw==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.4.0' - peerDependenciesMeta: - typescript: - optional: true - '@solana/fast-stable-stringify@8.2.0': resolution: {integrity: sha512-OND76Qsng/fiTVSUvaNZFv0WKEULlwcGRtgeIE2keA2xYoHYNTSoD6mxv4iWANfeDo4EH7D/HnOwnGEFXMjr9w==} engines: {node: '>=20.18.0'} @@ -533,15 +439,6 @@ packages: typescript: optional: true - '@solana/fixed-points@6.10.0': - resolution: {integrity: sha512-ZkKL0alXH3L7/wMiVG8YUuG8qBKunlM810+YBD7nUPRhifiGsX1zwADViHLYNqLr/jUk0mTYFUcKznTpB/K+Gg==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.4.0' - peerDependenciesMeta: - typescript: - optional: true - '@solana/fixed-points@8.2.0': resolution: {integrity: sha512-w19JKErcbbENZzw4B+oBGwJXVKMIOi8TC7WxBawmpuv0XJSk6LP6surosg+XeoBHhtEsVCNHDtizi0mAS6OmMw==} engines: {node: '>=20.18.0'} @@ -551,15 +448,6 @@ packages: typescript: optional: true - '@solana/functional@6.10.0': - resolution: {integrity: sha512-P8cevu4mAqHTXC37h1TVoOh8zhWB2tlOI/R9vWjYPpcLwcyWf8p2qq4LEGHl5kY+1C+4PNX39HsmCocXOPCDkQ==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.4.0' - peerDependenciesMeta: - typescript: - optional: true - '@solana/functional@8.2.0': resolution: {integrity: sha512-+oTPl9yRZBbppUZU8qs4eu93iWPvs4Ij+HELPHISxLFo/cuG2YZGTDcWBVEzc8XEw0DUwwBOvou/wP7v1SnH+A==} engines: {node: '>=20.18.0'} @@ -569,15 +457,6 @@ packages: typescript: optional: true - '@solana/instruction-plans@6.10.0': - resolution: {integrity: sha512-YG7mo4zykzdc6ZTV0BuN6pveK9qeBySzlYYerq578A4eQu3xcypMAYRGAvhMZtWTanjjmD6CKtM0M7kVp0TNxg==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.4.0' - peerDependenciesMeta: - typescript: - optional: true - '@solana/instruction-plans@8.2.0': resolution: {integrity: sha512-DDVHBAPifG3Q0s5e2hiBbfvrruLb3AhumTupDK+3f3f7MDc0Dth6rX054HtIINloqbFIw15f6/A3Z4VTh74CTg==} engines: {node: '>=20.18.0'} @@ -587,15 +466,6 @@ packages: typescript: optional: true - '@solana/instructions@6.10.0': - resolution: {integrity: sha512-0TToYF+8LXQ3ofPMx+yF6yaM9l4YJvcAPMy0qV5JsrBUFlWXBSANRuudKBQLHMvb+a3OiUTq5X7omuorKMBB3A==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.4.0' - peerDependenciesMeta: - typescript: - optional: true - '@solana/instructions@8.2.0': resolution: {integrity: sha512-SFts84wW6hDXGSrLK5spl8nbKxKns2aR+S2ar0Zi3I0bl007heyoO7UKyxAoUvhfhObIfEIMuy2/qLoo6vDcjQ==} engines: {node: '>=20.18.0'} @@ -605,15 +475,6 @@ packages: typescript: optional: true - '@solana/keys@6.10.0': - resolution: {integrity: sha512-26IRfdm/hTUCmM7MeEeX0ULSbCM6OzkZTkfkrPircqmRM7xyNqP4hq7u0P7wjb9dl7NfgyG6K7cdvUxrj2e3mA==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.4.0' - peerDependenciesMeta: - typescript: - optional: true - '@solana/keys@8.2.0': resolution: {integrity: sha512-DezFZ0/ya98nILq+eSeq9fu9onVfqQYb7mtuDctdWxY1QFJvix562zkkFuFqnjOLL7XMEpdVPMxxQOzZ33wGCg==} engines: {node: '>=20.18.0'} @@ -623,15 +484,6 @@ packages: typescript: optional: true - '@solana/kit@6.10.0': - resolution: {integrity: sha512-/WnnQp3uARh2JCFSfAakejTAqwmXVuMVTcRn5r2yDwY2yzZ4R6mt/Cl59VPimVLNSoTyN/KsEwhv9omr3ERazQ==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.4.0' - peerDependenciesMeta: - typescript: - optional: true - '@solana/kit@8.2.0': resolution: {integrity: sha512-1BfmnYmWe17u3RRX3HuNxjWkr2/n9Bai+yIG/XjMpgviobF3n8zsisZBJHPH2uORqvjkTFnOqGXoEQC8vUZHzw==} engines: {node: '>=20.18.0'} @@ -641,15 +493,6 @@ packages: typescript: optional: true - '@solana/nominal-types@6.10.0': - resolution: {integrity: sha512-9ykyBBvnkInH7fCacjJi7zu2PJyd+OCt+VTjIISv070fHzKIMFqZqJJ/dJ0SRH2aHwfB3n86iVsmtBtuxi4KKA==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.4.0' - peerDependenciesMeta: - typescript: - optional: true - '@solana/nominal-types@8.2.0': resolution: {integrity: sha512-iuDE6ewgT7LJOSVC6UK4HR6n8INujujbglYVVFWNK/xWKi5p1y8JCOEEWAl/htK26LhLC51A1nMNfmBmTjP3ZQ==} engines: {node: '>=20.18.0'} @@ -659,15 +502,6 @@ packages: typescript: optional: true - '@solana/offchain-messages@6.10.0': - resolution: {integrity: sha512-RiEgAueeMkFMC1suOXBIcmCZgtXRxy24yk0DldPB37bB4zwOF1SAaRjNRPjIkGK8RhCYrEpPosnzLyavw9ueRg==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.4.0' - peerDependenciesMeta: - typescript: - optional: true - '@solana/offchain-messages@8.2.0': resolution: {integrity: sha512-yXfVtK1VoQ/Eyz2jH/1+avixhYcpCPkGkXuiXxA3Vf73WCvniC8mNVQ5ppsV+OqCNw62mxaFMmNiVgiAQapKuw==} engines: {node: '>=20.18.0'} @@ -677,15 +511,6 @@ packages: typescript: optional: true - '@solana/options@6.10.0': - resolution: {integrity: sha512-RO9UT3UYD8/Cu2uM6ZXbKvLeMnVD42+g9JRds7Pfs4AhiOyg4R4TJrQUAppTgavPTO3PBRlWtWOC05ZH/yAIbg==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.4.0' - peerDependenciesMeta: - typescript: - optional: true - '@solana/options@8.2.0': resolution: {integrity: sha512-b3//UzZe/uBaIpw4fT/nvCOghh5IHoNkW7FCMA/nzvQ48A16n8qpLki9/+lLHi0V0o7/Jz5Sof0UYc0aSf1Dig==} engines: {node: '>=20.18.0'} @@ -695,15 +520,6 @@ packages: typescript: optional: true - '@solana/plugin-core@6.10.0': - resolution: {integrity: sha512-JE70YTQOfFACVFGvoJon4Scc/eHUWjMu8Ovo35CcV2kHTAHYMCd4UkBd2gmlhK0vRMMomsQi1ZLPlAlTq0OoUQ==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.4.0' - peerDependenciesMeta: - typescript: - optional: true - '@solana/plugin-core@8.2.0': resolution: {integrity: sha512-V7oSIhYXbUzjd5LUY4tbSUnyBka1hmULPFKuqxNzYxeY4eLI7S8GmTOg7xg6tOC0bJ+HLPvv64asuMXAn/PklQ==} engines: {node: '>=20.18.0'} @@ -713,15 +529,6 @@ packages: typescript: optional: true - '@solana/plugin-interfaces@6.10.0': - resolution: {integrity: sha512-vr0/l9wcM4orwGr8cjkFWaJ9A4HvzuAv00jMFNMg0Spd0GZqnwnpW+D/fXa1lIJnTRaF3EeEjLh4VjKU037T0Q==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.4.0' - peerDependenciesMeta: - typescript: - optional: true - '@solana/plugin-interfaces@8.2.0': resolution: {integrity: sha512-goOhGI493Fq+xhZ8JKl9/FDVFd0SJdkv5Lh0L2ubqekzUiGRCvHNwgXL8nVS7fso2UxIssDQmYKwXvubfhBVhw==} engines: {node: '>=20.18.0'} @@ -731,15 +538,6 @@ packages: typescript: optional: true - '@solana/program-client-core@6.10.0': - resolution: {integrity: sha512-4PPbTLdC1ylHIuvhOFDP8RnSkXPCFjNFWGslzc+UFKnoR4ajzBcByX94jmaruDMk5ncxgj7tr9pzJTvfGHIaMA==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.4.0' - peerDependenciesMeta: - typescript: - optional: true - '@solana/program-client-core@8.2.0': resolution: {integrity: sha512-miQ7qKW0d0etaa2YAehGU3heV5Y4ip5BBCwZXb/yg8yWndTt4d4E+8z+5Q/oS5kOuFraOFYr+Uev7SQKngNXBg==} engines: {node: '>=20.18.0'} @@ -749,15 +547,6 @@ packages: typescript: optional: true - '@solana/programs@6.10.0': - resolution: {integrity: sha512-qn/HeLP5KGUJXVub3fyGe69/rWaLX4jzwm6V/1pNxJDbdF+MBdgn18hP6F+VmhfdNmwK0lue3J/1HQ1UTMuQeQ==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.4.0' - peerDependenciesMeta: - typescript: - optional: true - '@solana/programs@8.2.0': resolution: {integrity: sha512-yttl6ps7G9vM83pdfekyregTIqmRThFpdcrCIZ3y2qOLZ63KVxVMhNJ8kn8FrX3MyWh5rr/hTWdWKc4/U12Epg==} engines: {node: '>=20.18.0'} @@ -767,15 +556,6 @@ packages: typescript: optional: true - '@solana/promises@6.10.0': - resolution: {integrity: sha512-oJSIn+VBBMWDo8oqw7RV3tI6Jih+Ieup6FcQLYLDUriaeo7+8l1Zdezl8zh7SIfeU4lOfAbRg6mR0huaS/Lltg==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.4.0' - peerDependenciesMeta: - typescript: - optional: true - '@solana/promises@8.2.0': resolution: {integrity: sha512-i33ll+en6/Qcjw10gPeikCmU687W1pQNZPxirEuRWO/+PhE2qDQ9ZODgEakVi/1k+vSwL8sK941qfWig+3D0dQ==} engines: {node: '>=20.18.0'} @@ -785,15 +565,6 @@ packages: typescript: optional: true - '@solana/rpc-api@6.10.0': - resolution: {integrity: sha512-RjPIVsAb/85P1ptoO3WpC0x7QG6gG/e4q/3lo6gbSznUZOcoM+8sSBnCX7BwP1ZkCDS6NK/ClXLnhhhYZx+OGg==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.4.0' - peerDependenciesMeta: - typescript: - optional: true - '@solana/rpc-api@8.2.0': resolution: {integrity: sha512-lGvk1xeOo4cbypuD/5AAkJPHv5E3g7lqbzRIxZhsQPBkK+knVuEb7e3UncOnjuWkijZoFiB/k+Rfk83gmlhdpg==} engines: {node: '>=20.18.0'} @@ -803,15 +574,6 @@ packages: typescript: optional: true - '@solana/rpc-parsed-types@6.10.0': - resolution: {integrity: sha512-5275mvSV1mxhwvrMVa+K7BU/nAetpHfcb+8Ql9rtA8RRf6DyiimFQFZUukE4Ez6XJihEpCHNy98yhkgai9wytQ==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.4.0' - peerDependenciesMeta: - typescript: - optional: true - '@solana/rpc-parsed-types@8.2.0': resolution: {integrity: sha512-JJ4BfUlX8eCIUh3zm8jTkHkNLf6HyY9UjJmi4GPicFPJZ5MXSUeh42eaSxvHszXUoS7u9V30kTt1hznwfF5fqA==} engines: {node: '>=20.18.0'} @@ -821,15 +583,6 @@ packages: typescript: optional: true - '@solana/rpc-spec-types@6.10.0': - resolution: {integrity: sha512-NDZrKyZrJk4HaMFhTE/lAiMB824cWAodKqDHyKi0UteHU9pyRmil3BN1jt7e+j08mwMWwfklSgyrTaq52g6DIQ==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.4.0' - peerDependenciesMeta: - typescript: - optional: true - '@solana/rpc-spec-types@8.2.0': resolution: {integrity: sha512-pKOezoP0vuVwyjUKcS4Ewl3Mm/owv/16n7RocqFC3nx94qtk5FpSOAtielUHzBQ3JUgRLJrSKonw2yWxqgtVFg==} engines: {node: '>=20.18.0'} @@ -839,15 +592,6 @@ packages: typescript: optional: true - '@solana/rpc-spec@6.10.0': - resolution: {integrity: sha512-yQdbWw5mZEWrwsunHR9NHkuhMXIB9sPOObwm18D53v5tAJnxTB0IcHvO647XqFDLTK/yQ4AdDtlYD1vsY07AMQ==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.4.0' - peerDependenciesMeta: - typescript: - optional: true - '@solana/rpc-spec@8.2.0': resolution: {integrity: sha512-fR0hv/NP3K4WNePK9+97GYrDjzoN7kF0hlffRlSygksAC0FKvtKQ5lPBMg0ptWtswInp8Kk7Cz1zTCf6S+wLUQ==} engines: {node: '>=20.18.0'} @@ -857,15 +601,6 @@ packages: typescript: optional: true - '@solana/rpc-subscriptions-api@6.10.0': - resolution: {integrity: sha512-CRPQoTtT1cOwOQUsqS7jgo7wYdAj7jB5ab/UmMPWVpecf2FNMhWhgvxP2s82M7VkDGTGl13qaQ0WySmi7Egrlg==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.4.0' - peerDependenciesMeta: - typescript: - optional: true - '@solana/rpc-subscriptions-api@8.2.0': resolution: {integrity: sha512-37UHtjFmBUagtRw9NeWViTqSJlExyuI2j88m3jJSw9c6WRw7lLzUJIRGA51ArYyhAyhtAoGjXpUZiODKSE9lEw==} engines: {node: '>=20.18.0'} @@ -875,125 +610,8 @@ packages: typescript: optional: true - '@solana/rpc-subscriptions-channel-websocket@6.10.0': - resolution: {integrity: sha512-KkqP1186HELPlJftA88SNAT2znR8knCVzsUipXVzY4zfW8sN3LOa0ePMzh9VZ/V+J+raTt55laR87ovAO0n+zw==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.4.0' - peerDependenciesMeta: - typescript: - optional: true - - '@solana/rpc-subscriptions-channel-websocket@8.2.0': - resolution: {integrity: sha512-R9pk8Lq030M1+bAz6e2qKv6ldGLmICFYJOaLxVifyDE4VBb1BGV3Tt1VTAaFIfHyYucmFmxGRmPFmedA3Kysqw==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.4.0' - peerDependenciesMeta: - typescript: - optional: true - - '@solana/rpc-subscriptions-spec@6.10.0': - resolution: {integrity: sha512-nWMwGaG4ulzeX2sskY5TywXF3cwEd8FDmUpLe2JBWxE8XDAOGOKcsYPYFcBgb8ee9KqfPT2PTNdcz9jOhJf34w==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.4.0' - peerDependenciesMeta: - typescript: - optional: true - - '@solana/rpc-subscriptions-spec@8.2.0': - resolution: {integrity: sha512-ajcncAnQ7XzE85MZ8uajjO9E7NyLwLWFVUYG+y82vb04ZWFRN3DrMswIC4T5m14OkU3RY/Z2WGxC9nT1W4wPWw==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.4.0' - peerDependenciesMeta: - typescript: - optional: true - - '@solana/rpc-subscriptions@6.10.0': - resolution: {integrity: sha512-6mfuHp/K7unFKCOTCCBC9ziEGnxe2tyJ74EbR51QUnBeCUdYD7Hhdpxic1WRSJ3UeNW/mG4OzFM6z8Wi64Eh9Q==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.4.0' - peerDependenciesMeta: - typescript: - optional: true - - '@solana/rpc-subscriptions@8.2.0': - resolution: {integrity: sha512-pHf/RiDqIHeGp2blseYRVjzWz4WUAY/5vkOya+BQhjx+7Odr/J19G3ZVDwExgtU95UhCDL9gVHPyAgKr0mNcUg==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.4.0' - peerDependenciesMeta: - typescript: - optional: true - - '@solana/rpc-transformers@6.10.0': - resolution: {integrity: sha512-2nFUrVTiE720pJOY4XKx3HuYmishw0of/4oScu76YGm6O8wsmvFvPNAkrEinmieWXQkfpBfRvLZmpl8PaAy+ug==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.4.0' - peerDependenciesMeta: - typescript: - optional: true - - '@solana/rpc-transformers@8.2.0': - resolution: {integrity: sha512-tiMdJ9ZRgqANBNxlXK7OSDbwixAy7K1MzowzO7vNdlJbV+0WN0Lm/X5hEhKnlU42AD+clC6t9qZjVbg7BhQrqw==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.4.0' - peerDependenciesMeta: - typescript: - optional: true - - '@solana/rpc-transport-http@6.10.0': - resolution: {integrity: sha512-JrdNuYi0nBbD3X8JUtgX1dQJwIwz/WJvmigDdELysXfGB2bTJpfjqGDLhCLOz2sRl66FASIEqgG/LVa2C9VXcA==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.4.0' - peerDependenciesMeta: - typescript: - optional: true - - '@solana/rpc-transport-http@8.2.0': - resolution: {integrity: sha512-eOkgv52ZSMFLYNQaCsvxmPciZeXplWaPjbEcl9iZkGOAp3B2bO6KyMg8trEjaZNfcLC15+CpXMOZpMArXXSBCg==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.4.0' - peerDependenciesMeta: - typescript: - optional: true - - '@solana/rpc-types@6.10.0': - resolution: {integrity: sha512-zaSecTfCPvz/vcoAmKD6XoRstGHTr1EKJBD8T9UcpEFFB6CtF6DxerDB+wrzkamuT6msmnR2DWXMrYOGDAsgIg==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.4.0' - peerDependenciesMeta: - typescript: - optional: true - - '@solana/rpc-types@8.2.0': - resolution: {integrity: sha512-rGF2vB8Bk0G2DYNxgEbDlANk+KirQGHVS1qRLxsi6OxACrgsSrGqrp0Onb5J8HLRMTEF+QrbbORDz9TQ5Q71fQ==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.4.0' - peerDependenciesMeta: - typescript: - optional: true - - '@solana/rpc@6.10.0': - resolution: {integrity: sha512-EwxsqoD+NXV+m+iobnWNtATD93gTgaNsOiQOzYB1/2e+8S6fl6obdNPB55yfXgtl4jt6GV6/ae4xuPhLv76vvg==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.4.0' - peerDependenciesMeta: - typescript: - optional: true - - '@solana/rpc@8.2.0': - resolution: {integrity: sha512-Of/2KqDf728HxKzJlwlZRvRSrgpHoDAg5+t/3RwdXWBoRQ1r3FXqwBXOrBT2g47w+fUy1iJcy5XZ7LXnXBXPIg==} + '@solana/rpc-subscriptions-channel-websocket@8.2.0': + resolution: {integrity: sha512-R9pk8Lq030M1+bAz6e2qKv6ldGLmICFYJOaLxVifyDE4VBb1BGV3Tt1VTAaFIfHyYucmFmxGRmPFmedA3Kysqw==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1001,8 +619,8 @@ packages: typescript: optional: true - '@solana/signers@6.10.0': - resolution: {integrity: sha512-+vtCc+mT1FpGxrA5oL2aaMxSHiMJ2hH5PcDIfjo2XJkHz2klZiCZyT5F9+zpltc9vdi1QTElQq59Sfplmtd33A==} + '@solana/rpc-subscriptions-spec@8.2.0': + resolution: {integrity: sha512-ajcncAnQ7XzE85MZ8uajjO9E7NyLwLWFVUYG+y82vb04ZWFRN3DrMswIC4T5m14OkU3RY/Z2WGxC9nT1W4wPWw==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1010,8 +628,8 @@ packages: typescript: optional: true - '@solana/signers@8.2.0': - resolution: {integrity: sha512-wfLiDhtPMnE9Mn8IeSAJ0RMfCyHUqeNZllFLfgDY3RUsCf5s9EgMC5U+HNSvtEWJ8ABGWWR5nYyWMXTWiMeuPA==} + '@solana/rpc-subscriptions@8.2.0': + resolution: {integrity: sha512-pHf/RiDqIHeGp2blseYRVjzWz4WUAY/5vkOya+BQhjx+7Odr/J19G3ZVDwExgtU95UhCDL9gVHPyAgKr0mNcUg==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1019,8 +637,8 @@ packages: typescript: optional: true - '@solana/subscribable@6.10.0': - resolution: {integrity: sha512-VsR6XMwkiDBkZJUcoGkEOhf397pOV75gKCL9Bx8bpi2T3Bbs0CxUpMn4yaUgAnRba3eXmjbXMNCXjttfa6sKbw==} + '@solana/rpc-transformers@8.2.0': + resolution: {integrity: sha512-tiMdJ9ZRgqANBNxlXK7OSDbwixAy7K1MzowzO7vNdlJbV+0WN0Lm/X5hEhKnlU42AD+clC6t9qZjVbg7BhQrqw==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1028,8 +646,8 @@ packages: typescript: optional: true - '@solana/subscribable@8.2.0': - resolution: {integrity: sha512-ATJBeJkaCUIxU3JWUcgfOjnOM3nn9qDfTigEkr0Cp3xFzIHnIVwis3W4Hcc/de1z0uvOXQOIYroahDr8H+djOg==} + '@solana/rpc-transport-http@8.2.0': + resolution: {integrity: sha512-eOkgv52ZSMFLYNQaCsvxmPciZeXplWaPjbEcl9iZkGOAp3B2bO6KyMg8trEjaZNfcLC15+CpXMOZpMArXXSBCg==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1037,8 +655,8 @@ packages: typescript: optional: true - '@solana/sysvars@6.10.0': - resolution: {integrity: sha512-cG13p1+onxz+20iWjwWQr1Z1jQwPm0fnjoW75fqZq7p4rVCie3L2sXvaJsYPjWKrUvpOzOIEHnqZGkG05rCpjg==} + '@solana/rpc-types@8.2.0': + resolution: {integrity: sha512-rGF2vB8Bk0G2DYNxgEbDlANk+KirQGHVS1qRLxsi6OxACrgsSrGqrp0Onb5J8HLRMTEF+QrbbORDz9TQ5Q71fQ==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1046,8 +664,8 @@ packages: typescript: optional: true - '@solana/sysvars@8.2.0': - resolution: {integrity: sha512-kwhOwBfUvUGuGGGnwTGHtNVQ02O3YCfXpp4xwUhe6bjUyp9M9wEmf70up6I9x2D4uB1nHaZRfco1CXfxhcH8sg==} + '@solana/rpc@8.2.0': + resolution: {integrity: sha512-Of/2KqDf728HxKzJlwlZRvRSrgpHoDAg5+t/3RwdXWBoRQ1r3FXqwBXOrBT2g47w+fUy1iJcy5XZ7LXnXBXPIg==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1055,8 +673,8 @@ packages: typescript: optional: true - '@solana/transaction-confirmation@6.10.0': - resolution: {integrity: sha512-ULvtg65qfenh4T/GYcIlKSUv5EqDcng9UN0dxbHU4kuZdR2e0B8HN2xDC4WhcFQVeFJSbTZmaYFkeTY/Y4gfGQ==} + '@solana/signers@8.2.0': + resolution: {integrity: sha512-wfLiDhtPMnE9Mn8IeSAJ0RMfCyHUqeNZllFLfgDY3RUsCf5s9EgMC5U+HNSvtEWJ8ABGWWR5nYyWMXTWiMeuPA==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1064,8 +682,8 @@ packages: typescript: optional: true - '@solana/transaction-confirmation@8.2.0': - resolution: {integrity: sha512-3L1LlMQ00l2kb3pcejvQ7vMKzyFayFhc6PqvZyh3M0/FNPfsc4z46yUf35I79SI6cuFWy2VkzA+a2ylOuCNC7w==} + '@solana/subscribable@8.2.0': + resolution: {integrity: sha512-ATJBeJkaCUIxU3JWUcgfOjnOM3nn9qDfTigEkr0Cp3xFzIHnIVwis3W4Hcc/de1z0uvOXQOIYroahDr8H+djOg==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1073,8 +691,8 @@ packages: typescript: optional: true - '@solana/transaction-introspection@8.2.0': - resolution: {integrity: sha512-unha6ugKrZa1TcB5Slnxisa/uQC56fyYi7BDvfCVI60OLEowtOTTvmJMKe35ETMzbimjBEPE/B5EgbydOHVBnQ==} + '@solana/sysvars@8.2.0': + resolution: {integrity: sha512-kwhOwBfUvUGuGGGnwTGHtNVQ02O3YCfXpp4xwUhe6bjUyp9M9wEmf70up6I9x2D4uB1nHaZRfco1CXfxhcH8sg==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1082,8 +700,8 @@ packages: typescript: optional: true - '@solana/transaction-messages@6.10.0': - resolution: {integrity: sha512-s7v8G3BTxGlKYIj3eWCG0g1296v+1LBt16mVnlRH5FuyaJ5AdhlhtRho5HUDpdwE8EXun+y1c48V6uhcZ8wdbQ==} + '@solana/transaction-confirmation@8.2.0': + resolution: {integrity: sha512-3L1LlMQ00l2kb3pcejvQ7vMKzyFayFhc6PqvZyh3M0/FNPfsc4z46yUf35I79SI6cuFWy2VkzA+a2ylOuCNC7w==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1091,8 +709,8 @@ packages: typescript: optional: true - '@solana/transaction-messages@8.2.0': - resolution: {integrity: sha512-+0U4iR/WRb8UiBXRhJJUY0+BmAOv+bQj7fifUF6o7x/IPg/K2Y4CmH4m7dOT2yhcg0KDzZPkXidXLm6saBX0Hw==} + '@solana/transaction-introspection@8.2.0': + resolution: {integrity: sha512-unha6ugKrZa1TcB5Slnxisa/uQC56fyYi7BDvfCVI60OLEowtOTTvmJMKe35ETMzbimjBEPE/B5EgbydOHVBnQ==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1100,8 +718,8 @@ packages: typescript: optional: true - '@solana/transactions@6.10.0': - resolution: {integrity: sha512-VADSqP9OTYmhrox4pcgDd4+RjVmednXSE0+8Y7SPK4PN1pK5Az2RJ0nSsy0xcTnaOr8mF/crwFktqPrRQwSbQA==} + '@solana/transaction-messages@8.2.0': + resolution: {integrity: sha512-+0U4iR/WRb8UiBXRhJJUY0+BmAOv+bQj7fifUF6o7x/IPg/K2Y4CmH4m7dOT2yhcg0KDzZPkXidXLm6saBX0Hw==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1617,19 +1235,6 @@ snapshots: '@solana-program/system': 0.14.0(@solana/kit@8.2.0(typescript@5.9.3)) '@solana/kit': 8.2.0(typescript@5.9.3) - '@solana/accounts@6.10.0(typescript@5.9.3)': - dependencies: - '@solana/addresses': 6.10.0(typescript@5.9.3) - '@solana/codecs-core': 6.10.0(typescript@5.9.3) - '@solana/codecs-strings': 6.10.0(typescript@5.9.3) - '@solana/errors': 6.10.0(typescript@5.9.3) - '@solana/rpc-spec': 6.10.0(typescript@5.9.3) - '@solana/rpc-types': 6.10.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - '@solana/accounts@8.2.0(typescript@5.9.3)': dependencies: '@solana/addresses': 8.2.0(typescript@5.9.3) @@ -1643,18 +1248,6 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/addresses@6.10.0(typescript@5.9.3)': - dependencies: - '@solana/assertions': 6.10.0(typescript@5.9.3) - '@solana/codecs-core': 6.10.0(typescript@5.9.3) - '@solana/codecs-strings': 6.10.0(typescript@5.9.3) - '@solana/errors': 6.10.0(typescript@5.9.3) - '@solana/nominal-types': 6.10.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - '@solana/addresses@8.2.0(typescript@5.9.3)': dependencies: '@solana/assertions': 8.2.0(typescript@5.9.3) @@ -1667,38 +1260,18 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/assertions@6.10.0(typescript@5.9.3)': - dependencies: - '@solana/errors': 6.10.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - '@solana/assertions@8.2.0(typescript@5.9.3)': dependencies: '@solana/errors': 8.2.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 - '@solana/codecs-core@6.10.0(typescript@5.9.3)': - dependencies: - '@solana/errors': 6.10.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - '@solana/codecs-core@8.2.0(typescript@5.9.3)': dependencies: '@solana/errors': 8.2.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 - '@solana/codecs-data-structures@6.10.0(typescript@5.9.3)': - dependencies: - '@solana/codecs-core': 6.10.0(typescript@5.9.3) - '@solana/codecs-numbers': 6.10.0(typescript@5.9.3) - '@solana/errors': 6.10.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - '@solana/codecs-data-structures@8.2.0(typescript@5.9.3)': dependencies: '@solana/codecs-core': 8.2.0(typescript@5.9.3) @@ -1707,13 +1280,6 @@ snapshots: optionalDependencies: typescript: 5.9.3 - '@solana/codecs-numbers@6.10.0(typescript@5.9.3)': - dependencies: - '@solana/codecs-core': 6.10.0(typescript@5.9.3) - '@solana/errors': 6.10.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - '@solana/codecs-numbers@8.2.0(typescript@5.9.3)': dependencies: '@solana/codecs-core': 8.2.0(typescript@5.9.3) @@ -1721,14 +1287,6 @@ snapshots: optionalDependencies: typescript: 5.9.3 - '@solana/codecs-strings@6.10.0(typescript@5.9.3)': - dependencies: - '@solana/codecs-core': 6.10.0(typescript@5.9.3) - '@solana/codecs-numbers': 6.10.0(typescript@5.9.3) - '@solana/errors': 6.10.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - '@solana/codecs-strings@8.2.0(typescript@5.9.3)': dependencies: '@solana/codecs-core': 8.2.0(typescript@5.9.3) @@ -1737,19 +1295,6 @@ snapshots: optionalDependencies: typescript: 5.9.3 - '@solana/codecs@6.10.0(typescript@5.9.3)': - dependencies: - '@solana/codecs-core': 6.10.0(typescript@5.9.3) - '@solana/codecs-data-structures': 6.10.0(typescript@5.9.3) - '@solana/codecs-numbers': 6.10.0(typescript@5.9.3) - '@solana/codecs-strings': 6.10.0(typescript@5.9.3) - '@solana/fixed-points': 6.10.0(typescript@5.9.3) - '@solana/options': 6.10.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - '@solana/codecs@8.2.0(typescript@5.9.3)': dependencies: '@solana/codecs-core': 8.2.0(typescript@5.9.3) @@ -1763,13 +1308,6 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/errors@6.10.0(typescript@5.9.3)': - dependencies: - chalk: 5.6.2 - commander: 15.0.0 - optionalDependencies: - typescript: 5.9.3 - '@solana/errors@8.2.0(typescript@5.9.3)': dependencies: chalk: 5.6.2 @@ -1777,21 +1315,10 @@ snapshots: optionalDependencies: typescript: 5.9.3 - '@solana/fast-stable-stringify@6.10.0(typescript@5.9.3)': - optionalDependencies: - typescript: 5.9.3 - '@solana/fast-stable-stringify@8.2.0(typescript@5.9.3)': optionalDependencies: typescript: 5.9.3 - '@solana/fixed-points@6.10.0(typescript@5.9.3)': - dependencies: - '@solana/codecs-core': 6.10.0(typescript@5.9.3) - '@solana/errors': 6.10.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - '@solana/fixed-points@8.2.0(typescript@5.9.3)': dependencies: '@solana/codecs-core': 8.2.0(typescript@5.9.3) @@ -1799,27 +1326,10 @@ snapshots: optionalDependencies: typescript: 5.9.3 - '@solana/functional@6.10.0(typescript@5.9.3)': - optionalDependencies: - typescript: 5.9.3 - '@solana/functional@8.2.0(typescript@5.9.3)': optionalDependencies: typescript: 5.9.3 - '@solana/instruction-plans@6.10.0(typescript@5.9.3)': - dependencies: - '@solana/errors': 6.10.0(typescript@5.9.3) - '@solana/instructions': 6.10.0(typescript@5.9.3) - '@solana/keys': 6.10.0(typescript@5.9.3) - '@solana/promises': 6.10.0(typescript@5.9.3) - '@solana/transaction-messages': 6.10.0(typescript@5.9.3) - '@solana/transactions': 6.10.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - '@solana/instruction-plans@8.2.0(typescript@5.9.3)': dependencies: '@solana/errors': 8.2.0(typescript@5.9.3) @@ -1833,13 +1343,6 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/instructions@6.10.0(typescript@5.9.3)': - dependencies: - '@solana/codecs-core': 6.10.0(typescript@5.9.3) - '@solana/errors': 6.10.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - '@solana/instructions@8.2.0(typescript@5.9.3)': dependencies: '@solana/codecs-core': 8.2.0(typescript@5.9.3) @@ -1847,19 +1350,6 @@ snapshots: optionalDependencies: typescript: 5.9.3 - '@solana/keys@6.10.0(typescript@5.9.3)': - dependencies: - '@solana/assertions': 6.10.0(typescript@5.9.3) - '@solana/codecs-core': 6.10.0(typescript@5.9.3) - '@solana/codecs-strings': 6.10.0(typescript@5.9.3) - '@solana/errors': 6.10.0(typescript@5.9.3) - '@solana/nominal-types': 6.10.0(typescript@5.9.3) - '@solana/promises': 6.10.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - '@solana/keys@8.2.0(typescript@5.9.3)': dependencies: '@solana/assertions': 8.2.0(typescript@5.9.3) @@ -1873,40 +1363,6 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/kit@6.10.0(typescript@5.9.3)': - dependencies: - '@solana/accounts': 6.10.0(typescript@5.9.3) - '@solana/addresses': 6.10.0(typescript@5.9.3) - '@solana/codecs': 6.10.0(typescript@5.9.3) - '@solana/errors': 6.10.0(typescript@5.9.3) - '@solana/functional': 6.10.0(typescript@5.9.3) - '@solana/instruction-plans': 6.10.0(typescript@5.9.3) - '@solana/instructions': 6.10.0(typescript@5.9.3) - '@solana/keys': 6.10.0(typescript@5.9.3) - '@solana/offchain-messages': 6.10.0(typescript@5.9.3) - '@solana/plugin-core': 6.10.0(typescript@5.9.3) - '@solana/plugin-interfaces': 6.10.0(typescript@5.9.3) - '@solana/program-client-core': 6.10.0(typescript@5.9.3) - '@solana/programs': 6.10.0(typescript@5.9.3) - '@solana/rpc': 6.10.0(typescript@5.9.3) - '@solana/rpc-api': 6.10.0(typescript@5.9.3) - '@solana/rpc-parsed-types': 6.10.0(typescript@5.9.3) - '@solana/rpc-spec-types': 6.10.0(typescript@5.9.3) - '@solana/rpc-subscriptions': 6.10.0(typescript@5.9.3) - '@solana/rpc-types': 6.10.0(typescript@5.9.3) - '@solana/signers': 6.10.0(typescript@5.9.3) - '@solana/subscribable': 6.10.0(typescript@5.9.3) - '@solana/sysvars': 6.10.0(typescript@5.9.3) - '@solana/transaction-confirmation': 6.10.0(typescript@5.9.3) - '@solana/transaction-messages': 6.10.0(typescript@5.9.3) - '@solana/transactions': 6.10.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - bufferutil - - fastestsmallesttextencoderdecoder - - utf-8-validate - '@solana/kit@8.2.0(typescript@5.9.3)': dependencies: '@solana/accounts': 8.2.0(typescript@5.9.3) @@ -1943,29 +1399,10 @@ snapshots: - fastestsmallesttextencoderdecoder - utf-8-validate - '@solana/nominal-types@6.10.0(typescript@5.9.3)': - optionalDependencies: - typescript: 5.9.3 - '@solana/nominal-types@8.2.0(typescript@5.9.3)': optionalDependencies: typescript: 5.9.3 - '@solana/offchain-messages@6.10.0(typescript@5.9.3)': - dependencies: - '@solana/addresses': 6.10.0(typescript@5.9.3) - '@solana/codecs-core': 6.10.0(typescript@5.9.3) - '@solana/codecs-data-structures': 6.10.0(typescript@5.9.3) - '@solana/codecs-numbers': 6.10.0(typescript@5.9.3) - '@solana/codecs-strings': 6.10.0(typescript@5.9.3) - '@solana/errors': 6.10.0(typescript@5.9.3) - '@solana/keys': 6.10.0(typescript@5.9.3) - '@solana/nominal-types': 6.10.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - '@solana/offchain-messages@8.2.0(typescript@5.9.3)': dependencies: '@solana/addresses': 8.2.0(typescript@5.9.3) @@ -1981,18 +1418,6 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/options@6.10.0(typescript@5.9.3)': - dependencies: - '@solana/codecs-core': 6.10.0(typescript@5.9.3) - '@solana/codecs-data-structures': 6.10.0(typescript@5.9.3) - '@solana/codecs-numbers': 6.10.0(typescript@5.9.3) - '@solana/codecs-strings': 6.10.0(typescript@5.9.3) - '@solana/errors': 6.10.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - '@solana/options@8.2.0(typescript@5.9.3)': dependencies: '@solana/codecs-core': 8.2.0(typescript@5.9.3) @@ -2005,28 +1430,10 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/plugin-core@6.10.0(typescript@5.9.3)': - optionalDependencies: - typescript: 5.9.3 - '@solana/plugin-core@8.2.0(typescript@5.9.3)': optionalDependencies: typescript: 5.9.3 - '@solana/plugin-interfaces@6.10.0(typescript@5.9.3)': - dependencies: - '@solana/addresses': 6.10.0(typescript@5.9.3) - '@solana/instruction-plans': 6.10.0(typescript@5.9.3) - '@solana/keys': 6.10.0(typescript@5.9.3) - '@solana/rpc-spec': 6.10.0(typescript@5.9.3) - '@solana/rpc-subscriptions-spec': 6.10.0(typescript@5.9.3) - '@solana/rpc-types': 6.10.0(typescript@5.9.3) - '@solana/signers': 6.10.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - '@solana/plugin-interfaces@8.2.0(typescript@5.9.3)': dependencies: '@solana/accounts': 8.2.0(typescript@5.9.3) @@ -2043,22 +1450,6 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/program-client-core@6.10.0(typescript@5.9.3)': - dependencies: - '@solana/accounts': 6.10.0(typescript@5.9.3) - '@solana/addresses': 6.10.0(typescript@5.9.3) - '@solana/codecs-core': 6.10.0(typescript@5.9.3) - '@solana/errors': 6.10.0(typescript@5.9.3) - '@solana/instruction-plans': 6.10.0(typescript@5.9.3) - '@solana/instructions': 6.10.0(typescript@5.9.3) - '@solana/plugin-interfaces': 6.10.0(typescript@5.9.3) - '@solana/rpc-api': 6.10.0(typescript@5.9.3) - '@solana/signers': 6.10.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - '@solana/program-client-core@8.2.0(typescript@5.9.3)': dependencies: '@solana/accounts': 8.2.0(typescript@5.9.3) @@ -2075,15 +1466,6 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/programs@6.10.0(typescript@5.9.3)': - dependencies: - '@solana/addresses': 6.10.0(typescript@5.9.3) - '@solana/errors': 6.10.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - '@solana/programs@8.2.0(typescript@5.9.3)': dependencies: '@solana/addresses': 8.2.0(typescript@5.9.3) @@ -2093,32 +1475,10 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/promises@6.10.0(typescript@5.9.3)': - optionalDependencies: - typescript: 5.9.3 - '@solana/promises@8.2.0(typescript@5.9.3)': optionalDependencies: typescript: 5.9.3 - '@solana/rpc-api@6.10.0(typescript@5.9.3)': - dependencies: - '@solana/addresses': 6.10.0(typescript@5.9.3) - '@solana/codecs-core': 6.10.0(typescript@5.9.3) - '@solana/codecs-strings': 6.10.0(typescript@5.9.3) - '@solana/errors': 6.10.0(typescript@5.9.3) - '@solana/keys': 6.10.0(typescript@5.9.3) - '@solana/rpc-parsed-types': 6.10.0(typescript@5.9.3) - '@solana/rpc-spec': 6.10.0(typescript@5.9.3) - '@solana/rpc-transformers': 6.10.0(typescript@5.9.3) - '@solana/rpc-types': 6.10.0(typescript@5.9.3) - '@solana/transaction-messages': 6.10.0(typescript@5.9.3) - '@solana/transactions': 6.10.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - '@solana/rpc-api@8.2.0(typescript@5.9.3)': dependencies: '@solana/addresses': 8.2.0(typescript@5.9.3) @@ -2137,32 +1497,16 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/rpc-parsed-types@6.10.0(typescript@5.9.3)': - optionalDependencies: - typescript: 5.9.3 - '@solana/rpc-parsed-types@8.2.0(typescript@5.9.3)': optionalDependencies: typescript: 5.9.3 - '@solana/rpc-spec-types@6.10.0(typescript@5.9.3)': - optionalDependencies: - typescript: 5.9.3 - '@solana/rpc-spec-types@8.2.0(typescript@5.9.3)': dependencies: '@solana/errors': 8.2.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 - '@solana/rpc-spec@6.10.0(typescript@5.9.3)': - dependencies: - '@solana/errors': 6.10.0(typescript@5.9.3) - '@solana/rpc-spec-types': 6.10.0(typescript@5.9.3) - '@solana/subscribable': 6.10.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - '@solana/rpc-spec@8.2.0(typescript@5.9.3)': dependencies: '@solana/errors': 8.2.0(typescript@5.9.3) @@ -2171,20 +1515,6 @@ snapshots: optionalDependencies: typescript: 5.9.3 - '@solana/rpc-subscriptions-api@6.10.0(typescript@5.9.3)': - dependencies: - '@solana/addresses': 6.10.0(typescript@5.9.3) - '@solana/keys': 6.10.0(typescript@5.9.3) - '@solana/rpc-subscriptions-spec': 6.10.0(typescript@5.9.3) - '@solana/rpc-transformers': 6.10.0(typescript@5.9.3) - '@solana/rpc-types': 6.10.0(typescript@5.9.3) - '@solana/transaction-messages': 6.10.0(typescript@5.9.3) - '@solana/transactions': 6.10.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - '@solana/rpc-subscriptions-api@8.2.0(typescript@5.9.3)': dependencies: '@solana/addresses': 8.2.0(typescript@5.9.3) @@ -2199,19 +1529,6 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/rpc-subscriptions-channel-websocket@6.10.0(typescript@5.9.3)': - dependencies: - '@solana/errors': 6.10.0(typescript@5.9.3) - '@solana/functional': 6.10.0(typescript@5.9.3) - '@solana/rpc-subscriptions-spec': 6.10.0(typescript@5.9.3) - '@solana/subscribable': 6.10.0(typescript@5.9.3) - ws: 8.21.3 - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - '@solana/rpc-subscriptions-channel-websocket@8.2.0(typescript@5.9.3)': dependencies: '@solana/errors': 8.2.0(typescript@5.9.3) @@ -2225,15 +1542,6 @@ snapshots: - bufferutil - utf-8-validate - '@solana/rpc-subscriptions-spec@6.10.0(typescript@5.9.3)': - dependencies: - '@solana/errors': 6.10.0(typescript@5.9.3) - '@solana/promises': 6.10.0(typescript@5.9.3) - '@solana/rpc-spec-types': 6.10.0(typescript@5.9.3) - '@solana/subscribable': 6.10.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - '@solana/rpc-subscriptions-spec@8.2.0(typescript@5.9.3)': dependencies: '@solana/errors': 8.2.0(typescript@5.9.3) @@ -2243,26 +1551,6 @@ snapshots: optionalDependencies: typescript: 5.9.3 - '@solana/rpc-subscriptions@6.10.0(typescript@5.9.3)': - dependencies: - '@solana/errors': 6.10.0(typescript@5.9.3) - '@solana/fast-stable-stringify': 6.10.0(typescript@5.9.3) - '@solana/functional': 6.10.0(typescript@5.9.3) - '@solana/promises': 6.10.0(typescript@5.9.3) - '@solana/rpc-spec-types': 6.10.0(typescript@5.9.3) - '@solana/rpc-subscriptions-api': 6.10.0(typescript@5.9.3) - '@solana/rpc-subscriptions-channel-websocket': 6.10.0(typescript@5.9.3) - '@solana/rpc-subscriptions-spec': 6.10.0(typescript@5.9.3) - '@solana/rpc-transformers': 6.10.0(typescript@5.9.3) - '@solana/rpc-types': 6.10.0(typescript@5.9.3) - '@solana/subscribable': 6.10.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - bufferutil - - fastestsmallesttextencoderdecoder - - utf-8-validate - '@solana/rpc-subscriptions@8.2.0(typescript@5.9.3)': dependencies: '@solana/errors': 8.2.0(typescript@5.9.3) @@ -2283,18 +1571,6 @@ snapshots: - fastestsmallesttextencoderdecoder - utf-8-validate - '@solana/rpc-transformers@6.10.0(typescript@5.9.3)': - dependencies: - '@solana/errors': 6.10.0(typescript@5.9.3) - '@solana/functional': 6.10.0(typescript@5.9.3) - '@solana/nominal-types': 6.10.0(typescript@5.9.3) - '@solana/rpc-spec-types': 6.10.0(typescript@5.9.3) - '@solana/rpc-types': 6.10.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - '@solana/rpc-transformers@8.2.0(typescript@5.9.3)': dependencies: '@solana/errors': 8.2.0(typescript@5.9.3) @@ -2307,15 +1583,6 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/rpc-transport-http@6.10.0(typescript@5.9.3)': - dependencies: - '@solana/errors': 6.10.0(typescript@5.9.3) - '@solana/rpc-spec': 6.10.0(typescript@5.9.3) - '@solana/rpc-spec-types': 6.10.0(typescript@5.9.3) - undici-types: 8.10.1 - optionalDependencies: - typescript: 5.9.3 - '@solana/rpc-transport-http@8.2.0(typescript@5.9.3)': dependencies: '@solana/errors': 8.2.0(typescript@5.9.3) @@ -2325,20 +1592,6 @@ snapshots: optionalDependencies: typescript: 5.9.3 - '@solana/rpc-types@6.10.0(typescript@5.9.3)': - dependencies: - '@solana/addresses': 6.10.0(typescript@5.9.3) - '@solana/codecs-core': 6.10.0(typescript@5.9.3) - '@solana/codecs-numbers': 6.10.0(typescript@5.9.3) - '@solana/codecs-strings': 6.10.0(typescript@5.9.3) - '@solana/errors': 6.10.0(typescript@5.9.3) - '@solana/fixed-points': 6.10.0(typescript@5.9.3) - '@solana/nominal-types': 6.10.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - '@solana/rpc-types@8.2.0(typescript@5.9.3)': dependencies: '@solana/addresses': 8.2.0(typescript@5.9.3) @@ -2353,22 +1606,6 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/rpc@6.10.0(typescript@5.9.3)': - dependencies: - '@solana/errors': 6.10.0(typescript@5.9.3) - '@solana/fast-stable-stringify': 6.10.0(typescript@5.9.3) - '@solana/functional': 6.10.0(typescript@5.9.3) - '@solana/rpc-api': 6.10.0(typescript@5.9.3) - '@solana/rpc-spec': 6.10.0(typescript@5.9.3) - '@solana/rpc-spec-types': 6.10.0(typescript@5.9.3) - '@solana/rpc-transformers': 6.10.0(typescript@5.9.3) - '@solana/rpc-transport-http': 6.10.0(typescript@5.9.3) - '@solana/rpc-types': 6.10.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - '@solana/rpc@8.2.0(typescript@5.9.3)': dependencies: '@solana/errors': 8.2.0(typescript@5.9.3) @@ -2385,22 +1622,6 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/signers@6.10.0(typescript@5.9.3)': - dependencies: - '@solana/addresses': 6.10.0(typescript@5.9.3) - '@solana/codecs-core': 6.10.0(typescript@5.9.3) - '@solana/errors': 6.10.0(typescript@5.9.3) - '@solana/instructions': 6.10.0(typescript@5.9.3) - '@solana/keys': 6.10.0(typescript@5.9.3) - '@solana/nominal-types': 6.10.0(typescript@5.9.3) - '@solana/offchain-messages': 6.10.0(typescript@5.9.3) - '@solana/transaction-messages': 6.10.0(typescript@5.9.3) - '@solana/transactions': 6.10.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - '@solana/signers@8.2.0(typescript@5.9.3)': dependencies: '@solana/addresses': 8.2.0(typescript@5.9.3) @@ -2417,13 +1638,6 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/subscribable@6.10.0(typescript@5.9.3)': - dependencies: - '@solana/errors': 6.10.0(typescript@5.9.3) - '@solana/promises': 6.10.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - '@solana/subscribable@8.2.0(typescript@5.9.3)': dependencies: '@solana/errors': 8.2.0(typescript@5.9.3) @@ -2431,19 +1645,6 @@ snapshots: optionalDependencies: typescript: 5.9.3 - '@solana/sysvars@6.10.0(typescript@5.9.3)': - dependencies: - '@solana/accounts': 6.10.0(typescript@5.9.3) - '@solana/codecs-core': 6.10.0(typescript@5.9.3) - '@solana/codecs-data-structures': 6.10.0(typescript@5.9.3) - '@solana/codecs-numbers': 6.10.0(typescript@5.9.3) - '@solana/errors': 6.10.0(typescript@5.9.3) - '@solana/rpc-types': 6.10.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - '@solana/sysvars@8.2.0(typescript@5.9.3)': dependencies: '@solana/accounts': 8.2.0(typescript@5.9.3) @@ -2457,25 +1658,6 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/transaction-confirmation@6.10.0(typescript@5.9.3)': - dependencies: - '@solana/addresses': 6.10.0(typescript@5.9.3) - '@solana/codecs-strings': 6.10.0(typescript@5.9.3) - '@solana/errors': 6.10.0(typescript@5.9.3) - '@solana/keys': 6.10.0(typescript@5.9.3) - '@solana/promises': 6.10.0(typescript@5.9.3) - '@solana/rpc': 6.10.0(typescript@5.9.3) - '@solana/rpc-subscriptions': 6.10.0(typescript@5.9.3) - '@solana/rpc-types': 6.10.0(typescript@5.9.3) - '@solana/transaction-messages': 6.10.0(typescript@5.9.3) - '@solana/transactions': 6.10.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - bufferutil - - fastestsmallesttextencoderdecoder - - utf-8-validate - '@solana/transaction-confirmation@8.2.0(typescript@5.9.3)': dependencies: '@solana/addresses': 8.2.0(typescript@5.9.3) @@ -2510,22 +1692,6 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/transaction-messages@6.10.0(typescript@5.9.3)': - dependencies: - '@solana/addresses': 6.10.0(typescript@5.9.3) - '@solana/codecs-core': 6.10.0(typescript@5.9.3) - '@solana/codecs-data-structures': 6.10.0(typescript@5.9.3) - '@solana/codecs-numbers': 6.10.0(typescript@5.9.3) - '@solana/errors': 6.10.0(typescript@5.9.3) - '@solana/functional': 6.10.0(typescript@5.9.3) - '@solana/instructions': 6.10.0(typescript@5.9.3) - '@solana/nominal-types': 6.10.0(typescript@5.9.3) - '@solana/rpc-types': 6.10.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - '@solana/transaction-messages@8.2.0(typescript@5.9.3)': dependencies: '@solana/addresses': 8.2.0(typescript@5.9.3) @@ -2542,25 +1708,6 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/transactions@6.10.0(typescript@5.9.3)': - dependencies: - '@solana/addresses': 6.10.0(typescript@5.9.3) - '@solana/codecs-core': 6.10.0(typescript@5.9.3) - '@solana/codecs-data-structures': 6.10.0(typescript@5.9.3) - '@solana/codecs-numbers': 6.10.0(typescript@5.9.3) - '@solana/codecs-strings': 6.10.0(typescript@5.9.3) - '@solana/errors': 6.10.0(typescript@5.9.3) - '@solana/functional': 6.10.0(typescript@5.9.3) - '@solana/instructions': 6.10.0(typescript@5.9.3) - '@solana/keys': 6.10.0(typescript@5.9.3) - '@solana/nominal-types': 6.10.0(typescript@5.9.3) - '@solana/rpc-types': 6.10.0(typescript@5.9.3) - '@solana/transaction-messages': 6.10.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - '@solana/transactions@8.2.0(typescript@5.9.3)': dependencies: '@solana/addresses': 8.2.0(typescript@5.9.3) diff --git a/programs/settlement/idl/package.json b/programs/settlement/idl/package.json index 1c65c58..2976855 100644 --- a/programs/settlement/idl/package.json +++ b/programs/settlement/idl/package.json @@ -9,7 +9,7 @@ "keywords": [], "author": "", "license": "MIT OR Apache-2.0", - "packageManager": "pnpm@10.30.3", + "packageManager": "pnpm@11.25.0", "dependencies": { "@codama/nodes-from-anchor": "^1.5.2", "@codama/renderers-js": "^2.3.0", From 5855be9383daeeadbe894ab0cbac8c059073179a Mon Sep 17 00:00:00 2001 From: Kaze <230549489+kaze-cow@users.noreply.github.com> Date: Wed, 2 Sep 2026 16:59:50 +0900 Subject: [PATCH 34/43] final cleanups by removing unnecessary lines --- programs/settlement/idl/client/js/package.json | 2 -- programs/settlement/idl/package.json | 3 --- 2 files changed, 5 deletions(-) diff --git a/programs/settlement/idl/client/js/package.json b/programs/settlement/idl/client/js/package.json index 059c7ed..6191491 100644 --- a/programs/settlement/idl/client/js/package.json +++ b/programs/settlement/idl/client/js/package.json @@ -14,8 +14,6 @@ "scripts": { "test": "vitest run" }, - "keywords": [], - "author": "CoW ", "peerDependencies": { "@solana/kit": "^6.10.0" }, diff --git a/programs/settlement/idl/package.json b/programs/settlement/idl/package.json index 2976855..85bf28b 100644 --- a/programs/settlement/idl/package.json +++ b/programs/settlement/idl/package.json @@ -1,13 +1,10 @@ { "name": "idl", "version": "1.0.0", - "description": "", "private": true, "scripts": { "generate": "node generate.mjs" }, - "keywords": [], - "author": "", "license": "MIT OR Apache-2.0", "packageManager": "pnpm@11.25.0", "dependencies": { From 5ca9842aa0f1f99ed57e8d14d21a829a7f9af01e Mon Sep 17 00:00:00 2001 From: Kaze <230549489+kaze-cow@users.noreply.github.com> Date: Wed, 2 Sep 2026 17:02:20 +0900 Subject: [PATCH 35/43] Update programs/settlement/idl/package.json Co-authored-by: Federico Giacon <58218759+fedgiac@users.noreply.github.com> --- programs/settlement/idl/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/programs/settlement/idl/package.json b/programs/settlement/idl/package.json index 85bf28b..bbf2b20 100644 --- a/programs/settlement/idl/package.json +++ b/programs/settlement/idl/package.json @@ -1,5 +1,5 @@ { - "name": "idl", + "name": "@cowprotocol/solana-program-idl-generation", "version": "1.0.0", "private": true, "scripts": { From c9d9cb681c65edcd40acbb945310e6a6e17dedaa Mon Sep 17 00:00:00 2001 From: Kaze <230549489+kaze-cow@users.noreply.github.com> Date: Wed, 2 Sep 2026 19:37:01 +0900 Subject: [PATCH 36/43] add order pda test --- .../idl/client/js/tests/orderPda.test.ts | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 programs/settlement/idl/client/js/tests/orderPda.test.ts diff --git a/programs/settlement/idl/client/js/tests/orderPda.test.ts b/programs/settlement/idl/client/js/tests/orderPda.test.ts new file mode 100644 index 0000000..bdc1485 --- /dev/null +++ b/programs/settlement/idl/client/js/tests/orderPda.test.ts @@ -0,0 +1,46 @@ +import { describe, expect, it } from "vitest"; +import { getAddressDecoder } from "@solana/kit"; +import { + getOrderIntentEncoder, + OrderKind, + type OrderIntentArgs, +} from "../src/generated"; +import { encodeFlags } from "../src/order"; + +const address = (byte: number) => + getAddressDecoder().decode(new Uint8Array(32).fill(byte)); + +// Same as used in Rust (interface/src/data/intent.rs) +const SAMPLE_INTENT: OrderIntentArgs = { + owner: address(0x11), + buyTokenAccount: address(0x22), + buyMint: address(0x33), + sellTokenAccount: address(0x44), + sellMint: address(0x55), + sellAmount: 0x0123_4567_89ab_cdefn, + buyAmount: 0xfedc_ba98_7654_3210n, + validTo: 0xdead_beef, + flags: encodeFlags({ + createdOnChain: true, + kind: OrderKind.Buy, + partiallyFillable: true, + }), + appData: new Uint8Array(32).fill(0x66), +}; + +// `uid_digest_regression` in interface/src/data/intent.rs. +const SAMPLE_UID = + "de4096c6c100056f1e4636ea4fafefad40fc1d0b37692fe3ca1e0db3644b86bd"; + +const hex = (bytes: Uint8Array) => + Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join(""); + +describe("resolveOrderPda", () => { + it("hashes the intent to the UID the program derives", async () => { + const digest = await crypto.subtle.digest( + "SHA-256", + getOrderIntentEncoder().encode(SAMPLE_INTENT), + ); + expect(hex(new Uint8Array(digest))).toBe(SAMPLE_UID); + }); +}); From e4af21b6e40f479d7a636f558417cae2d4cd3a10 Mon Sep 17 00:00:00 2001 From: Denis Makarov Date: Wed, 2 Sep 2026 17:07:23 +0400 Subject: [PATCH 37/43] feat: add automatic action trigger --- .github/workflows/auto-release.yml | 109 +++++++++++++++++++++++++++++ .github/workflows/publish-npm.yml | 46 ++++++++++-- README.md | 8 +-- 3 files changed, 154 insertions(+), 9 deletions(-) create mode 100644 .github/workflows/auto-release.yml diff --git a/.github/workflows/auto-release.yml b/.github/workflows/auto-release.yml new file mode 100644 index 0000000..1ee67cc --- /dev/null +++ b/.github/workflows/auto-release.yml @@ -0,0 +1,109 @@ +name: Auto-create release on version bump + +# Watches pushes to main for a change to the workspace version in Cargo.toml +# (the dedicated "bump version" PR from README.md's release flow). When it +# changes, this automatically cuts the GitHub Release that publish-npm.yml +# listens for, so merging the bump PR is the only manual step left before a +# release goes out (npm publish itself still needs manual approval, see +# publish-npm.yml's npm-publish environment). +on: + push: + branches: [main] + +permissions: + contents: write + actions: write # to dispatch publish-npm.yml, see the note on the "Create release" step + +jobs: + auto-release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 + with: + fetch-depth: 0 + + - name: Detect version bump + id: detect + run: | + # All-zeros `before` shows up on branch creation/force-push; there's + # no meaningful "previous version" to diff against, so skip. + if [ "${{ github.event.before }}" = "0000000000000000000000000000000000000000" ]; then + echo "changed=false" >> "$GITHUB_OUTPUT" + exit 0 + fi + + old_version=$(git show "${{ github.event.before }}:Cargo.toml" 2>/dev/null | grep -m1 '^version = ' | sed -E 's/version = "(.*)"/\1/') || true + new_version=$(grep -m1 '^version = ' Cargo.toml | sed -E 's/version = "(.*)"/\1/') + + if [ -z "$new_version" ] || [ "$old_version" = "$new_version" ]; then + echo "changed=false" >> "$GITHUB_OUTPUT" + exit 0 + fi + + # Fail before creating anything if the bump PR forgot the npm package. + # Catching this here means no release/tag ever gets created against + # this commit — checking only after publish-npm.yml runs would leave + # a broken, immutable tag pinned to a commit that can never actually + # publish (a follow-up commit fixing just package.json wouldn't + # re-trigger this workflow, since it only watches Cargo.toml). + npm_version=$(node -p 'require("./programs/settlement/idl/client/js/package.json").version') + if [ "$new_version" != "$npm_version" ]; then + echo "::error::Cargo version $new_version does not match npm version $npm_version in programs/settlement/idl/client/js/package.json. Bump both together before merging." >&2 + exit 1 + fi + + echo "changed=true" >> "$GITHUB_OUTPUT" + echo "version=$new_version" >> "$GITHUB_OUTPUT" + + - name: Check for existing release + id: check + if: steps.detect.outputs.changed == 'true' + env: + GH_TOKEN: ${{ github.token }} + VERSION: ${{ steps.detect.outputs.version }} + run: | + tag="v$VERSION" + if gh release view "$tag" >/dev/null 2>&1; then + echo "exists=true" >> "$GITHUB_OUTPUT" + else + echo "exists=false" >> "$GITHUB_OUTPUT" + fi + + - name: Create release + if: steps.detect.outputs.changed == 'true' && steps.check.outputs.exists == 'false' + env: + GH_TOKEN: ${{ github.token }} + VERSION: ${{ steps.detect.outputs.version }} + run: | + tag="v$VERSION" + # --target pins the release to the exact commit this run is for, not + # whatever main's tip happens to be when this step runs — otherwise a + # commit landing on main mid-run could get tagged/published instead. + gh release create "$tag" \ + --target "$GITHUB_SHA" \ + --title "Alpha release, $tag" \ + --generate-notes + + # A separate, unconditional-on-"just created" step: if a previous run + # created the release but failed before dispatching (e.g. a transient + # API error), re-running this job must still retry the dispatch instead + # of short-circuiting on "release already exists". + - name: Dispatch publish workflow + if: steps.detect.outputs.changed == 'true' + env: + GH_TOKEN: ${{ github.token }} + VERSION: ${{ steps.detect.outputs.version }} + run: | + tag="v$VERSION" + # GitHub suppresses the `release` event when the resource that triggers + # it (this release) was itself created using GITHUB_TOKEN — otherwise + # this would recurse. That means publish-npm.yml's `release: published` + # trigger will NOT fire for a release created here. + # https://docs.github.com/en/actions/concepts/security/github_token + # So dispatch it explicitly instead of relying on that event. + # + # Dispatch against the tag itself, not `main`: the tag is immutable and + # points at $GITHUB_SHA above, whereas `main` can move between this line + # running and the dispatched run's checkout, which would silently build + # and (pending approval) publish a different, unreviewed commit. + gh workflow run publish-npm.yml --ref "$tag" -f tag="$tag" diff --git a/.github/workflows/publish-npm.yml b/.github/workflows/publish-npm.yml index a99cac0..86bc384 100644 --- a/.github/workflows/publish-npm.yml +++ b/.github/workflows/publish-npm.yml @@ -4,16 +4,33 @@ on: release: types: [published] workflow_dispatch: + inputs: + tag: + description: >- + Release tag to publish (e.g. v0.4.0). Set automatically when + auto-release.yml dispatches this workflow (GITHUB_TOKEN-created + releases don't fire the `release` event, so it can't rely on that + trigger — see https://docs.github.com/en/actions/concepts/security/github_token). + Leave empty for a manual build-only dry run (skips the tag/version check). + required: false jobs: build: runs-on: ubuntu-latest + permissions: + contents: read # to look up releases in the "Version must match the release tag" step outputs: package-name: ${{ steps.pkg.outputs.name }} package-version: ${{ steps.pkg.outputs.version }} steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 with: + # A manual dispatch could pass --ref main while also supplying an + # unrelated existing release's tag as input; without this, the tag + # would pass the version check below while the build actually ran + # against whatever `main` happens to be, not the released commit. + # Pinning to the tag input (when present) makes that impossible. + ref: ${{ github.event.inputs.tag || github.ref }} persist-credentials: false - uses: ./.github/actions/setup-solana @@ -44,17 +61,34 @@ jobs: echo "version=$(node -p 'require("./package.json").version')" >> "$GITHUB_OUTPUT" - name: Version must match the release tag - if: github.event_name == 'release' + if: github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && github.event.inputs.tag != '') working-directory: programs/settlement/idl/client/js + env: + GH_TOKEN: ${{ github.token }} run: | + # Real `release` events carry the tag as the ref; a dispatch from + # auto-release.yml (see its comment on why it can't use the `release` + # trigger) passes it as an explicit input instead. That input is + # free text from whoever ran the dispatch, so unlike the `release` + # case it isn't proof a real release exists — confirm one does, + # rather than only checking it's self-consistent with package.json. + if [ "${{ github.event_name }}" = "release" ]; then + raw_tag="$GITHUB_REF_NAME" + else + raw_tag="${{ github.event.inputs.tag }}" + if ! gh release view "$raw_tag" >/dev/null 2>&1; then + echo "::error::No release named $raw_tag exists. Refusing to publish against a tag that wasn't actually released." >&2 + exit 1 + fi + fi # Existing tags (v0.2, v0.3) are major.minor only, while npm/Cargo need # full semver (0.3.0), so pad any missing patch component before comparing. - tag="${GITHUB_REF_NAME#v}" + tag="${raw_tag#v}" IFS='.' read -r major minor patch <<< "$tag" normalized_tag="${major}.${minor:-0}.${patch:-0}" pkg_version="${{ steps.pkg.outputs.version }}" if [ "$normalized_tag" != "$pkg_version" ]; then - echo "::error::Release tag $GITHUB_REF_NAME (normalized: $normalized_tag) does not match package.json version $pkg_version. Bump programs/settlement/idl/client/js/package.json's version as part of the release PR before publishing." >&2 + echo "::error::Release tag $raw_tag (normalized: $normalized_tag) does not match package.json version $pkg_version. Bump programs/settlement/idl/client/js/package.json's version as part of the release PR before publishing." >&2 exit 1 fi @@ -67,7 +101,7 @@ jobs: echo "Before approving, confirm:" echo "1. The tarball contents below only include expected files (no stray secrets, keys, or debug output)." echo "2. The dependency diff below has no unexpected new/changed packages." - echo "3. Package \`${{ steps.pkg.outputs.name }}\` is being published at version \`${{ steps.pkg.outputs.version }}\`, matching release \`${{ github.event.release.tag_name || github.ref_name }}\`." + echo "3. Package \`${{ steps.pkg.outputs.name }}\` is being published at version \`${{ steps.pkg.outputs.version }}\`, matching release \`${{ github.event.release.tag_name || github.event.inputs.tag || github.ref_name }}\`." echo echo "### Tarball contents (\`npm pack --dry-run --ignore-scripts\`)" echo '```' @@ -110,6 +144,10 @@ jobs: publish: needs: build + # A workflow_dispatch with an empty `tag` is documented as a build-only dry + # run (skips the version check above) — it must not be able to reach an + # actual `npm publish` just because someone approves the environment gate. + if: github.event_name == 'release' || github.event.inputs.tag != '' runs-on: ubuntu-latest # Configure this environment in repo Settings > Environments with required # reviewers: whoever approves is confirming the checklist in the `build` diff --git a/README.md b/README.md index 3667c80..5414151 100644 --- a/README.md +++ b/README.md @@ -111,7 +111,7 @@ cargo publish ### Publishing the npm package -The TS/JS client (`@cowprotocol/solana-settlement-client`, generated from `programs/settlement/idl/cow_settlement.json` via Codama) is published automatically by [`publish-npm.yml`](.github/workflows/publish-npm.yml) whenever a GitHub release is cut — its version must already match the release tag (see [Bumping the crate version](#bumping-the-crate-version), which bumps it alongside the crates). +The TS/JS client (`@cowprotocol/solana-settlement-client`, generated from `programs/settlement/idl/cow_settlement.json` via Codama) is published automatically by [`publish-npm.yml`](.github/workflows/publish-npm.yml) whenever a GitHub release is cut — its version must already match the release tag (see [Bumping the crate version](#bumping-the-crate-version), which bumps it alongside the crates). The release itself is also created automatically, by [`auto-release.yml`](.github/workflows/auto-release.yml), as soon as a version-bump PR merges into `main` — see the [Breaking change](#breaking-change) and [Patch update](#patch-update) flows above. Merging the bump PR is the only manual step left before a release goes out; npm publishing still needs manual approval (below). Publishing itself requires a manual approval in the `npm-publish` GitHub Environment. Before approving, check the job summary the workflow posts: it lists the exact tarball contents about to be published and a dependency diff against the previously published version. Approve only if both look as expected for the changes in this release. @@ -144,19 +144,17 @@ You can use the settle CLI for a smoke test of the programs after a release. See - [Deploy the programs](#how-to-deploy). The deployer keypair is in 1password (under "Solana Deployer"). The program keypair file is the key that was generated before. - Authorize all [currently existing solver](https://app.notion.com/p/cownation/Solvers-for-Solana-Dev-Contracts-3ca8da5f04ca80968642e85640178cbd) using the solver CLI (`cow solver add --help`). - Make sure the package installs without errors: run `cargo install --path /mnt/lima-solana/repos/solana-programs/solana-program-workbench/test-cli --locked` (it depends on all other packages). -- Create a PR with the changes and wait for approval. +- Create a PR with the changes and wait for approval, then merge it. Merging automatically creates a GitHub release (tag `v$VERSION`, e.g. `v0.42.0`) via [`auto-release.yml`](.github/workflows/auto-release.yml), which in turn triggers the npm package publish workflow — see [Publishing the npm package](#publishing-the-npm-package). - [Publish the cargo packages](#publishing-the-cargo-packages). -- Create a [new GitHub release](https://github.com/cowprotocol/solana-programs/releases/new); in doing so, create a new tag like `v0.42`; title "Alpha release, v0.42". This is also what triggers the npm package publish workflow — see [Publishing the npm package](#publishing-the-npm-package). ### Patch update - Check out the `main` branch. Make sure there are no local changes (`git status --porcelain` is empty). - [Bump the crate version](#bumping-the-crate-version) by a patch version. - Commit the code changes resulting from the changes above. -- Create a PR with the changes and wait for approval. +- Create a PR with the changes and wait for approval, then merge it. Merging automatically creates a GitHub release (tag `v$VERSION`, e.g. `v0.42.1`) via [`auto-release.yml`](.github/workflows/auto-release.yml), which in turn triggers the npm package publish workflow — see [Publishing the npm package](#publishing-the-npm-package). - [Update the programs](#how-to-deploy). The deployer keypair and the program keypair are in 1password (stored respectively under "Solana Deployer" and "Settlement account by version"). - [Publish the cargo packages](#publishing-the-cargo-packages). -- Create a [new GitHub release](https://github.com/cowprotocol/solana-programs/releases/new); in doing so, create a new tag including the patch number, like `v0.42.1` (unlike breaking-change releases, the patch digit here is non-zero, so it must be included to avoid colliding with the `v0.42` tag); title "Alpha release, v0.42.1". This is also what triggers the npm package publish workflow — see [Publishing the npm package](#publishing-the-npm-package). ### Bumping the crate version From a010d89f725f45515f86f88539e37c70bdc832a7 Mon Sep 17 00:00:00 2001 From: Denis Makarov Date: Wed, 2 Sep 2026 22:51:33 +0400 Subject: [PATCH 38/43] feat: use Trusted publisher approach to publish packages --- .github/workflows/publish-npm.yml | 19 ++++++++++++++++--- README.md | 2 ++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/.github/workflows/publish-npm.yml b/.github/workflows/publish-npm.yml index 950a94c..e6db5a2 100644 --- a/.github/workflows/publish-npm.yml +++ b/.github/workflows/publish-npm.yml @@ -168,11 +168,24 @@ jobs: node-version: 22 registry-url: https://registry.npmjs.org + # Trusted Publishing (OIDC) needs npm >= 11.5.1; the default bundled + # with actions/setup-node's Node 22 build can be older. + # https://docs.npmjs.com/trusted-publishers + - name: Upgrade npm for Trusted Publishing + run: npm install -g npm@~11.10.0 # pinned like cow-sdk's release workflow, see https://github.com/npm/cli/issues/9151 + - name: Publish ${{ needs.build.outputs.package-name }}@${{ needs.build.outputs.package-version }} working-directory: package - # --ignore-scripts: the artifact was already built and reviewed in the `build` - # job; no lifecycle script should run at this point with access to NPM_TOKEN - # or a chance to alter dist after it's been reviewed. + # No NODE_AUTH_TOKEN here on purpose: with `id-token: write` above and + # this package's npmjs.com Trusted Publisher configured for this repo + + # workflow + environment, npm authenticates via OIDC, no stored secret + # needed. NPM_TOKEN is a bootstrap-only fallback for the very first + # publish, before a Trusted Publisher can be configured (that requires + # the package to already exist on the registry) — once that's set up, + # delete the NPM_TOKEN secret; this step needs no other change. + # --ignore-scripts: the artifact was already built and reviewed in the + # `build` job; no lifecycle script should run at this point with a + # chance to alter dist after it's been reviewed. run: npm publish --provenance --access public --ignore-scripts env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/README.md b/README.md index 9ff3c53..e51bf1f 100644 --- a/README.md +++ b/README.md @@ -131,6 +131,8 @@ The TS/JS client (`@cowprotocol/solana-settlement-client`, generated from `progr Publishing itself requires a manual approval in the `npm-publish` GitHub Environment. Before approving, check the job summary the workflow posts: it lists the exact tarball contents about to be published and a dependency diff against the previously published version. Approve only if both look as expected for the changes in this release. +Authentication to npm uses [Trusted Publishing](https://docs.npmjs.com/trusted-publishers) (OIDC) — no long-lived npm token is stored. This requires a one-time setup on npmjs.com *after* the package's first publish (a Trusted Publisher is configured on the package's own settings page, so it can't be set up before the package exists): add a Trusted Publisher for this exact repo, `publish-npm.yml`, and the `npm-publish` environment, then delete the `NPM_TOKEN` secret — it's a bootstrap-only fallback for that first publish. + ### Devnet example ```sh From f797e2668aa32300bf608287161dc0110194e54d Mon Sep 17 00:00:00 2001 From: Denis Makarov Date: Wed, 2 Sep 2026 23:58:37 +0400 Subject: [PATCH 39/43] fix: use esbuild --- programs/settlement/idl/client/js/pnpm-workspace.yaml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 programs/settlement/idl/client/js/pnpm-workspace.yaml diff --git a/programs/settlement/idl/client/js/pnpm-workspace.yaml b/programs/settlement/idl/client/js/pnpm-workspace.yaml new file mode 100644 index 0000000..5ed0b5a --- /dev/null +++ b/programs/settlement/idl/client/js/pnpm-workspace.yaml @@ -0,0 +1,2 @@ +allowBuilds: + esbuild: true From 3e7b018fd3ec8e13c49a7d56ef643a5976cea158 Mon Sep 17 00:00:00 2001 From: Denis Makarov Date: Thu, 3 Sep 2026 00:30:39 +0400 Subject: [PATCH 40/43] chore: use the same pined v7 sha for action/checkout --- .github/workflows/auto-release.yml | 2 +- .github/workflows/publish-npm.yml | 12 +++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/.github/workflows/auto-release.yml b/.github/workflows/auto-release.yml index 1ee67cc..863d4f5 100644 --- a/.github/workflows/auto-release.yml +++ b/.github/workflows/auto-release.yml @@ -18,7 +18,7 @@ jobs: auto-release: runs-on: ubuntu-latest steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: fetch-depth: 0 diff --git a/.github/workflows/publish-npm.yml b/.github/workflows/publish-npm.yml index e6db5a2..81af8b5 100644 --- a/.github/workflows/publish-npm.yml +++ b/.github/workflows/publish-npm.yml @@ -23,7 +23,7 @@ jobs: package-name: ${{ steps.pkg.outputs.name }} package-version: ${{ steps.pkg.outputs.version }} steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: # A manual dispatch could pass --ref main while also supplying an # unrelated existing release's tag as input; without this, the tag @@ -183,6 +183,16 @@ jobs: # publish, before a Trusted Publisher can be configured (that requires # the package to already exist on the registry) — once that's set up, # delete the NPM_TOKEN secret; this step needs no other change. + # + # Safe either way, including once NPM_TOKEN is deleted and this + # resolves to an empty string: npm's `publish` command always attempts + # OIDC first and unconditionally, before checking for any configured + # token, overwriting it on success (npm/cli lib/commands/publish.js + # calls oidc() right before reading getCredentialsByURI; lib/utils/oidc.js + # does config.set(authTokenKey, ...) when the exchange succeeds). The + # pre-configured token is only ever a fallback for when OIDC isn't + # available or the exchange fails — exactly the bootstrap-publish case, + # before this package has a Trusted Publisher configured. # --ignore-scripts: the artifact was already built and reviewed in the # `build` job; no lifecycle script should run at this point with a # chance to alter dist after it's been reviewed. From a1438eec2aa4d539609b77485447d35132698903 Mon Sep 17 00:00:00 2001 From: Denis Makarov Date: Sun, 6 Sep 2026 21:06:39 +0400 Subject: [PATCH 41/43] feat: address review comments --- .github/workflows/ci.yml | 15 +-- .github/workflows/publish-npm.yml | 123 +++++------------- README.md | 6 +- programs/settlement/idl/client/js/README.md | 24 ++++ .../settlement/idl/client/js/package.json | 5 +- .../idl/client/js/scripts/publish-summary.sh | 51 ++++++++ 6 files changed, 120 insertions(+), 104 deletions(-) create mode 100644 programs/settlement/idl/client/js/README.md create mode 100755 programs/settlement/idl/client/js/scripts/publish-summary.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4387379..c6dfbdf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -45,6 +45,10 @@ jobs: test-js-client: runs-on: ubuntu-latest + # Corepack otherwise asks for confirmation before fetching pnpm, which + # would hang the job. + env: + COREPACK_ENABLE_DOWNLOAD_PROMPT: "0" steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: @@ -57,20 +61,11 @@ jobs: - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: - # Bump to upgrade. Releases: https://github.com/nodejs/node/releases - # Node ships corepack, which `just test-js-client` uses to run the pnpm - # version the packages pin — so pnpm needs no separate setup step here. - node-version: "24" + node-version: "24" # Node ships corepack, which just build-js-client/test-js-client use - name: Build JS client - # Corepack otherwise asks for confirmation before fetching pnpm, which - # would hang the job. - env: - COREPACK_ENABLE_DOWNLOAD_PROMPT: "0" run: just build-js-client - name: Test JS client - env: - COREPACK_ENABLE_DOWNLOAD_PROMPT: "0" run: just test-js-client fmt-check: diff --git a/.github/workflows/publish-npm.yml b/.github/workflows/publish-npm.yml index 81af8b5..eda4d98 100644 --- a/.github/workflows/publish-npm.yml +++ b/.github/workflows/publish-npm.yml @@ -18,7 +18,11 @@ jobs: build: runs-on: ubuntu-latest permissions: - contents: read # to look up releases in the "Version must match the release tag" step + contents: read # to look up releases in the "Cargo and npm versions must match" step + # Corepack otherwise asks for confirmation before fetching pnpm, which + # would hang the job. + env: + COREPACK_ENABLE_DOWNLOAD_PROMPT: "0" outputs: package-name: ${{ steps.pkg.outputs.name }} package-version: ${{ steps.pkg.outputs.version }} @@ -39,20 +43,11 @@ jobs: - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: - # Matches ci.yml's test-js-client job: Node ships corepack, which - # `just build-js-client`/`test-js-client` use to run the pnpm version - # the packages pin, so pnpm needs no separate setup step here. - node-version: "24" + node-version: "24" # matches ci.yml's test-js-client job - name: Build JS client - # Corepack otherwise asks for confirmation before fetching pnpm, which - # would hang the job. - env: - COREPACK_ENABLE_DOWNLOAD_PROMPT: "0" run: just build-js-client - name: Test JS client - env: - COREPACK_ENABLE_DOWNLOAD_PROMPT: "0" run: just test-js-client - name: Read package metadata @@ -62,80 +57,44 @@ jobs: echo "name=$(node -p 'require("./package.json").name')" >> "$GITHUB_OUTPUT" echo "version=$(node -p 'require("./package.json").version')" >> "$GITHUB_OUTPUT" - - name: Version must match the release tag + - name: Release tag, Cargo.toml, and package.json versions must all match if: github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && github.event.inputs.tag != '') working-directory: programs/settlement/idl/client/js env: GH_TOKEN: ${{ github.token }} run: | # Real `release` events carry the tag as the ref; a dispatch from - # auto-release.yml (see its comment on why it can't use the `release` - # trigger) passes it as an explicit input instead. That input is - # free text from whoever ran the dispatch, so unlike the `release` - # case it isn't proof a real release exists — confirm one does, - # rather than only checking it's self-consistent with package.json. + # auto-release.yml passes it as an explicit input instead. That + # input is free text from whoever ran the dispatch, so unlike the + # `release` case it isn't proof a real release exists — confirm one + # does, rather than only checking it's self-consistent otherwise. if [ "${{ github.event_name }}" = "release" ]; then raw_tag="$GITHUB_REF_NAME" else raw_tag="${{ github.event.inputs.tag }}" if ! gh release view "$raw_tag" >/dev/null 2>&1; then - echo "::error::No release named $raw_tag exists. Refusing to publish against a tag that wasn't actually released." >&2 + echo "::error::No release named $raw_tag exists." >&2 exit 1 fi fi - # Existing tags (v0.2, v0.3) are major.minor only, while npm/Cargo need - # full semver (0.3.0), so pad any missing patch component before comparing. + + # Existing tags (v0.2, v0.3) are major.minor only, while npm/Cargo + # need full semver (0.3.0), so pad any missing patch component. tag="${raw_tag#v}" IFS='.' read -r major minor patch <<< "$tag" normalized_tag="${major}.${minor:-0}.${patch:-0}" + + cargo_version=$(grep -m1 '^version = ' ../../../../../Cargo.toml | sed -E 's/version = "(.*)"/\1/') pkg_version="${{ steps.pkg.outputs.version }}" - if [ "$normalized_tag" != "$pkg_version" ]; then - echo "::error::Release tag $raw_tag (normalized: $normalized_tag) does not match package.json version $pkg_version. Bump programs/settlement/idl/client/js/package.json's version as part of the release PR before publishing." >&2 + + if [ "$normalized_tag" != "$cargo_version" ] || [ "$cargo_version" != "$pkg_version" ]; then + echo "::error::Version mismatch — release tag $raw_tag (normalized $normalized_tag), Cargo.toml $cargo_version, package.json $pkg_version must all match." >&2 exit 1 fi - name: Write publish summary working-directory: programs/settlement/idl/client/js - run: | - { - echo "## npm publish review" - echo - echo "Before approving, confirm:" - echo "1. The tarball contents below only include expected files (no stray secrets, keys, or debug output)." - echo "2. The dependency diff below has no unexpected new/changed packages." - echo "3. Package \`${{ steps.pkg.outputs.name }}\` is being published at version \`${{ steps.pkg.outputs.version }}\`, matching release \`${{ github.event.release.tag_name || github.event.inputs.tag || github.ref_name }}\`." - echo - echo "### Tarball contents (\`npm pack --dry-run --ignore-scripts\`)" - echo '```' - npm pack --dry-run --ignore-scripts 2>&1 - echo '```' - echo - echo "### Dependency diff vs. previously published version" - name="${{ steps.pkg.outputs.name }}" - view_err=$(mktemp) - if ! npm view "$name" version >/dev/null 2>"$view_err"; then - if grep -q "code E404" "$view_err"; then - echo "_First publish of this package — nothing to diff against._" - else - echo "::error::Failed to look up $name on the npm registry (not a 404 — could be auth, network, or an outage). Refusing to treat this as a first publish." >&2 - cat "$view_err" >&2 - exit 1 - fi - else - prev_deps_json=$(npm view "$name" dependencies --json 2>/dev/null); [ -z "$prev_deps_json" ] && prev_deps_json='null' - prev_peer_json=$(npm view "$name" peerDependencies --json 2>/dev/null); [ -z "$prev_peer_json" ] && prev_peer_json='null' - node -e ' - const fs = require("fs"); - const [prevDeps, prevPeer] = process.argv.slice(1).map((s) => JSON.parse(s)); - const curr = require("./package.json"); - fs.writeFileSync("/tmp/prev-deps.json", JSON.stringify({dependencies: prevDeps, peerDependencies: prevPeer}, null, 2) + "\n"); - fs.writeFileSync("/tmp/curr-deps.json", JSON.stringify({dependencies: curr.dependencies ?? null, peerDependencies: curr.peerDependencies ?? null}, null, 2) + "\n"); - ' "$prev_deps_json" "$prev_peer_json" - echo '```diff' - diff -u /tmp/prev-deps.json /tmp/curr-deps.json || true - echo '```' - fi - } >> "$GITHUB_STEP_SUMMARY" + run: ./scripts/publish-summary.sh "${{ github.event.release.tag_name || github.event.inputs.tag || github.ref_name }}" >> "$GITHUB_STEP_SUMMARY" - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: @@ -143,6 +102,7 @@ jobs: path: | programs/settlement/idl/client/js/dist programs/settlement/idl/client/js/package.json + programs/settlement/idl/client/js/README.md publish: needs: build @@ -151,9 +111,8 @@ jobs: # actual `npm publish` just because someone approves the environment gate. if: github.event_name == 'release' || github.event.inputs.tag != '' runs-on: ubuntu-latest - # Configure this environment in repo Settings > Environments with required - # reviewers: whoever approves is confirming the checklist in the `build` - # job's step summary, not just that CI is green. + # See README.md's "Publishing the Node.js client" section for what an + # approver here should check. environment: npm-publish permissions: id-token: write # for npm provenance @@ -165,37 +124,23 @@ jobs: - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: - node-version: 22 + node-version: "24" registry-url: https://registry.npmjs.org - # Trusted Publishing (OIDC) needs npm >= 11.5.1; the default bundled - # with actions/setup-node's Node 22 build can be older. - # https://docs.npmjs.com/trusted-publishers + # Trusted Publishing (OIDC) needs npm >= 11.5.1; pinned since the bundled + # version can be older even on Node 24. - name: Upgrade npm for Trusted Publishing run: npm install -g npm@~11.10.0 # pinned like cow-sdk's release workflow, see https://github.com/npm/cli/issues/9151 - name: Publish ${{ needs.build.outputs.package-name }}@${{ needs.build.outputs.package-version }} working-directory: package - # No NODE_AUTH_TOKEN here on purpose: with `id-token: write` above and - # this package's npmjs.com Trusted Publisher configured for this repo + - # workflow + environment, npm authenticates via OIDC, no stored secret - # needed. NPM_TOKEN is a bootstrap-only fallback for the very first - # publish, before a Trusted Publisher can be configured (that requires - # the package to already exist on the registry) — once that's set up, - # delete the NPM_TOKEN secret; this step needs no other change. - # - # Safe either way, including once NPM_TOKEN is deleted and this - # resolves to an empty string: npm's `publish` command always attempts - # OIDC first and unconditionally, before checking for any configured - # token, overwriting it on success (npm/cli lib/commands/publish.js - # calls oidc() right before reading getCredentialsByURI; lib/utils/oidc.js - # does config.set(authTokenKey, ...) when the exchange succeeds). The - # pre-configured token is only ever a fallback for when OIDC isn't - # available or the exchange fails — exactly the bootstrap-publish case, - # before this package has a Trusted Publisher configured. - # --ignore-scripts: the artifact was already built and reviewed in the - # `build` job; no lifecycle script should run at this point with a - # chance to alter dist after it's been reviewed. + # NODE_AUTH_TOKEN is only a bootstrap fallback for this package's very + # first publish, before a Trusted Publisher can be configured for it + # (see README.md's "Publishing the Node.js client"). `npm publish` + # always tries OIDC first regardless, so this is safe to leave set + # even after NPM_TOKEN is deleted (it just resolves to an empty string). + # --ignore-scripts: publish exactly the artifact reviewed in `build`, + # with no lifecycle script able to run and alter it at this point. run: npm publish --provenance --access public --ignore-scripts env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/README.md b/README.md index e51bf1f..5f3d140 100644 --- a/README.md +++ b/README.md @@ -125,13 +125,13 @@ Then, all packages can published in one go: cargo publish ``` -### Publishing the npm package +### Publishing the Node.js client The TS/JS client (`@cowprotocol/solana-settlement-client`, generated from `programs/settlement/idl/cow_settlement.json` via Codama) is published automatically by [`publish-npm.yml`](.github/workflows/publish-npm.yml) whenever a GitHub release is cut — its version must already match the release tag (see [Bumping the crate version](#bumping-the-crate-version), which bumps it alongside the crates). The release itself is also created automatically, by [`auto-release.yml`](.github/workflows/auto-release.yml), as soon as a version-bump PR merges into `main` — see the [Breaking change](#breaking-change) and [Patch update](#patch-update) flows above. Merging the bump PR is the only manual step left before a release goes out; npm publishing still needs manual approval (below). -Publishing itself requires a manual approval in the `npm-publish` GitHub Environment. Before approving, check the job summary the workflow posts: it lists the exact tarball contents about to be published and a dependency diff against the previously published version. Approve only if both look as expected for the changes in this release. +Publishing requires manual approval: `publish-npm.yml`'s publish step runs under a [GitHub Environment](https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment) named `npm-publish`, configured in repo Settings → Environments with required reviewers. Before approving, check the job summary the workflow posts: it lists the exact tarball contents about to be published and a dependency diff against the previously published version. Approve only if both look as expected for the changes in this release. -Authentication to npm uses [Trusted Publishing](https://docs.npmjs.com/trusted-publishers) (OIDC) — no long-lived npm token is stored. This requires a one-time setup on npmjs.com *after* the package's first publish (a Trusted Publisher is configured on the package's own settings page, so it can't be set up before the package exists): add a Trusted Publisher for this exact repo, `publish-npm.yml`, and the `npm-publish` environment, then delete the `NPM_TOKEN` secret — it's a bootstrap-only fallback for that first publish. +Authentication to npm uses [Trusted Publishing](https://docs.npmjs.com/trusted-publishers) — no stored npm token. One-time setup after the package's *first* publish (it can't be configured before the package exists): on npmjs.com, add a Trusted Publisher for this repo, `publish-npm.yml`, and the `npm-publish` environment, then delete the `NPM_TOKEN` secret. ### Devnet example diff --git a/programs/settlement/idl/client/js/README.md b/programs/settlement/idl/client/js/README.md new file mode 100644 index 0000000..16bd410 --- /dev/null +++ b/programs/settlement/idl/client/js/README.md @@ -0,0 +1,24 @@ +# @cowprotocol/solana-settlement-client + +TypeScript/JavaScript client for the CoW Protocol Solana settlement program, generated from its IDL ([`cow_settlement.json`](../../cow_settlement.json)) via [Codama](https://github.com/codama-idl/codama), built on [`@solana/kit`](https://github.com/anza-xyz/kit). + +> [!CAUTION] +> The settlement program is a work in progress and **not ready for production use**. See the [repository README](../../../../../README.md) for details. + +## Usage + +```typescript +import { + getCreateOrderInstructionAsync, + resolveOrderPda, + OrderKind, + encodeFlags, + COW_SETTLEMENT_PROGRAM_ADDRESS, +} from "@cowprotocol/solana-settlement-client"; +``` + +See the [repository README](../../../../../README.md) and [DESIGN.md](../../../../../DESIGN.md) for the settlement program's design and this client's generation pipeline. + +## Development + +This package is generated and built from the parent repository; see its [Justfile](../../../../../Justfile) (`just generate-js-client`, `just build-js-client`, `just test-js-client`) rather than running commands directly here. diff --git a/programs/settlement/idl/client/js/package.json b/programs/settlement/idl/client/js/package.json index 881dfc8..dfad0f2 100644 --- a/programs/settlement/idl/client/js/package.json +++ b/programs/settlement/idl/client/js/package.json @@ -7,7 +7,7 @@ "main": "./dist/index.js", "types": "./dist/index.d.ts", "license": "(MIT OR Apache-2.0)", - "author": "CoW Protocol", + "author": "CoW Foundation ", "repository": { "type": "git", "url": "https://github.com/cowprotocol/solana-programs.git", @@ -17,7 +17,8 @@ "access": "public" }, "files": [ - "dist/**" + "dist/**", + "README.md" ], "scripts": { "build": "tsup src/index.ts --format esm --dts --out-dir dist", diff --git a/programs/settlement/idl/client/js/scripts/publish-summary.sh b/programs/settlement/idl/client/js/scripts/publish-summary.sh new file mode 100755 index 0000000..3ffb65d --- /dev/null +++ b/programs/settlement/idl/client/js/scripts/publish-summary.sh @@ -0,0 +1,51 @@ +#!/usr/bin/env bash +# Writes the pre-publish review checklist (tarball contents + dependency diff +# vs. the currently-published version) to stdout. Used by publish-npm.yml +# (redirected into $GITHUB_STEP_SUMMARY) but runnable locally too, from +# programs/settlement/idl/client/js, to preview what a real publish would show: +# ./scripts/publish-summary.sh [release-label] +set -euo pipefail + +name=$(node -p 'require("./package.json").name') +version=$(node -p 'require("./package.json").version') +release_label="${1:-$version (local run, no release)}" + +cat <&1) +\`\`\` + +### Dependency diff vs. previously published version +EOF + +view_err=$(mktemp) +if ! npm view "$name" version >/dev/null 2>"$view_err"; then + if grep -q "code E404" "$view_err"; then + echo "_First publish of this package — nothing to diff against._" + else + echo "::error::Failed to look up $name on the npm registry (not a 404 — could be auth, network, or an outage). Refusing to treat this as a first publish." >&2 + cat "$view_err" >&2 + exit 1 + fi +else + prev_deps_json=$(npm view "$name" dependencies --json 2>/dev/null); [ -z "$prev_deps_json" ] && prev_deps_json='null' + prev_peer_json=$(npm view "$name" peerDependencies --json 2>/dev/null); [ -z "$prev_peer_json" ] && prev_peer_json='null' + node -e ' + const fs = require("fs"); + const [prevDeps, prevPeer] = process.argv.slice(1).map((s) => JSON.parse(s)); + const curr = require("./package.json"); + fs.writeFileSync("/tmp/prev-deps.json", JSON.stringify({dependencies: prevDeps, peerDependencies: prevPeer}, null, 2) + "\n"); + fs.writeFileSync("/tmp/curr-deps.json", JSON.stringify({dependencies: curr.dependencies ?? null, peerDependencies: curr.peerDependencies ?? null}, null, 2) + "\n"); + ' "$prev_deps_json" "$prev_peer_json" + echo '```diff' + diff -u /tmp/prev-deps.json /tmp/curr-deps.json || true + echo '```' +fi From 63743d5a84bb0cb3ebb90bc5e57637dc66bccfa8 Mon Sep 17 00:00:00 2001 From: Denis Makarov Date: Sun, 6 Sep 2026 21:32:41 +0400 Subject: [PATCH 42/43] chore: simplify output --- programs/settlement/idl/client/js/scripts/publish-summary.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/programs/settlement/idl/client/js/scripts/publish-summary.sh b/programs/settlement/idl/client/js/scripts/publish-summary.sh index 3ffb65d..d28e3e8 100755 --- a/programs/settlement/idl/client/js/scripts/publish-summary.sh +++ b/programs/settlement/idl/client/js/scripts/publish-summary.sh @@ -31,7 +31,7 @@ if ! npm view "$name" version >/dev/null 2>"$view_err"; then if grep -q "code E404" "$view_err"; then echo "_First publish of this package — nothing to diff against._" else - echo "::error::Failed to look up $name on the npm registry (not a 404 — could be auth, network, or an outage). Refusing to treat this as a first publish." >&2 + echo "::error::Failed to look up $name on the npm registry (not a 404, could be auth, network, or an outage)." >&2 cat "$view_err" >&2 exit 1 fi From 588fddb6ffea53597ad389edc3ebadb72e374bdf Mon Sep 17 00:00:00 2001 From: Denis Makarov Date: Mon, 7 Sep 2026 17:21:26 +0400 Subject: [PATCH 43/43] fix: add hooks export & add example of usage & replace relative paths in links by absolute one --- programs/settlement/idl/client/js/README.md | 47 +++++++++++++++++-- .../settlement/idl/client/js/src/index.ts | 1 + 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/programs/settlement/idl/client/js/README.md b/programs/settlement/idl/client/js/README.md index 16bd410..36b9e7a 100644 --- a/programs/settlement/idl/client/js/README.md +++ b/programs/settlement/idl/client/js/README.md @@ -1,13 +1,16 @@ # @cowprotocol/solana-settlement-client -TypeScript/JavaScript client for the CoW Protocol Solana settlement program, generated from its IDL ([`cow_settlement.json`](../../cow_settlement.json)) via [Codama](https://github.com/codama-idl/codama), built on [`@solana/kit`](https://github.com/anza-xyz/kit). +TypeScript/JavaScript client for the CoW Protocol Solana settlement program, generated from its IDL ([`cow_settlement.json`](https://github.com/cowprotocol/solana-programs/blob/main/programs/settlement/idl/cow_settlement.json)) via [Codama](https://github.com/codama-idl/codama), built on [`@solana/kit`](https://github.com/anza-xyz/kit). > [!CAUTION] -> The settlement program is a work in progress and **not ready for production use**. See the [repository README](../../../../../README.md) for details. +> The settlement program is a work in progress and **not ready for production use**. See the [repository README](https://github.com/cowprotocol/solana-programs/blob/main/README.md) for details. ## Usage +Building a `createOrder` instruction: + ```typescript +import { type TransactionSigner, type Address } from "@solana/kit"; import { getCreateOrderInstructionAsync, resolveOrderPda, @@ -15,10 +18,46 @@ import { encodeFlags, COW_SETTLEMENT_PROGRAM_ADDRESS, } from "@cowprotocol/solana-settlement-client"; + +declare const owner: TransactionSigner; // e.g. from generateKeyPairSigner() or a wallet adapter +declare const buyTokenAccount: Address, buyMint: Address; +declare const sellTokenAccount: Address, sellMint: Address; + +const intent = { + owner: owner.address, + buyTokenAccount, + buyMint, + sellTokenAccount, + sellMint, + sellAmount: 1_000_000n, + buyAmount: 2_000_000n, + validTo: Math.floor(Date.now() / 1000) + 3600, + flags: encodeFlags({ createdOnChain: true, kind: OrderKind.Sell, partiallyFillable: false }), + appData: new Uint8Array(32), +}; + +// getCreateOrderInstructionAsync resolves the order PDA internally; call +// resolveOrderPda yourself only if you need the address separately, e.g. to +// fetch the resulting account after sending this instruction. It can't be +// derived with a generic PDA lookup, its seed hashes the whole intent. +const { value: orderPda } = await resolveOrderPda({ + programAddress: COW_SETTLEMENT_PROGRAM_ADDRESS, + args: { intent }, +}); + +const instruction = await getCreateOrderInstructionAsync({ + owner, + createdBy: owner, // pays the order PDA's rent; may be a different signer than owner + intent, +}); ``` -See the [repository README](../../../../../README.md) and [DESIGN.md](../../../../../DESIGN.md) for the settlement program's design and this client's generation pipeline. +From here, `instruction` is added to a transaction message and sent like any `@solana/kit` instruction (`createTransactionMessage`, `appendTransactionMessageInstruction`, sign, and send via an RPC). Every other instruction (`getAddSolverInstruction`, `getReclaimOrderInstructionAsync`, etc.) follows the same shape: build the args, get the instruction. + +If your project uses classic `@solana/web3.js` instead of `@solana/kit`, the instructions this package returns (`{ programAddress, accounts, data }`) can be converted to a `web3.TransactionInstruction` by mapping `accounts` (each `{ address, role }`, where `role` is a bitmask: bit 0 = writable, bit 1 = signer) to `web3.AccountMeta`. + +See the [repository README](https://github.com/cowprotocol/solana-programs/blob/main/README.md) and [DESIGN.md](https://github.com/cowprotocol/solana-programs/blob/main/DESIGN.md) for the settlement program's design and this client's generation pipeline. ## Development -This package is generated and built from the parent repository; see its [Justfile](../../../../../Justfile) (`just generate-js-client`, `just build-js-client`, `just test-js-client`) rather than running commands directly here. +This package is generated and built from the parent repository; see its [Justfile](https://github.com/cowprotocol/solana-programs/blob/main/Justfile) (`just generate-js-client`, `just build-js-client`, `just test-js-client`) rather than running commands directly here. diff --git a/programs/settlement/idl/client/js/src/index.ts b/programs/settlement/idl/client/js/src/index.ts index 9aafe37..da14385 100644 --- a/programs/settlement/idl/client/js/src/index.ts +++ b/programs/settlement/idl/client/js/src/index.ts @@ -1,2 +1,3 @@ export * from "./generated"; export * from "./order"; +export * from "./hooked";