diff --git a/.github/workflows/conformance.yml b/.github/workflows/conformance.yml index 75e1b21f8..65e4f305e 100644 --- a/.github/workflows/conformance.yml +++ b/.github/workflows/conformance.yml @@ -277,7 +277,7 @@ jobs: path: harness/results/ if-no-files-found: ignore - # Real on-chain settlement: forks mainnet (surfpool 1.4) and executes the + # Real on-chain settlement: forks mainnet (surfpool 1.5) and executes the # deployed payment-channels program, so a green run proves settlement lands. onchain: name: onchain diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index 0b4b98c5f..3da9f237c 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -29,6 +29,9 @@ on: permissions: contents: write id-token: write + # The called CI workflow's path-filter job reads PR metadata; a reusable + # workflow cannot request more than its caller grants (startup_failure). + pull-requests: read # Prevent concurrent publishes concurrency: diff --git a/.github/workflows/pypi-publish.yml b/.github/workflows/pypi-publish.yml index 2d02f539e..09d832e59 100644 --- a/.github/workflows/pypi-publish.yml +++ b/.github/workflows/pypi-publish.yml @@ -30,6 +30,9 @@ on: permissions: contents: write id-token: write # PyPI Trusted Publishing (OIDC) + # The called CI workflow's path-filter job reads PR metadata; a reusable + # workflow cannot request more than its caller grants (startup_failure). + pull-requests: read # Prevent concurrent publishes concurrency: diff --git a/.gitmodules b/.gitmodules index 8791df3a4..2a94027f1 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,7 +1,7 @@ [submodule "typescript/external/x402"] path = typescript/external/x402 - url = https://github.com/x402-foundation/x402.git - branch = main + url = https://github.com/solana-foundation/x402.git + branch = feat/svm-client-transaction-v1 [submodule "external/mpp-specs"] path = external/mpp-specs url = https://github.com/tempoxyz/mpp-specs.git @@ -16,3 +16,4 @@ path = external/x402-txv1 url = https://github.com/solana-foundation/x402.git shallow = true + branch = feat/svm-client-transaction-v1 diff --git a/external/x402-txv1 b/external/x402-txv1 index 3d723dd54..d411aea10 160000 --- a/external/x402-txv1 +++ b/external/x402-txv1 @@ -1 +1 @@ -Subproject commit 3d723dd54706b9edab8a33dc2c4e9cad22f35745 +Subproject commit d411aea104d17926465c91755fdfe12b0f445fc0 diff --git a/greptile.json b/greptile.json new file mode 100644 index 000000000..11af4c46b --- /dev/null +++ b/greptile.json @@ -0,0 +1,220 @@ +{ + "autoReview": [], + "strictness": 1, + "customContext": { + "rules": [ + { + "rule": "pay-kit#317 `solana-foundation/pay-kit@a58c78e:go/protocols/mpp/wire/challenge_test.go:56`: `now` was fixed at 1900, so the leap-second cases proved only that parsing succeeded, not the mapping to the last nanosecond of `:59` (https://github.com/solana-foundation/pay-kit/pull/317#discussion_r3982265139).", + "scope": [ + "**" + ] + }, + { + "rule": "pay-kit#13 `caliperforge/pay-kit@efff41c:harness/protocol-runners/kotlin.json:3`: the manifest execs an installed Gradle distribution that no CI job builds, so on a clean checkout the runner cannot start (https://github.com/caliperforge/pay-kit/pull/13#discussion_r4166253848).", + "scope": [ + "**" + ] + }, + { + "rule": "pay-kit#13 `caliperforge/pay-kit@8c59ab9:harness/test/protocol-conformance.test.ts:195`: a spawn failure, a non-zero exit or empty stdout counted as the expected divergence, so a runner that never ran looked green.", + "scope": [ + "**" + ] + }, + { + "rule": "pay-kit#13 `caliperforge/pay-kit@2291822:harness/kotlin-protocol-runner/src/main/kotlin/com/solana/paykit/protocolrunner/Main.kt:77`: decoding with unknown keys ignored silently dropped the `hash` payload of `credential_with_source` (https://github.com/caliperforge/pay-kit/pull/13#discussion_r4166253870).", + "scope": [ + "**" + ] + }, + { + "rule": "pay-kit#13 `caliperforge/pay-kit@c4341ee:harness/kotlin-protocol-runner/src/main/kotlin/com/solana/paykit/protocolrunner/Main.kt:57-66`: the same lenient decoding dropped the challenge `description` (https://github.com/caliperforge/pay-kit/pull/13#discussion_r4166253852).", + "scope": [ + "**" + ] + }, + { + "rule": "pay-kit#320 `solana-foundation/pay-kit@a55ee48:php/tests/PayCore/Rfc3339Test.php:48`: long-fraction vectors were checked with `format('c')`, which drops microseconds, so a parser that discards the fraction still passed (https://github.com/solana-foundation/pay-kit/pull/320#discussion_r3992887690).", + "scope": [ + "**" + ] + }, + { + "rule": "pay-kit#320 `solana-foundation/pay-kit@a55ee48:php/tests/PayCore/Rfc3339Test.php:88`: no case exercised the last-day-of-month rule for `23:59:60Z`, so deleting the check kept the suite green (https://github.com/solana-foundation/pay-kit/pull/320#discussion_r3992887696).", + "scope": [ + "**" + ] + }, + { + "rule": "pay-kit#340 `solana-foundation/pay-kit@b2638e1:ruby/lib/pay_kit/config.rb:271`: an empty `PAY_KIT_RPC_URL` overrode the network default with `\"\"`, unlike the Python SDK it mirrors (https://github.com/solana-foundation/pay-kit/pull/340#discussion_r4095737040).", + "scope": [ + "**" + ] + }, + { + "rule": "pay-kit#340 `solana-foundation/pay-kit@b2638e1:ruby/lib/pay_kit/config.rb:277`: a zero or negative `PAY_KIT_MPP_EXPIRES_IN` was accepted, issuing already-expired challenges, unlike the Python SDK it mirrors (https://github.com/solana-foundation/pay-kit/pull/340#discussion_r4095737053).", + "scope": [ + "**" + ] + }, + { + "rule": "pay-kit#340 `solana-foundation/pay-kit@b2638e1:ruby/lib/pay_kit/config.rb:308`: `yes`/`no`/`on`/`off` for `PAY_KIT_PREFLIGHT` raised at boot, unlike the Python SDK it mirrors (https://github.com/solana-foundation/pay-kit/pull/340#discussion_r4095737067).", + "scope": [ + "**" + ] + }, + { + "rule": "pay-kit#340 `solana-foundation/pay-kit@b2638e1:ruby/lib/pay_kit/config.rb:268`: lowercase `pay_kit_*` variables were silently ignored, unlike the Python SDK it mirrors (https://github.com/solana-foundation/pay-kit/pull/340#discussion_r4095737071).", + "scope": [ + "**" + ] + }, + { + "rule": "pay-kit#15 `caliperforge/pay-kit@1f02e55:swift/Sources/mpp-protocol-runner/main.swift:74`: `challenge.parse` dropped `description` (https://github.com/caliperforge/pay-kit/pull/15#discussion_r4173474978).", + "scope": [ + "**" + ] + }, + { + "rule": "pay-kit#15 `caliperforge/pay-kit@1f02e55:swift/Sources/mpp-protocol-runner/main.swift:97`: `credential.format` required `transaction` for `type: \"transaction\"`, so the canonical `basic_credential` vector could not be formatted (https://github.com/caliperforge/pay-kit/pull/15#discussion_r4173474983).", + "scope": [ + "**" + ] + }, + { + "rule": "pay-kit#322 `solana-foundation/pay-kit@c35533e:swift/Sources/SolanaPayKit/Protocols/Mpp/Core/Models.swift:125`: a review asked to allow leap seconds only in June and December; RFC 3339 §5.7 and Appendix D do not restrict them, the UTC month-end check matches the Rust reference, and the finding was withdrawn (https://github.com/solana-foundation/pay-kit/pull/322#discussion_r4035505691).", + "scope": [ + "**" + ] + }, + { + "rule": "pay-kit#282 `solana-foundation/pay-kit@e2f2b1d:harness/src/protocol/vectors.ts:436`: `collectExpiresCases()` had no callers, though comments said the per-language tests used it (https://github.com/solana-foundation/pay-kit/pull/282#discussion_r3751682861).", + "scope": [ + "**" + ] + }, + { + "rule": "pay-kit#282 `solana-foundation/pay-kit@faf3250:typescript/packages/mpp/src/__tests__/client-charge-validation.test.ts:449`: the test imported `../shared/rfc3339.js`, which did not exist at that SHA, so the whole file failed to load (https://github.com/solana-foundation/pay-kit/pull/282#discussion_r3960191945).", + "scope": [ + "**" + ] + }, + { + "rule": "pay-kit#282 `solana-foundation/pay-kit@faf3250:typescript/packages/mpp/src/__tests__/client-charge-validation.test.ts:478`: the loop tested only `parseRfc3339` while the production guards still used `new Date(...)` and `Date.parse`, so the tests could pass without exercising the shipped code (https://github.com/solana-foundation/pay-kit/pull/282#discussion_r3960191963).", + "scope": [ + "**" + ] + }, + { + "rule": "pay-kit#313 `solana-foundation/pay-kit@a752d51:typescript/packages/mpp/src/shared/rfc3339.ts:38`: rejected `second = 60`, which RFC 3339 allows for a positive leap second (https://github.com/solana-foundation/pay-kit/pull/313#discussion_r3962113765).", + "scope": [ + "**" + ] + }, + { + "rule": "pay-kit#14 `caliperforge/pay-kit@208fbd7:harness/test/protocol-conformance.test.ts:179`: an expectation checked only that `description` was absent, so `result: {}` would also pass (https://github.com/caliperforge/pay-kit/pull/14#discussion_r4173234527).", + "scope": [ + "**" + ] + }, + { + "rule": "pay-kit#13 `caliperforge/pay-kit@66449a5:harness/kotlin-protocol-runner/src/main/kotlin/com/solana/paykit/protocolrunner/Main.kt:66`: \"P1\" **Challenge description is dropped** When a valid header contains a top-level `description`, such as the canonical `full_challenge`, this response omits it. The parsed challenge no longer matches the expected object, and the basic-only runner test does not catch the difference. (https://github.com/caliperforge/pay-kit/pull/13#discussion_r4166253852).", + "scope": [ + "**" + ] + }, + { + "rule": "pay-kit#13 `caliperforge/pay-kit@66449a5:harness/kotlin-protocol-runner/src/main/kotlin/com/solana/paykit/protocolrunner/Main.kt:65`: \"P1\" **Plain opaque values fail parsing** The SDK treats `opaque` as a pass-through string. When a valid challenge contains a plain value such as `trace-123`, decoding it as base64url JSON throws, so the runner returns `parse_error` instead of the parsed challenge. (https://github.com/caliperforge/pay-kit/pull/13#discussion_r4166253859).", + "scope": [ + "**" + ] + }, + { + "rule": "pay-kit#13 `caliperforge/pay-kit@8c59ab9:harness/kotlin-protocol-runner/src/main/kotlin/com/solana/paykit/protocolrunner/Main.kt:77`: \"P1\" **Hash payload is lost** The canonical `credential_with_source` case contains a valid `hash` payload. This code deserializes it while ignoring unknown fields, but the Kotlin payload type has no `hash` property. Formatting then emits an Authorization header without the hash value. (https://github.com/caliperforge/pay-kit/pull/13#discussion_r4166253870).", + "scope": [ + "**" + ] + }, + { + "rule": "pay-kit#16 `caliperforge/pay-kit@00614e3:harness/kotlin-protocol-runner/src/main/kotlin/com/solana/paykit/protocolrunner/Main.kt:78`: \"P1\" **Opaque values are misparsed** When a valid Payment challenge includes `opaque`, the runner tries to decode it as base64url JSON even though the SDK and protocol adapter treat it as an opaque string. A value that is not JSON becomes a parse error; a JSON-bearing value is returned with the wrong type. (https://github.com/caliperforge/pay-kit/pull/16#discussion_r4186902439).", + "scope": [ + "**" + ] + }, + { + "rule": "pay-kit#16 `caliperforge/pay-kit@00614e3:harness/kotlin-protocol-runner/src/main/kotlin/com/solana/paykit/protocolrunner/Main.kt:85`: \"P2\" **Missing request becomes valid** If a `credential.format` input omits the required `challenge.request`, the runner inserts an empty request and can return a successful Authorization header. This hides an invalid input and produces a header that does not represent the supplied challenge. (https://github.com/caliperforge/pay-kit/pull/16#discussion_r4186902463).", + "scope": [ + "**" + ] + }, + { + "rule": "pay-kit#16 `caliperforge/pay-kit@00614e3:harness/kotlin-protocol-runner/src/main/kotlin/com/solana/paykit/protocolrunner/Main.kt:77`: \"P2\" **Empty optional values disappear** When a parsed challenge contains an explicitly empty `expires` or `digest`, these checks omit the field from the result. The adapter distinguishes a present empty value from an absent field, so the runner returns the wrong object for those headers. (https://github.com/caliperforge/pay-kit/pull/16#discussion_r4186902477).", + "scope": [ + "**" + ] + }, + { + "rule": "pay-kit#16 `caliperforge/pay-kit@00614e3:harness/kotlin-protocol-runner/src/main/kotlin/com/solana/paykit/protocolrunner/Main.kt:33`: \"P2\" **Conformance skips recognized operations** Seven recognized operations always return fixed errors, and the Kotlin divergence tests assert those responses instead of exercising protocol behavior. A green Kotlin protocol job therefore does not verify encoding, challenge generation, or those header operations. Implement them or separate these gap checks from conformance coverage. (https://github.com/caliperforge/pay-kit/pull/16#discussion_r4186902484).", + "scope": [ + "**" + ] + }, + { + "rule": "pay-kit#20 `caliperforge/pay-kit@473293a:php/src/Gate.php:136`: \"P1\" **Inherited protocol limits are ignored** When a gate has no explicit `accept` list, this method returns true for any fee-free protocol without checking `Config`. With a configuration that accepts only MPP, `gate->accepts(Protocol::X402)` therefore returns true even though the middleware excludes X402. Callers of this new public method get an admission decision that contradicts the configured protocol limit. (https://github.com/caliperforge/pay-kit/pull/20#discussion_r4188609106).", + "scope": [ + "**" + ] + }, + { + "rule": "pay-kit#18 `caliperforge/pay-kit@c94203d:php/src/Config.php:113`: \"P2\" **Blank expiry bypasses validation** If `PAY_KIT_MPP_EXPIRES_IN` is set but blank, this helper turns it into `null`. The TTL resolver then uses the 120-second default instead of rejecting the malformed value, so a mistyped setting goes unnoticed. (https://github.com/caliperforge/pay-kit/pull/18#discussion_r4188597519).", + "scope": [ + "**" + ] + }, + { + "rule": "pay-kit#18 `caliperforge/pay-kit@c94203d:php/tests/ConfigTest.php:31`: \"P2\" **Tests clear existing configuration** If the shell already has a production configuration variable set, these tests do not isolate themselves from it and `tearDown()` removes it instead of restoring it. For example, an existing `PAY_KIT_NETWORK=solana_mainnet` makes the defaults test throw because it selects mainnet with a demo signer; after cleanup, subsequent tests see a different environment. (https://github.com/caliperforge/pay-kit/pull/18#discussion_r4188597530).", + "scope": [ + "**" + ] + }, + { + "rule": "pay-kit#22 `caliperforge/pay-kit@3514734:python/tests/allowlist_generator.py:127`: \"P2\" **Token drains go untested** (https://github.com/caliperforge/pay-kit/pull/22#discussion_r4220236268).", + "scope": [ + "**" + ] + }, + { + "rule": "pay-kit#14 `caliperforge/pay-kit@17dd9a2:harness/test/protocol-conformance.test.ts:212`: \"P2\" **Formatter cases are skipped** This filter selects no successful `credential.format` vector and no `receipt.format` vector: neither operation is in `smokeOps`, and the Kotlin map has only a failing credential-format case. The credential formatter could fail every valid request without failing this suite, while the declared receipt-format gap gets no conformance check. Add a successful formatter case and track the receipt-format gap. (https://github.com/caliperforge/pay-kit/pull/14#discussion_r4173234531).", + "scope": [ + "**" + ] + }, + { + "rule": "pay-kit#14 `caliperforge/pay-kit@b976cea:harness/test/protocol-conformance.test.ts:179`: \"P2\" **Challenge fields go unchecked** For challenges with a description, this expectation checks only that `description` is absent. A response with `result: {}` would also pass, so the test would miss regressions in required challenge fields or the decoded request. Check those fields against the vector while allowing the known omission. (https://github.com/caliperforge/pay-kit/pull/14#discussion_r4173234527).", + "scope": [ + "**" + ] + }, + { + "rule": "pay-kit#18 `caliperforge/pay-kit@e227243:harness/src/artifacts.ts:48`: \"P1\" **Swift conformance build fails** The Swift conformance target builds from `swift/`, but its `Package.swift` is at the repository root. The macOS artifact build therefore cannot find the package manifest and fails before the Swift harness legs can run. (https://github.com/caliperforge/pay-kit/pull/18#discussion_r4209441653).", + "scope": [ + "**" + ] + }, + { + "rule": "pay-kit#18 `caliperforge/pay-kit@e227243:typescript/packages/mpp/src/server/Charge.ts:815`: \"P1\" **Failed sends strand payments** If `sendTransaction` fails before accepting a pull-mode payment, the replay reservation remains pending for 21 minutes. A retry of the same signed payment is rejected as already in progress; after the lease expires, recovery only checks for confirmation and never broadcasts it. A transient send failure can therefore leave a valid payment unable to complete. (https://github.com/caliperforge/pay-kit/pull/18#discussion_r4209441678).", + "scope": [ + "**" + ] + } + ], + "files": [ + { + "path": "docs/paykit-interface.md", + "scope": [ + "**" + ] + } + ] + } +} diff --git a/harness/README.md b/harness/README.md index ddb8064a9..6e5175535 100644 --- a/harness/README.md +++ b/harness/README.md @@ -107,7 +107,10 @@ cargo run -q -p paykit-conformance --bin pkc -- help ``` `pkc` judges every result itself (outcome, `rejectCode`, exact bytes, x402 -envelope shape, transaction shape) and, for every accepted build, decodes the +envelope shape, transaction shape; a vector whose spec leaves the verdict to +the implementation lists the other conformant verdicts in +`expect.alsoConformant`, see [RULINGS.md](expectations/RULINGS.md#harness-consequences)) +and, for every accepted build, decodes the built transaction, runs the Rust kit's verifier on it against the vector's request and compares its instruction multiset (program, set of accounts, data; signatures excluded, ordering free) with the kit's own build of the same case. @@ -257,12 +260,12 @@ regenerated with `pnpm coverage` and CI fails when it is stale. | --- | ---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: | | flow | 34 | — | — | — | — | — | — | — | — | 30 · 4u | | protocol | 91 | 91 | — | 91 | 91 | 91 | 91 | 91 | — | 91 | -| vector charge | 117 | 71 · 46k | — | 57 · 29u · 31k | 59 · 29u · 29k | 79 · 38k | 60 · 29u · 28k | 117 | 29 · 72u · 16k | 74 · 2u · 41k | -| vector session | 191 | 8 · 183u | 3 · 188u | — | — | 36 · 148u · 7k | — | 191 | 3 · 188u | 36 · 148u · 7k | -| vector subscription | 123 | — | — | — | — | — | — | 123 | — | 70 · 15u · 38k | -| vector x402-batch-settlement | 165 | — | — | — | — | — | — | 165 | — | 66 · 27u · 72k | -| vector x402-exact | 73 | 47 · 26k | — | 32 · 19u · 22k | 32 · 21u · 20k | 44 · 2u · 27k | 29 · 19u · 25k | 73 | 14 · 52u · 7k | 35 · 29u · 9k | -| vector x402-upto | 124 | — | — | — | — | — | — | 124 | — | 104 · 2u · 18k | +| vector charge | 117 | 71 · 46k | — | 57 · 29u · 31k | 59 · 29u · 29k | 79 · 38k | 60 · 29u · 28k | 117 | 29 · 72u · 16k | 82 · 2u · 33k | +| vector session | 192 | 8 · 184u | 3 · 189u | — | — | 36 · 149u · 7k | — | 192 | 3 · 189u | 37 · 149u · 6k | +| vector subscription | 123 | — | — | — | — | — | — | 123 | — | 97 · 15u · 11k | +| vector x402-batch-settlement | 175 | — | — | — | — | — | — | 175 | — | 134 · 35u · 6k | +| vector x402-exact | 78 | 49 · 29k | — | 34 · 21u · 23k | 34 · 23u · 21k | 46 · 2u · 30k | 30 · 21u · 27k | 78 | 14 · 55u · 9k | 66 · 9u · 3k | +| vector x402-upto | 128 | — | — | — | — | — | — | 128 | — | 121 · 4u · 3k | Each cell counts the cases that must pass, then `u` unsupported (declared, executed, must report unsupported) and `k` known failing (declared with tracking, executed, must fail). `—` means the SDK does not claim the suite. Source: `harness/expectations/.toml`. @@ -280,21 +283,21 @@ when the table is stale. | client \ server | go | lua | php | python | ruby | rust | typescript | | --- | :---: | :---: | :---: | :---: | :---: | :---: | :---: | -| go | **11**/14 | **11**/14 | **11**/14 | **11**/14 | **11**/14 | 14/14 | **11**/14 | -| python | **11**/14 | **11**/14 | **11**/14 | **11**/14 | **11**/14 | 14/14 | **11**/14 | +| go | **11**/14 | **11**/14 | **11**/14 | **11**/14 | **11**/14 | 14/14 | **12**/14 | +| python | **11**/14 | **11**/14 | **11**/14 | **11**/14 | **11**/14 | 14/14 | **12**/14 | | rust | **8**/14 | **8**/14 | **8**/14 | 14/14 | **8**/14 | 14/14 | **8**/14 | -| swift | **11**/14 | **11**/14 | **11**/14 | **11**/14 | **11**/14 | 14/14 | **11**/14 | -| typescript | **10**/13 | **10**/13 | **10**/13 | **10**/13 | **10**/13 | 13/13 | **10**/13 | +| swift | **11**/14 | **11**/14 | **11**/14 | **11**/14 | **11**/14 | 14/14 | **12**/14 | +| typescript | **10**/13 | **10**/13 | **10**/13 | **10**/13 | **10**/13 | 13/13 | **11**/13 | **x402-exact**: builds by the client SDK (rows) verified by the server SDK (columns), agreeing with the Rust judge / total. | client \ server | go | lua | php | python | ruby | rust | typescript | | --- | :---: | :---: | :---: | :---: | :---: | :---: | :---: | -| go | 15/15 | 15/15 | 15/15 | 15/15 | 15/15 | 15/15 | 10/10 · 5u | -| python | 15/15 | 15/15 | 15/15 | 15/15 | 15/15 | 15/15 | 10/10 · 5u | -| rust | **13**/15 | **13**/15 | **13**/15 | **13**/15 | **13**/15 | 15/15 | 10/10 · 5u | -| swift | 15/15 | 15/15 | 15/15 | 15/15 | 15/15 | 15/15 | 10/10 · 5u | -| typescript | 10/10 | 10/10 | 10/10 | 10/10 | 10/10 | 10/10 | 8/8 · 2u | +| go | 15/15 | 15/15 | 15/15 | 15/15 | 15/15 | 15/15 | 12/12 · 3u | +| python | 15/15 | 15/15 | 15/15 | 15/15 | 15/15 | 15/15 | 12/12 · 3u | +| rust | **13**/15 | **13**/15 | **13**/15 | **13**/15 | **13**/15 | 15/15 | 12/12 · 3u | +| swift | 15/15 | 15/15 | 15/15 | 15/15 | 15/15 | 15/15 | 12/12 · 3u | +| typescript | **9**/11 | **9**/11 | **9**/11 | **9**/11 | **9**/11 | 11/11 | 10/10 · 1u | A server agrees with a build when it accepts what the Rust judge accepted (verifier plus instruction multiset against the kit's own build) and refuses what it refused; `u` counts builds the server reports it cannot express. Disagreements are listed in `harness/results/cross.json`. @@ -314,7 +317,7 @@ files (`pkc report`; `pkc report --check` fails when stale). The counts come from the same extraction as `pkc req-lint`. -1732 normative sentences in the pinned specs: 405 mapped to a requirement, 1307 unmapped. +1896 normative sentences in the pinned specs: 416 mapped to a requirement, 1460 unmapped. | Spec file | Normative | Mapped | Ignored | Unmapped | | --- | ---: | ---: | ---: | ---: | @@ -323,20 +326,20 @@ come from the same extraction as `pkc req-lint`. | `mpp-specs/draft-payment-intent-subscription-00.md` | 44 | 2 | 0 | 42 | | `mpp-specs/draft-solana-charge-00.md` | 145 | 47 | 0 | 98 | | `mpp-specs/draft-solana-session-00.md` | 219 | 98 | 0 | 121 | -| `x402/x402-specification-v2.md` | 10 | 0 | 0 | 10 | -| `x402/scheme_exact.md` | 42 | 4 | 20 | 18 | -| `x402/scheme_exact_svm.md` | 35 | 17 | 0 | 18 | +| `x402/x402-specification-v2.md` | 11 | 0 | 0 | 11 | +| `x402/scheme_exact.md` | 53 | 4 | 20 | 29 | +| `x402/scheme_exact_svm.md` | 91 | 17 | 0 | 74 | | `x402/payment_identifier.md` | 0 | 0 | 0 | 0 | | `x402/scheme_upto.md` | 13 | 2 | 0 | 11 | -| `x402/scheme_upto_svm.md` | 87 | 42 | 0 | 45 | +| `x402/scheme_upto_svm.md` | 105 | 42 | 0 | 63 | | `x402/scheme_batch_settlement.md` | 2 | 0 | 0 | 2 | -| `x402/scheme_batch_settlement_svm.md` | 200 | 78 | 0 | 122 | +| `x402/scheme_batch_settlement_svm.md` | 223 | 82 | 0 | 141 | | `mpp-specs-solana/draft-solana-subscription-00.md` | 93 | 40 | 0 | 53 | | `mpp-specs-txv1/draft-solana-charge-00.md` | 156 | 18 | 0 | 138 | | `mpp-specs-txv1/draft-solana-session-00.md` | 229 | 12 | 0 | 217 | -| `x402-txv1/scheme_exact_svm.md` | 48 | 18 | 0 | 30 | -| `x402-txv1/scheme_upto_svm.md` | 101 | 12 | 0 | 89 | -| `x402-txv1/scheme_batch_settlement_svm.md` | 215 | 13 | 0 | 202 | +| `x402-txv1/scheme_exact_svm.md` | 91 | 21 | 0 | 70 | +| `x402-txv1/scheme_upto_svm.md` | 105 | 14 | 0 | 91 | +| `x402-txv1/scheme_batch_settlement_svm.md` | 223 | 15 | 0 | 208 | **Requirements × SDK**: cases per requirement, and per SDK the cases it must pass, then `u` unsupported and `k` known failing; `—` means the SDK claims none of them. `*` marks `required = true` (req-lint fails if its last case goes). @@ -345,7 +348,7 @@ come from the same extraction as `pkc req-lint`. | `MPP-5a84bf0d0b`* | draft-httpauth-payment-01.md § Challenge Binding | 13 | — | — | — | — | — | — | 13 | — | 2 · 11k | | `MPP-8a3cdc949b`* | draft-httpauth-payment-01.md § Challenge Binding | 5 | 5 | — | 5 | 5 | 5 | 5 | 5 | 5 | 5 | | `MPP-3688fa68c7`* | draft-payment-intent-subscription-00.md § Required Fields | 1 | — | — | — | — | — | — | 1 | — | 1 | -| `MPP-c1bffbb1a3`* | draft-payment-intent-subscription-00.md § Shared Fields | 1 | — | — | — | — | — | — | 1 | — | 0 · 1k | +| `MPP-c1bffbb1a3`* | draft-payment-intent-subscription-00.md § Shared Fields | 1 | — | — | — | — | — | — | 1 | — | 1 | | `MPP-de0815e07c`* | draft-solana-charge-00.md § Client Requirements | 5 | 5 | — | 3 · 2u | 3 · 2u | 5 | 3 · 2u | 5 | 2 · 3u | 5 | | `MPP-51806e831a`* | draft-solana-charge-00.md § Encoding Conventions | 3 | 3 | — | 3 | 3 | 3 | 3 | 3 | 3 | 3 | | `MPP-71198689c1`* | draft-solana-charge-00.md § Encoding Conventions | 5 | 5 | — | 5 | 5 | 5 | 5 | 5 | 5 | 5 | @@ -353,7 +356,7 @@ come from the same extraction as `pkc req-lint`. | `MPP-837333ec9f`* | draft-solana-charge-00.md § Fee Payer Configuration | 2 | 2 | — | 0 · 2u | 0 · 2u | 2 | 0 · 2u | 2 | 2 | 2 | | `MPP-b4a76cab12`* | draft-solana-charge-00.md § Fee Payer Configuration | 1 | 1 | — | 0 · 1u | 0 · 1u | 1 | 0 · 1u | 1 | 1 | 1 | | `MPP-1180595e82`* | draft-solana-charge-00.md § Method Details | 4 | 4 | — | 4 | 4 | 4 | 4 | 4 | 0 · 4u | 4 | -| `MPP-4b02ff0c39`* | draft-solana-charge-00.md § Method Details | 2 | 2 | — | 0 · 2u | 0 · 2u | 2 | 0 · 2u | 2 | 2 | 1 · 1k | +| `MPP-4b02ff0c39`* | draft-solana-charge-00.md § Method Details | 2 | 2 | — | 0 · 2u | 0 · 2u | 2 | 0 · 2u | 2 | 2 | 2 | | `MPP-5348f3f797`* | draft-solana-charge-00.md § Method Details | 1 | 1 | — | 0 · 1u | 0 · 1u | 1 | 0 · 1u | 1 | 1 | 1 | | `MPP-58f2b1922a`* | draft-solana-charge-00.md § Method Details | 1 | 0 · 1k | — | 0 · 1u | 0 · 1u | 0 · 1k | 0 · 1u | 1 | 1 | 1 | | `MPP-6ce505e77b`* | draft-solana-charge-00.md § Method Details | 4 | 4 | — | 4 | 4 | 4 | 4 | 4 | 0 · 4u | 4 | @@ -364,8 +367,8 @@ come from the same extraction as `pkc req-lint`. | `MPP-b134044e08`* | draft-solana-charge-00.md § Method Details | 1 | 1 | — | 0 · 1u | 0 · 1u | 1 | 0 · 1u | 1 | 1 | 1 | | `MPP-b769615b39`* | draft-solana-charge-00.md § Method Details | 2 | 0 · 2k | — | 1 · 1u | 1 · 1u | 1 · 1k | 1 · 1u | 2 | 1 · 1u | 2 | | `MPP-c189ef935e`* | draft-solana-charge-00.md § Method Details | 2 | 2 | — | 0 · 2u | 0 · 2u | 2 | 0 · 2u | 2 | 2 | 2 | -| `MPP-ec29292f9d`* | draft-solana-charge-00.md § Method Details | 2 | 0 · 1u · 1k | 0 · 1u | 0 · 1u | 0 · 1u | 0 · 1u · 1k | 0 · 1u | 2 | 0 · 1u · 1k | 0 · 1u · 1k | -| `MPP-fde6ebf8c7`* | draft-solana-charge-00.md § Method Details | 1 | 0 · 1k | — | 0 · 1u | 0 · 1u | 0 · 1k | 0 · 1u | 1 | 0 · 1k | 0 · 1k | +| `MPP-ec29292f9d`* | draft-solana-charge-00.md § Method Details | 2 | 0 · 1u · 1k | 0 · 1u | 0 · 1u | 0 · 1u | 0 · 1u · 1k | 0 · 1u | 2 | 0 · 1u · 1k | 1 · 1u | +| `MPP-fde6ebf8c7`* | draft-solana-charge-00.md § Method Details | 1 | 0 · 1k | — | 0 · 1u | 0 · 1u | 0 · 1k | 0 · 1u | 1 | 0 · 1k | 1 | | `MPP-e02293d02d`* | draft-solana-charge-00.md § Native SOL | 1 | 1 | — | 0 · 1u | 0 · 1u | 1 | 0 · 1u | 1 | 1 | 1 | | `MPP-1659a03107`* | draft-solana-charge-00.md § Native SOL Verification | 1 | 1 | — | 1 | 1 | 1 | 1 | 1 | 0 · 1u | 1 | | `MPP-4a77950278`* | draft-solana-charge-00.md § Native SOL Verification | 2 | 2 | — | 2 | 2 | 2 | 2 | 2 | 0 · 2u | 2 | @@ -379,14 +382,14 @@ come from the same extraction as `pkc req-lint`. | `MPP-64da85f4f3`* | draft-solana-charge-00.md § SPL Tokens | 1 | 1 | — | 1 | 1 | 1 | 1 | 1 | 0 · 1u | 1 | | `MPP-2d30d806c0`* | draft-solana-charge-00.md § Server Requirements | 7 | 7 | — | 7 | 7 | 7 | 7 | 7 | 0 · 7u | 7 | | `MPP-3d2ad6ef40`* | draft-solana-charge-00.md § Shared Fields | 1 | 1 | — | 1 | 1 | 1 | 1 | 1 | 0 · 1u | 1 | -| `MPP-a6f3950ec9`* | draft-solana-charge-00.md § Shared Fields | 2 | 2 | — | 0 · 2u | 0 · 2u | 1 · 1k | 0 · 2u | 2 | 2 | 1 · 1k | +| `MPP-a6f3950ec9`* | draft-solana-charge-00.md § Shared Fields | 2 | 2 | — | 0 · 2u | 0 · 2u | 1 · 1k | 0 · 2u | 2 | 2 | 2 | | `MPP-0399450c79`* | draft-solana-charge-00.md § Split Recipient ATA Creation | 1 | 1 | — | 1 | 1 | 1 | 1 | 1 | 0 · 1u | 1 | | `MPP-197d674f50`* | draft-solana-charge-00.md § Split Recipient ATA Creation | 1 | 1 | — | 1 | 1 | 1 | 1 | 1 | 0 · 1u | 1 | | `MPP-304370cfc4`* | draft-solana-charge-00.md § Split Recipient ATA Creation | 1 | 1 | — | 1 | 1 | 1 | 1 | 1 | 0 · 1u | 1 | | `MPP-438c3bfb12`* | draft-solana-charge-00.md § Split Recipient ATA Creation | 1 | 1 | — | 1 | 1 | 1 | 1 | 1 | 0 · 1u | 1 | | `MPP-681f5e090f`* | draft-solana-charge-00.md § Split Recipient ATA Creation | 2 | 1 · 1k | — | 2 | 2 | 2 | 2 | 2 | 0 · 2u | 2 | | `MPP-74cf327879`* | draft-solana-charge-00.md § Split Recipient ATA Creation | 1 | 1 | — | 1 | 1 | 1 | 1 | 1 | 0 · 1u | 1 | -| `MPP-ab401714b4`* | draft-solana-charge-00.md § Split Recipient ATA Creation | 1 | 1 | — | 1 | 1 | 1 | 1 | 1 | 0 · 1u | 0 · 1k | +| `MPP-ab401714b4`* | draft-solana-charge-00.md § Split Recipient ATA Creation | 1 | 1 | — | 1 | 1 | 1 | 1 | 1 | 0 · 1u | 1 | | `MPP-b333c50e7e`* | draft-solana-charge-00.md § Split Recipient ATA Creation | 1 | 1 | — | 1 | 1 | 1 | 1 | 1 | 0 · 1u | 1 | | `MPP-baa94f08cb`* | draft-solana-charge-00.md § Split Recipient ATA Creation | 2 | 0 · 2k | — | 2 | 2 | 2 | 2 | 2 | 0 · 2u | 2 | | `MPP-d63913e921`* | draft-solana-charge-00.md § Split Recipient ATA Creation | 2 | 1 · 1k | — | 2 | 2 | 2 | 2 | 2 | 0 · 2u | 2 | @@ -410,7 +413,7 @@ come from the same extraction as `pkc req-lint`. | `MPP-53a60f6563`* | draft-solana-session-00.md § Action: "open" | 1 | 0 · 1u | 0 · 1u | — | — | 0 · 1u | — | 1 | 0 · 1u | 0 · 1u | | `MPP-7126d3b0b5`* | draft-solana-session-00.md § Action: "open" | 3 | 0 · 3u | 0 · 3u | — | — | 0 · 3u | — | 3 | 0 · 3u | 0 · 3u | | `MPP-73f0b859d9`* | draft-solana-session-00.md § Action: "open" | 1 | 0 · 1u | 0 · 1u | — | — | 0 · 1u | — | 1 | 0 · 1u | 0 · 1u | -| `MPP-89f2059960`* | draft-solana-session-00.md § Action: "open" | 2 | 0 · 2u | 0 · 2u | — | — | 0 · 1u · 1k | — | 2 | 0 · 2u | 0 · 1u · 1k | +| `MPP-89f2059960`* | draft-solana-session-00.md § Action: "open" | 2 | 0 · 2u | 0 · 2u | — | — | 0 · 1u · 1k | — | 2 | 0 · 2u | 1 · 1u | | `MPP-a5edb594a1`* | draft-solana-session-00.md § Action: "open" | 3 | 0 · 3u | 0 · 3u | — | — | 1 · 2u | — | 3 | 0 · 3u | 1 · 2u | | `MPP-a9cb73c5b3`* | draft-solana-session-00.md § Action: "open" | 4 | 0 · 4u | 0 · 4u | — | — | 0 · 4u | — | 4 | 0 · 4u | 0 · 4u | | `MPP-a9eb047d07`* | draft-solana-session-00.md § Action: "open" | 2 | 0 · 2u | 0 · 2u | — | — | 1 · 1u | — | 2 | 0 · 2u | 1 · 1u | @@ -449,7 +452,7 @@ come from the same extraction as `pkc req-lint`. | `MPP-69c0a4f95f`* | draft-solana-session-00.md § Method Details | 6 | 0 · 6u | 0 · 6u | — | — | 4 · 2u | — | 6 | 0 · 6u | 4 · 2u | | `MPP-a3d2da92ea`* | draft-solana-session-00.md § Method Details | 1 | 0 · 1u | 0 · 1u | — | — | 0 · 1u | — | 1 | 0 · 1u | 0 · 1u | | `MPP-bb80675c8e`* | draft-solana-session-00.md § Method Details | 1 | 0 · 1u | 0 · 1u | — | — | 1 | — | 1 | 0 · 1u | 1 | -| `MPP-d235eadc2e`* | draft-solana-session-00.md § Method Details | 2 | 0 · 2u | 0 · 2u | — | — | 0 · 2u | — | 2 | 0 · 2u | 0 · 2u | +| `MPP-d235eadc2e`* | draft-solana-session-00.md § Method Details | 3 | 0 · 3u | 0 · 3u | — | — | 0 · 3u | — | 3 | 0 · 3u | 0 · 3u | | `MPP-d5da84fe70`* | draft-solana-session-00.md § Method Details | 3 | 0 · 3u | 0 · 3u | — | — | 1 · 2u | — | 3 | 0 · 3u | 1 · 2u | | `MPP-ecdf5de619`* | draft-solana-session-00.md § Method Details | 2 | 0 · 2u | 0 · 2u | — | — | 1 · 1u | — | 2 | 0 · 2u | 1 · 1u | | `MPP-bf87a688ef`* | draft-solana-session-00.md § Mint Allow-List | 1 | 0 · 1u | 0 · 1u | — | — | 0 · 1u | — | 1 | 0 · 1u | 0 · 1u | @@ -493,44 +496,44 @@ come from the same extraction as `pkc req-lint`. | `MPP-b87a0cd7d3`* | draft-solana-subscription-00.md § Account Ownership and Program-ID Validation | 2 | — | — | — | — | — | — | 2 | — | 0 · 2u | | `MPP-9255227955`* | draft-solana-subscription-00.md § Activation | 4 | — | — | — | — | — | — | 4 | — | 3 · 1k | | `MPP-e0965cb0fe`* | draft-solana-subscription-00.md § Activation | 2 | — | — | — | — | — | — | 2 | — | 2 | -| `MPP-4a9406cfcb`* | draft-solana-subscription-00.md § Amount and Period Verification | 4 | — | — | — | — | — | — | 4 | — | 3 · 1k | +| `MPP-4a9406cfcb`* | draft-solana-subscription-00.md § Amount and Period Verification | 4 | — | — | — | — | — | — | 4 | — | 4 | | `MPP-62866c1462`* | draft-solana-subscription-00.md § Amount and Period Verification | 4 | — | — | — | — | — | — | 4 | — | 4 | | `MPP-449b853cb2`* | draft-solana-subscription-00.md § Authorization Scope Verification | 1 | — | — | — | — | — | — | 1 | — | 1 | -| `MPP-89be025a89`* | draft-solana-subscription-00.md § Authorization Scope Verification | 13 | — | — | — | — | — | — | 13 | — | 11 · 2k | +| `MPP-89be025a89`* | draft-solana-subscription-00.md § Authorization Scope Verification | 13 | — | — | — | — | — | — | 13 | — | 13 | | `MPP-1ec64dcbc6`* | draft-solana-subscription-00.md § Bearer Proof Theft | 3 | — | — | — | — | — | — | 3 | — | 0 · 3u | | `MPP-9dab72f223`* | draft-solana-subscription-00.md § Cancellation | 1 | — | — | — | — | — | — | 1 | — | 0 · 1u | -| `MPP-5d14dd20cb`* | draft-solana-subscription-00.md § Currency Formats | 1 | — | — | — | — | — | — | 1 | — | 0 · 1k | -| `MPP-12c23b8418`* | draft-solana-subscription-00.md § Definition | 1 | — | — | — | — | — | — | 1 | — | 0 · 1k | +| `MPP-5d14dd20cb`* | draft-solana-subscription-00.md § Currency Formats | 1 | — | — | — | — | — | — | 1 | — | 1 | +| `MPP-12c23b8418`* | draft-solana-subscription-00.md § Definition | 1 | — | — | — | — | — | — | 1 | — | 1 | | `MPP-83bfc235ab`* | draft-solana-subscription-00.md § Destination Scoping | 1 | — | — | — | — | — | — | 1 | — | 1 | -| `MPP-1d44630921`* | draft-solana-subscription-00.md § Method Details | 1 | — | — | — | — | — | — | 1 | — | 0 · 1k | -| `MPP-327d9b66ba`* | draft-solana-subscription-00.md § Method Details | 2 | — | — | — | — | — | — | 2 | — | 0 · 2k | +| `MPP-1d44630921`* | draft-solana-subscription-00.md § Method Details | 1 | — | — | — | — | — | — | 1 | — | 1 | +| `MPP-327d9b66ba`* | draft-solana-subscription-00.md § Method Details | 2 | — | — | — | — | — | — | 2 | — | 2 | | `MPP-463ea35304`* | draft-solana-subscription-00.md § Method Details | 1 | — | — | — | — | — | — | 1 | — | 1 | | `MPP-4a98642d3c`* | draft-solana-subscription-00.md § Method Details | 1 | — | — | — | — | — | — | 1 | — | 1 | | `MPP-60413f3bf6`* | draft-solana-subscription-00.md § Method Details | 1 | — | — | — | — | — | — | 1 | — | 1 | -| `MPP-634239a4f5`* | draft-solana-subscription-00.md § Method Details | 2 | — | — | — | — | — | — | 2 | — | 0 · 2k | +| `MPP-634239a4f5`* | draft-solana-subscription-00.md § Method Details | 2 | — | — | — | — | — | — | 2 | — | 2 | | `MPP-7ebd75eefc`* | draft-solana-subscription-00.md § Method Details | 2 | — | — | — | — | — | — | 2 | — | 2 | | `MPP-f90bd07116`* | draft-solana-subscription-00.md § Method Details | 1 | — | — | — | — | — | — | 1 | — | 1 | -| `MPP-fc9334823a`* | draft-solana-subscription-00.md § Method Details | 3 | — | — | — | — | — | — | 3 | — | 0 · 3k | -| `MPP-58828c88cd`* | draft-solana-subscription-00.md § Optional Fields | 10 | — | — | — | — | — | — | 10 | — | 9 · 1k | -| `MPP-6739698bb1`* | draft-solana-subscription-00.md § Optional Fields | 2 | — | — | — | — | — | — | 2 | — | 0 · 2k | -| `MPP-95dab3a64d`* | draft-solana-subscription-00.md § Optional Fields | 3 | — | — | — | — | — | — | 3 | — | 0 · 3k | -| `MPP-aadffadc90`* | draft-solana-subscription-00.md § Optional Fields | 8 | — | — | — | — | — | — | 8 | — | 2 · 6k | +| `MPP-fc9334823a`* | draft-solana-subscription-00.md § Method Details | 3 | — | — | — | — | — | — | 3 | — | 3 | +| `MPP-58828c88cd`* | draft-solana-subscription-00.md § Optional Fields | 10 | — | — | — | — | — | — | 10 | — | 10 | +| `MPP-6739698bb1`* | draft-solana-subscription-00.md § Optional Fields | 2 | — | — | — | — | — | — | 2 | — | 2 | +| `MPP-95dab3a64d`* | draft-solana-subscription-00.md § Optional Fields | 3 | — | — | — | — | — | — | 3 | — | 3 | +| `MPP-aadffadc90`* | draft-solana-subscription-00.md § Optional Fields | 8 | — | — | — | — | — | — | 8 | — | 8 | | `MPP-d063521350`* | draft-solana-subscription-00.md § Optional Fields | 2 | — | — | — | — | — | — | 2 | — | 2 | -| `MPP-45b8ba4317`* | draft-solana-subscription-00.md § Payload | 3 | — | — | — | — | — | — | 3 | — | 2 · 1k | +| `MPP-45b8ba4317`* | draft-solana-subscription-00.md § Payload | 3 | — | — | — | — | — | — | 3 | — | 3 | | `MPP-52f835b76c`* | draft-solana-subscription-00.md § Payload | 3 | — | — | — | — | — | — | 3 | — | 3 | | `MPP-98987d4454`* | draft-solana-subscription-00.md § Payload | 1 | — | — | — | — | — | — | 1 | — | 1 | | `MPP-42cf63c8b8`* | draft-solana-subscription-00.md § Request Schema | 2 | — | — | — | — | — | — | 2 | — | 2 | | `MPP-cdbcb3a843`* | draft-solana-subscription-00.md § Required Fields | 3 | — | — | — | — | — | — | 3 | — | 3 | | `MPP-0a7c7d7791`* | draft-solana-subscription-00.md § Server Accounting and Idempotency | 14 | — | — | — | — | — | — | 14 | — | 2 · 12u | | `MPP-2bbba2b551`* | draft-solana-subscription-00.md § Shared Fields | 2 | — | — | — | — | — | — | 2 | — | 2 | -| `MPP-0e0da9c6a6`* | draft-solana-subscription-00.md § Source Verification | 2 | — | — | — | — | — | — | 2 | — | 0 · 2k | +| `MPP-0e0da9c6a6`* | draft-solana-subscription-00.md § Source Verification | 2 | — | — | — | — | — | — | 2 | — | 2 | | `MPP-afd07e174b`* | draft-solana-subscription-00.md § Source Verification | 2 | — | — | — | — | — | — | 2 | — | 2 | -| `MPP-11cddfe4f2`* | draft-solana-subscription-00.md § Subscription Bearer Proof | 8 | — | — | — | — | — | — | 8 | — | 1 · 2u · 5k | -| `MPP-8a193ab322`* | draft-solana-subscription-00.md § Subscription Bearer Proof | 4 | — | — | — | — | — | — | 4 | — | 3 · 1k | +| `MPP-11cddfe4f2`* | draft-solana-subscription-00.md § Subscription Bearer Proof | 8 | — | — | — | — | — | — | 8 | — | 6 · 2u | +| `MPP-8a193ab322`* | draft-solana-subscription-00.md § Subscription Bearer Proof | 4 | — | — | — | — | — | — | 4 | — | 4 | | `MPP-9edde7b556`* | draft-solana-subscription-00.md § Subscription Bearer Proof | 4 | 0 · 2u | 0 · 2u | — | — | 2 | — | 4 | 0 · 2u | 4 | | `MPP-dcaa3d63c8`* | draft-solana-subscription-00.md § Subscription Bearer Proof | 6 | — | — | — | — | — | — | 6 | — | 6 | | `MPP-ef1bb057fc`* | draft-solana-subscription-00.md § Subscription Bearer Proof | 10 | — | — | — | — | — | — | 10 | — | 10 | -| `MPPTX-507629a4fa`* | draft-solana-charge-00.md § Fee Payer Configuration | 3 | 0 · 3k | — | 0 · 2u · 1k | 0 · 2u · 1k | 0 · 3k | 1 · 2u | 3 | 0 · 1u · 2k | 0 · 3k | +| `MPPTX-507629a4fa`* | draft-solana-charge-00.md § Fee Payer Configuration | 3 | 0 · 3k | — | 0 · 2u · 1k | 0 · 2u · 1k | 0 · 3k | 1 · 2u | 3 | 0 · 1u · 2k | 1 · 2k | | `MPPTX-102b6dc2a5`* | draft-solana-charge-00.md § Method Details | 19 | 2 · 7u · 10k | 0 · 7u | 2 · 10k | 2 · 10k | 2 · 2u · 15k | 2 · 10k | 19 | 0 · 14u · 5k | 2 · 2u · 15k | | `MPPTX-6e9ac6c31d`* | draft-solana-charge-00.md § Native SOL Verification | 1 | 0 · 1k | — | 0 · 1k | 0 · 1k | 1 | 0 · 1k | 1 | 0 · 1u | 0 · 1k | | `MPPTX-96ba338b1e`* | draft-solana-charge-00.md § SPL Token Verification | 3 | 0 · 3k | — | 0 · 3k | 0 · 3k | 3 | 0 · 3k | 3 | 0 · 3u | 0 · 3k | @@ -538,108 +541,112 @@ come from the same extraction as `pkc req-lint`. | `MPPTX-c483036092`* | draft-solana-charge-00.md § Transaction Payload Security | 2 | 0 · 2k | — | 0 · 2k | 0 · 2k | 1 · 1k | 0 · 2k | 2 | 0 · 2u | 0 · 2k | | `MPPTX-4f1a73dd49`* | draft-solana-charge-00.md § Transaction Payload — Pull Mode | 3 | 0 · 3k | — | 0 · 3k | 0 · 3k | 0 · 3k | 0 · 3k | 3 | 0 · 3u | 0 · 3k | | `MPPTX-d5e5d796c6`* | draft-solana-charge-00.md § Transaction Payload — Pull Mode | 4 | 0 · 4k | — | 0 · 1u · 3k | 0 · 1u · 3k | 1 · 3k | 0 · 1u · 3k | 4 | 0 · 3u · 1k | 0 · 4k | -| `MPPTX-f8468a31de`* | draft-solana-charge-00.md § Transaction Payload — Pull Mode | 2 | 0 · 2k | — | 0 · 2k | 0 · 2k | 0 · 2k | 0 · 2k | 2 | 0 · 2u | 0 · 2k | +| `MPPTX-f8468a31de`* | draft-solana-charge-00.md § Transaction Payload — Pull Mode | 2 | 0 · 2k | — | 0 · 2k | 0 · 2k | 0 · 2k | 0 · 2k | 2 | 0 · 2u | 1 · 1k | | `MPPTX-27a6fd4f3f`* | draft-solana-charge-00.md § Transaction Versions | 6 | 0 · 1u · 5k | 0 · 1u | 0 · 5k | 1 · 4k | 0 · 1u · 5k | 0 · 5k | 6 | 0 · 6u | 1 · 1u · 4k | | `MPPTX-2855caa59a`* | draft-solana-charge-00.md § Transaction Versions | 1 | 0 · 1k | — | 0 · 1k | 1 | 0 · 1k | 0 · 1k | 1 | 0 · 1u | 1 | -| `MPPTX-3f51d8e008`* | draft-solana-charge-00.md § Transaction Versions | 3 | 0 · 3k | — | 0 · 1u · 2k | 0 · 1u · 2k | 0 · 3k | 0 · 1u · 2k | 3 | 0 · 2u · 1k | 0 · 3k | +| `MPPTX-3f51d8e008`* | draft-solana-charge-00.md § Transaction Versions | 3 | 0 · 3k | — | 0 · 1u · 2k | 0 · 1u · 2k | 0 · 3k | 0 · 1u · 2k | 3 | 0 · 2u · 1k | 1 · 2k | | `MPPTX-46848f6fce`* | draft-solana-charge-00.md § Transaction Versions | 2 | 0 · 1u · 1k | 0 · 1u | 0 · 1k | 0 · 1k | 0 · 1u · 1k | 0 · 1k | 2 | 0 · 2u | 0 · 1u · 1k | | `MPPTX-5b29a4494f`* | draft-solana-charge-00.md § Transaction Versions | 5 | 0 · 2u · 3k | 0 · 2u | 0 · 3k | 0 · 3k | 0 · 1u · 4k | 0 · 3k | 5 | 0 · 4u · 1k | 0 · 1u · 4k | | `MPPTX-8a036b6610`* | draft-solana-charge-00.md § Transaction Versions | 2 | 0 · 1u · 1k | 0 · 1u | 0 · 1k | 0 · 1k | 0 · 1u · 1k | 0 · 1k | 2 | 0 · 2u | 0 · 1u · 1k | | `MPPTX-8a988b0f7a`* | draft-solana-charge-00.md § Transaction Versions | 6 | 0 · 1u · 5k | 0 · 1u | 0 · 5k | 0 · 5k | 0 · 1u · 5k | 0 · 5k | 6 | 0 · 6u | 0 · 1u · 5k | | `MPPTX-d180d03a99`* | draft-solana-charge-00.md § Transaction Versions | 11 | 3 · 8k | — | 0 · 11u | 0 · 11u | 3 · 8k | 0 · 11u | 11 | 3 · 8k | 2 · 2u · 7k | -| `MPPTX-d53a9f42dd`* | draft-solana-charge-00.md § Transaction Versions | 3 | 0 · 1u · 2k | 0 · 1u | 0 · 2k | 0 · 2k | 0 · 1u · 2k | 2 | 3 | 0 · 3u | 0 · 1u · 2k | +| `MPPTX-d53a9f42dd`* | draft-solana-charge-00.md § Transaction Versions | 3 | 0 · 1u · 2k | 0 · 1u | 0 · 2k | 0 · 2k | 0 · 1u · 2k | 2 | 3 | 0 · 3u | 2 · 1u | | `MPPTX-5410e1de47`* | draft-solana-session-00.md § Action: "open" | 7 | 0 · 7u | 0 · 7u | — | — | 0 · 5u · 2k | — | 7 | 0 · 7u | 0 · 5u · 2k | | `MPPTX-4563533e08`* | draft-solana-session-00.md § Action: "topUp" | 1 | 0 · 1u | 0 · 1u | — | — | 0 · 1k | — | 1 | 0 · 1u | 0 · 1k | -| `X402-063b58b983`* | scheme_batch_settlement_svm.md § 3. Payment-Channel Method | 5 | — | — | — | — | — | — | 5 | — | 0 · 1u · 4k | -| `X402-556df29ac2`* | scheme_batch_settlement_svm.md § 3. Payment-Channel Method | 2 | — | — | — | — | — | — | 2 | — | 0 · 1u · 1k | +| `X402-063b58b983`* | scheme_batch_settlement_svm.md § 3. Payment-Channel Method | 5 | — | — | — | — | — | — | 5 | — | 4 · 1u | +| `X402-556df29ac2`* | scheme_batch_settlement_svm.md § 3. Payment-Channel Method | 2 | — | — | — | — | — | — | 2 | — | 1 · 1u | | `X402-c0dd3bd5b3`* | scheme_batch_settlement_svm.md § 3. Payment-Channel Method | 1 | — | — | — | — | — | — | 1 | — | 1 | | `X402-1230bb35a3`* | scheme_batch_settlement_svm.md § 4.1 PaymentRequirements (in PAYMENT-REQUIRED.accepts[]) | 2 | — | — | — | — | — | — | 2 | — | 2 | | `X402-180abaa115`* | scheme_batch_settlement_svm.md § 4.1 PaymentRequirements (in PAYMENT-REQUIRED.accepts[]) | 1 | — | — | — | — | — | — | 1 | — | 1 | | `X402-7556a4ec7c`* | scheme_batch_settlement_svm.md § 4.1 PaymentRequirements (in PAYMENT-REQUIRED.accepts[]) | 5 | — | — | — | — | — | — | 5 | — | 4 · 1u | -| `X402-bde1322bb3`* | scheme_batch_settlement_svm.md § 4.1 PaymentRequirements (in PAYMENT-REQUIRED.accepts[]) | 2 | — | — | — | — | — | — | 2 | — | 1 · 1k | +| `X402-bde1322bb3`* | scheme_batch_settlement_svm.md § 4.1 PaymentRequirements (in PAYMENT-REQUIRED.accepts[]) | 2 | — | — | — | — | — | — | 2 | — | 2 | | `X402-df15443ca9`* | scheme_batch_settlement_svm.md § 4.1 PaymentRequirements (in PAYMENT-REQUIRED.accepts[]) | 1 | — | — | — | — | — | — | 1 | — | 1 | -| `X402-f265c321e3`* | scheme_batch_settlement_svm.md § 4.1 PaymentRequirements (in PAYMENT-REQUIRED.accepts[]) | 4 | — | — | — | — | — | — | 4 | — | 2 · 2k | -| `X402-22712c36e1`* | scheme_batch_settlement_svm.md § 4.2 Shared Wire Objects and Program Mapping | 1 | — | — | — | — | — | — | 1 | — | 0 · 1k | +| `X402-f265c321e3`* | scheme_batch_settlement_svm.md § 4.1 PaymentRequirements (in PAYMENT-REQUIRED.accepts[]) | 4 | — | — | — | — | — | — | 4 | — | 4 | +| `X402-22712c36e1`* | scheme_batch_settlement_svm.md § 4.2 Shared Wire Objects and Program Mapping | 1 | — | — | — | — | — | — | 1 | — | 1 | | `X402-23747f44c3`* | scheme_batch_settlement_svm.md § 4.2 Shared Wire Objects and Program Mapping | 2 | — | — | — | — | — | — | 2 | — | 2 | | `X402-2f8ea170e2`* | scheme_batch_settlement_svm.md § 4.2 Shared Wire Objects and Program Mapping | 1 | — | — | — | — | — | — | 1 | — | 1 | -| `X402-87c5fe8803`* | scheme_batch_settlement_svm.md § 4.2 Shared Wire Objects and Program Mapping | 5 | — | — | — | — | — | — | 5 | — | 0 · 5k | -| `X402-a2dd2eb911`* | scheme_batch_settlement_svm.md § 4.2 Shared Wire Objects and Program Mapping | 1 | — | — | — | — | — | — | 1 | — | 1 | +| `X402-87c5fe8803`* | scheme_batch_settlement_svm.md § 4.2 Shared Wire Objects and Program Mapping | 5 | — | — | — | — | — | — | 5 | — | 5 | +| `X402-a2dd2eb911`* | scheme_batch_settlement_svm.md § 4.2 Shared Wire Objects and Program Mapping | 2 | — | — | — | — | — | — | 2 | — | 2 | | `X402-ae5ee4f564`* | scheme_batch_settlement_svm.md § 4.2 Shared Wire Objects and Program Mapping | 1 | — | — | — | — | — | — | 1 | — | 1 | | `X402-d171becfd9`* | scheme_batch_settlement_svm.md § 4.2 Shared Wire Objects and Program Mapping | 2 | — | — | — | — | — | — | 2 | — | 1 · 1k | | `X402-d71a021041`* | scheme_batch_settlement_svm.md § 4.2 Shared Wire Objects and Program Mapping | 2 | — | — | — | — | — | — | 2 | — | 1 · 1u | -| `X402-f0a4201d93`* | scheme_batch_settlement_svm.md § 4.2 Shared Wire Objects and Program Mapping | 2 | — | — | — | — | — | — | 2 | — | 1 · 1k | +| `X402-f0a4201d93`* | scheme_batch_settlement_svm.md § 4.2 Shared Wire Objects and Program Mapping | 2 | — | — | — | — | — | — | 2 | — | 2 | | `X402-fb76d46cb8`* | scheme_batch_settlement_svm.md § 4.2 Shared Wire Objects and Program Mapping | 7 | — | — | — | — | — | — | 7 | — | 7 | | `X402-24cd5fed02`* | scheme_batch_settlement_svm.md § 4.3 Client PaymentPayload Variants | 2 | — | — | — | — | — | — | 2 | — | 2 | | `X402-492eabbfab`* | scheme_batch_settlement_svm.md § 4.3 Client PaymentPayload Variants | 1 | — | — | — | — | — | — | 1 | — | 1 | | `X402-62a1b36ba4`* | scheme_batch_settlement_svm.md § 4.3 Client PaymentPayload Variants | 1 | — | — | — | — | — | — | 1 | — | 1 | | `X402-cee6662254`* | scheme_batch_settlement_svm.md § 4.3 Client PaymentPayload Variants | 1 | — | — | — | — | — | — | 1 | — | 1 | | `X402-e98b9b9bec`* | scheme_batch_settlement_svm.md § 4.3 Client PaymentPayload Variants | 2 | — | — | — | — | — | — | 2 | — | 1 · 1u | -| `X402-fa34804f1b`* | scheme_batch_settlement_svm.md § 4.3 Client PaymentPayload Variants | 5 | — | — | — | — | — | — | 5 | — | 1 · 1u · 3k | +| `X402-fa34804f1b`* | scheme_batch_settlement_svm.md § 4.3 Client PaymentPayload Variants | 5 | — | — | — | — | — | — | 5 | — | 4 · 1u | | `X402-5ebca343d1`* | scheme_batch_settlement_svm.md § 4.4 SettlementResponse (in PAYMENT-RESPONSE) | 1 | — | — | — | — | — | — | 1 | — | 0 · 1u | | `X402-c3d9b43d25`* | scheme_batch_settlement_svm.md § 4.5 Facilitator Interface | 2 | — | — | — | — | — | — | 2 | — | 1 · 1u | -| `X402-d29d49ebde`* | scheme_batch_settlement_svm.md § 4.5 Facilitator Interface | 5 | — | — | — | — | — | — | 5 | — | 1 · 1u · 3k | +| `X402-d29d49ebde`* | scheme_batch_settlement_svm.md § 4.5 Facilitator Interface | 5 | — | — | — | — | — | — | 5 | — | 4 · 1u | | `X402-171a57666e`* | scheme_batch_settlement_svm.md § 4.6 Corrective PaymentRequired | 7 | — | — | — | — | — | — | 7 | — | 0 · 7u | | `X402-638126c26b`* | scheme_batch_settlement_svm.md § 4.6 Corrective PaymentRequired | 12 | — | — | — | — | — | — | 12 | — | 0 · 12u | | `X402-84916fe051`* | scheme_batch_settlement_svm.md § 8. Security Properties | 1 | — | — | — | — | — | — | 1 | — | 1 | | `X402-f882f2074a`* | scheme_batch_settlement_svm.md § 8. Security Properties | 1 | — | — | — | — | — | — | 1 | — | 1 | -| `X402-176a26e5b6`* | scheme_batch_settlement_svm.md § Canonical open | 2 | — | — | — | — | — | — | 2 | — | 0 · 2k | -| `X402-5276aee847`* | scheme_batch_settlement_svm.md § Canonical refund request_close | 3 | — | — | — | — | — | — | 3 | — | 0 · 3k | -| `X402-a6092f0a02`* | scheme_batch_settlement_svm.md § Canonical refund request_close | 4 | — | — | — | — | — | — | 4 | — | 0 · 4k | -| `X402-c88cc9c766`* | scheme_batch_settlement_svm.md § Canonical refund request_close | 2 | — | — | — | — | — | — | 2 | — | 0 · 2k | -| `X402-d450762477`* | scheme_batch_settlement_svm.md § Canonical refund request_close | 1 | — | — | — | — | — | — | 1 | — | 0 · 1k | -| `X402-06bb8f3a9e`* | scheme_batch_settlement_svm.md § Canonical top_up | 3 | — | — | — | — | — | — | 3 | — | 1 · 1u · 1k | +| `X402-0ff4cabcb4`* | scheme_batch_settlement_svm.md § Canonical open | 1 | — | — | — | — | — | — | 1 | — | 0 · 1k | +| `X402-176a26e5b6`* | scheme_batch_settlement_svm.md § Canonical open | 1 | — | — | — | — | — | — | 1 | — | 1 | +| `X402-5276aee847`* | scheme_batch_settlement_svm.md § Canonical refund request_close | 3 | — | — | — | — | — | — | 3 | — | 3 | +| `X402-a6092f0a02`* | scheme_batch_settlement_svm.md § Canonical refund request_close | 4 | — | — | — | — | — | — | 4 | — | 4 | +| `X402-c88cc9c766`* | scheme_batch_settlement_svm.md § Canonical refund request_close | 2 | — | — | — | — | — | — | 2 | — | 2 | +| `X402-d450762477`* | scheme_batch_settlement_svm.md § Canonical refund request_close | 1 | — | — | — | — | — | — | 1 | — | 1 | +| `X402-014270dc81`* | scheme_batch_settlement_svm.md § Canonical top_up | 1 | — | — | — | — | — | — | 1 | — | 0 · 1k | +| `X402-06bb8f3a9e`* | scheme_batch_settlement_svm.md § Canonical top_up | 4 | — | — | — | — | — | — | 4 | — | 3 · 1u | | `X402-4cedb5114b`* | scheme_batch_settlement_svm.md § Canonical top_up | 2 | — | — | — | — | — | — | 2 | — | 1 · 1k | -| `X402-9ca40ae469`* | scheme_batch_settlement_svm.md § Canonical top_up | 1 | — | — | — | — | — | — | 1 | — | 0 · 1k | -| `X402-be2f5b7ea4`* | scheme_batch_settlement_svm.md § Canonical top_up | 1 | — | — | — | — | — | — | 1 | — | 0 · 1k | +| `X402-9ca40ae469`* | scheme_batch_settlement_svm.md § Canonical top_up | 1 | — | — | — | — | — | — | 1 | — | 1 | +| `X402-be2f5b7ea4`* | scheme_batch_settlement_svm.md § Canonical top_up | 1 | — | — | — | — | — | — | 1 | — | 1 | | `X402-04b1c68ba2`* | scheme_batch_settlement_svm.md § GET /supported | 2 | — | — | — | — | — | — | 2 | — | 1 · 1u | -| `X402-129e295f0c`* | scheme_batch_settlement_svm.md § Message and signer rules | 2 | — | — | — | — | — | — | 2 | — | 0 · 1u · 1k | +| `X402-8f57677e36`* | scheme_batch_settlement_svm.md § GET /supported | 1 | — | — | — | — | — | — | 1 | — | 0 · 1u | +| `X402-129e295f0c`* | scheme_batch_settlement_svm.md § Message and signer rules | 2 | — | — | — | — | — | — | 2 | — | 1 · 1u | | `X402-13c8fefbbf`* | scheme_batch_settlement_svm.md § Message and signer rules | 3 | — | — | — | — | — | — | 3 | — | 2 · 1k | -| `X402-55d34e173c`* | scheme_batch_settlement_svm.md § Message and signer rules | 1 | — | — | — | — | — | — | 1 | — | 0 · 1k | +| `X402-55d34e173c`* | scheme_batch_settlement_svm.md § Message and signer rules | 1 | — | — | — | — | — | — | 1 | — | 1 | | `X402-6ac6583e77`* | scheme_batch_settlement_svm.md § Message and signer rules | 1 | — | — | — | — | — | — | 1 | — | 1 | -| `X402-f729304bf1`* | scheme_batch_settlement_svm.md § Message and signer rules | 1 | — | — | — | — | — | — | 1 | — | 0 · 1k | -| `X402-3679bfc55e`* | scheme_batch_settlement_svm.md § POST /settle | 1 | — | — | — | — | — | — | 1 | — | 0 · 1k | +| `X402-f729304bf1`* | scheme_batch_settlement_svm.md § Message and signer rules | 1 | — | — | — | — | — | — | 1 | — | 1 | +| `X402-3679bfc55e`* | scheme_batch_settlement_svm.md § POST /settle | 1 | — | — | — | — | — | — | 1 | — | 0 · 1u | | `X402-45c411d301`* | scheme_batch_settlement_svm.md § POST /settle | 1 | — | — | — | — | — | — | 1 | — | 1 | -| `X402-7f4ee54a73`* | scheme_batch_settlement_svm.md § POST /settle | 5 | — | — | — | — | — | — | 5 | — | 5 | -| `X402-a8645e7833`* | scheme_batch_settlement_svm.md § POST /settle | 1 | — | — | — | — | — | — | 1 | — | 0 · 1k | -| `X402-d167f9a958`* | scheme_batch_settlement_svm.md § POST /settle | 2 | — | — | — | — | — | — | 2 | — | 1 · 1k | -| `X402-dcd8fcf77b`* | scheme_batch_settlement_svm.md § POST /settle | 1 | — | — | — | — | — | — | 1 | — | 0 · 1k | +| `X402-76654742e7`* | scheme_batch_settlement_svm.md § POST /settle | 5 | — | — | — | — | — | — | 5 | — | 5 | +| `X402-a8645e7833`* | scheme_batch_settlement_svm.md § POST /settle | 1 | — | — | — | — | — | — | 1 | — | 1 | +| `X402-c2ca42b7a4`* | scheme_batch_settlement_svm.md § POST /settle | 3 | — | — | — | — | — | — | 3 | — | 3 | +| `X402-d167f9a958`* | scheme_batch_settlement_svm.md § POST /settle | 2 | — | — | — | — | — | — | 2 | — | 1 · 1u | +| `X402-dcd8fcf77b`* | scheme_batch_settlement_svm.md § POST /settle | 1 | — | — | — | — | — | — | 1 | — | 0 · 1u | | `X402-f5205e3932`* | scheme_batch_settlement_svm.md § POST /settle | 3 | — | — | — | — | — | — | 3 | — | 3 | | `X402-2ae0fdc5c6`* | scheme_batch_settlement_svm.md § POST /verify | 1 | — | — | — | — | — | — | 1 | — | 1 | | `X402-3485cafa46`* | scheme_batch_settlement_svm.md § POST /verify | 8 | — | — | — | — | — | — | 8 | — | 8 | -| `X402-fbdea947ae`* | scheme_batch_settlement_svm.md § POST /verify | 3 | — | — | — | — | — | — | 3 | — | 0 · 3k | +| `X402-fbdea947ae`* | scheme_batch_settlement_svm.md § POST /verify | 3 | — | — | — | — | — | — | 3 | — | 2 · 1k | | `X402-4ea8d1b0d9`* | scheme_batch_settlement_svm.md § Phase 1 - Open or Top Up | 2 | — | — | — | — | — | — | 2 | — | 2 | -| `X402-d16b3abbab`* | scheme_batch_settlement_svm.md § Phase 1 - Open or Top Up | 1 | — | — | — | — | — | — | 1 | — | 0 · 1k | +| `X402-d16b3abbab`* | scheme_batch_settlement_svm.md § Phase 1 - Open or Top Up | 1 | — | — | — | — | — | — | 1 | — | 1 | | `X402-f0d0755fc9`* | scheme_batch_settlement_svm.md § Phase 1 - Open or Top Up | 2 | — | — | — | — | — | — | 2 | — | 0 · 2k | | `X402-2073737c58`* | scheme_batch_settlement_svm.md § Phase 3 - Voucher Acceptance (before serving) | 2 | — | — | — | — | — | — | 2 | — | 1 · 1u | | `X402-46d0a12f84`* | scheme_batch_settlement_svm.md § Phase 3 - Voucher Acceptance (before serving) | 2 | — | — | — | — | — | — | 2 | — | 2 | | `X402-5b328b9a73`* | scheme_batch_settlement_svm.md § Phase 3 - Voucher Acceptance (before serving) | 2 | — | — | — | — | — | — | 2 | — | 2 | | `X402-91ecad3faa`* | scheme_batch_settlement_svm.md § Phase 3 - Voucher Acceptance (before serving) | 2 | — | — | — | — | — | — | 2 | — | 2 | -| `X402-a6efa8062a`* | scheme_batch_settlement_svm.md § Phase 3 - Voucher Acceptance (before serving) | 22 | — | — | — | — | — | — | 22 | — | 12 · 6u · 4k | -| `X402-15a1a9834e`* | scheme_batch_settlement_svm.md § Top-level instruction layout | 3 | — | — | — | — | — | — | 3 | — | 0 · 3k | -| `X402-3ed2ac9962`* | scheme_batch_settlement_svm.md § Top-level instruction layout | 1 | — | — | — | — | — | — | 1 | — | 0 · 1k | -| `X402-536163eb05`* | scheme_batch_settlement_svm.md § Top-level instruction layout | 2 | — | — | — | — | — | — | 2 | — | 0 · 2k | +| `X402-a6efa8062a`* | scheme_batch_settlement_svm.md § Phase 3 - Voucher Acceptance (before serving) | 22 | — | — | — | — | — | — | 22 | — | 13 · 9u | +| `X402-15a1a9834e`* | scheme_batch_settlement_svm.md § Top-level instruction layout | 3 | — | — | — | — | — | — | 3 | — | 3 | +| `X402-3ed2ac9962`* | scheme_batch_settlement_svm.md § Top-level instruction layout | 1 | — | — | — | — | — | — | 1 | — | 1 | +| `X402-536163eb05`* | scheme_batch_settlement_svm.md § Top-level instruction layout | 2 | — | — | — | — | — | — | 2 | — | 2 | | `X402-897add7b39`* | scheme_batch_settlement_svm.md § Top-level instruction layout | 1 | — | — | — | — | — | — | 1 | — | 1 | -| `X402-a93234f1d7`* | scheme_batch_settlement_svm.md § Top-level instruction layout | 3 | — | — | — | — | — | — | 3 | — | 1 · 2k | -| `X402-ae18578132`* | scheme_batch_settlement_svm.md § Top-level instruction layout | 2 | — | — | — | — | — | — | 2 | — | 1 · 1k | -| `X402-ebd20058fd`* | scheme_batch_settlement_svm.md § Top-level instruction layout | 3 | — | — | — | — | — | — | 3 | — | 0 · 3k | +| `X402-a93234f1d7`* | scheme_batch_settlement_svm.md § Top-level instruction layout | 5 | — | — | — | — | — | — | 5 | — | 5 | +| `X402-ae18578132`* | scheme_batch_settlement_svm.md § Top-level instruction layout | 2 | — | — | — | — | — | — | 2 | — | 2 | +| `X402-ebd20058fd`* | scheme_batch_settlement_svm.md § Top-level instruction layout | 3 | — | — | — | — | — | — | 3 | — | 3 | | `X402-8fcdf05fbf`* | scheme_exact.md § Client-submitted (payment proof) | 2 | 2 | — | 2 | 2 | 2 | 2 | 2 | 0 · 2u | 2 | | `X402-f870a56d25`* | scheme_exact.md § Client-submitted (payment proof) | 19 | 19 | — | 9 · 10u | 9 · 10u | 19 | 9 · 10u | 19 | 10 · 9u | 12 · 7u | -| `X402-fc2225a882`* | scheme_exact.md § Critical Validation Requirements | 1 | 0 · 1k | — | 0 · 1k | 0 · 1k | 0 · 1k | 0 · 1k | 1 | 0 · 1u | 0 · 1k | +| `X402-fc2225a882`* | scheme_exact.md § Critical Validation Requirements | 1 | 1 | — | 1 | 1 | 1 | 1 | 1 | 0 · 1u | 1 | | `X402-f45fed3f51`* | scheme_exact.md § SVM | 3 | 3 | — | 2 · 1u | 2 · 1u | 3 | 2 · 1u | 3 | 1 · 2u | 3 | | `X402-2f0d5ef017`* | scheme_exact_svm.md § 1.4 Exactly One Matching Transfer (MUST) | 1 | 1 | — | 1 | 1 | 1 | 1 | 1 | 0 · 1u | 1 | -| `X402-516a2d7b57`* | scheme_exact_svm.md § 1.4 Exactly One Matching Transfer (MUST) | 3 | 3 | — | 3 | 3 | 3 | 3 | 3 | 0 · 3u | 2 · 1k | +| `X402-516a2d7b57`* | scheme_exact_svm.md § 1.4 Exactly One Matching Transfer (MUST) | 3 | 3 | — | 3 | 3 | 3 | 3 | 3 | 0 · 3u | 3 | | `X402-bac6bc288a`* | scheme_exact_svm.md § 1.4 Exactly One Matching Transfer (MUST) | 3 | 3 | — | 3 | 3 | 3 | 3 | 3 | 0 · 3u | 3 | -| `X402-ee90546220`* | scheme_exact_svm.md § 1.4 Exactly One Matching Transfer (MUST) | 4 | 4 | — | 4 | 4 | 4 | 4 | 4 | 0 · 4u | 3 · 1k | +| `X402-ee90546220`* | scheme_exact_svm.md § 1.4 Exactly One Matching Transfer (MUST) | 4 | 4 | — | 4 | 4 | 4 | 4 | 4 | 0 · 4u | 4 | | `X402-93650bf2e3`* | scheme_exact_svm.md § 2.1 Minimal Safety Baseline (Normative MUSTs) | 3 | 3 | — | 2 · 1k | 2 · 1k | 2 · 1k | 3 | 3 | 0 · 3u | 3 | | `X402-0ad718daab`* | scheme_exact_svm.md § 2.1.1 Fee Payer Isolation (MUST) | 1 | 1 | — | 0 · 1k | 0 · 1k | 0 · 1k | 1 | 1 | 0 · 1u | 1 | | `X402-6708749c55`* | scheme_exact_svm.md § 2.1.1 Fee Payer Isolation (MUST) | 2 | 2 | — | 1 · 1k | 1 · 1k | 1 · 1k | 2 | 2 | 0 · 2u | 2 | | `X402-ed41478ffe`* | scheme_exact_svm.md § 2.1.1 Fee Payer Isolation (MUST) | 1 | 1 | — | 1 | 1 | 1 | 1 | 1 | 0 · 1u | 1 | | `X402-985ecc1ea3`* | scheme_exact_svm.md § 2.1.3 Fee Payer Fund Safety (MUST) | 1 | 1 | — | 0 · 1k | 0 · 1k | 0 · 1k | 1 | 1 | 0 · 1u | 1 | -| `X402-27bff260c3`* | scheme_exact_svm.md § 2.1.4 Signer Set Integrity (MUST) | 1 | 0 · 1k | — | 0 · 1k | 0 · 1k | 0 · 1k | 0 · 1k | 1 | 0 · 1u | 0 · 1k | -| `X402-9b240d95a0`* | scheme_exact_svm.md § 2.1.4 Signer Set Integrity (MUST) | 1 | 0 · 1k | — | 0 · 1k | 0 · 1k | 0 · 1k | 0 · 1k | 1 | 0 · 1u | 0 · 1k | +| `X402-27bff260c3`* | scheme_exact_svm.md § 2.1.4 Signer Set Integrity (MUST) | 1 | 0 · 1k | — | 0 · 1k | 0 · 1k | 1 | 0 · 1k | 1 | 0 · 1u | 0 · 1k | +| `X402-9b240d95a0`* | scheme_exact_svm.md § 2.1.4 Signer Set Integrity (MUST) | 1 | 0 · 1k | — | 0 · 1k | 0 · 1k | 1 | 0 · 1k | 1 | 0 · 1u | 0 · 1k | +| `X402-05c2aacafc`* | scheme_exact_svm.md § 3.1 Path 1 — Static Layout Verification (standard wallets) | 4 | 4 | — | 4 | 4 | 4 | 4 | 4 | 0 · 4u | 4 | | `X402-6b3e9350c8`* | scheme_exact_svm.md § 3.1 Path 1 — Static Layout Verification (standard wallets) | 7 | 5 | — | 0 · 5u | 0 · 5u | 5 | 0 · 5u | 7 | 5 | 5 · 2u | | `X402-a1cf65b0f0`* | scheme_exact_svm.md § 3.1 Path 1 — Static Layout Verification (standard wallets) | 1 | 1 | — | 1 | 1 | 1 | 1 | 1 | 0 · 1u | 1 | -| `X402-a8bd75d71b`* | scheme_exact_svm.md § 3.1 Path 1 — Static Layout Verification (standard wallets) | 4 | 4 | — | 4 | 4 | 4 | 4 | 4 | 0 · 4u | 4 | | `X402-c9a227ad88`* | scheme_exact_svm.md § 3.1 Path 1 — Static Layout Verification (standard wallets) | 3 | 3 | — | 3 | 3 | 3 | 3 | 3 | 0 · 3u | 3 | | `X402-d844c67736`* | scheme_exact_svm.md § 3.4 Post-Settlement Verification (TOCTOU defense) | 2 | 2 | — | 2 | 2 | 2 | 2 | 2 | 0 · 2u | 2 | | `X402-d5f1ded529`* | scheme_exact_svm.md § PaymentRequirements for exact | 4 | 1 | — | 0 · 1u | 0 · 1u | 1 | 0 · 1u | 4 | 1 | 4 | @@ -659,7 +666,7 @@ come from the same extraction as `pkc req-lint`. | `X402-cf373442ff`* | scheme_upto_svm.md § 4.2 UptoPayload (in PAYMENT-SIGNATURE.payload) | 3 | — | — | — | — | — | — | 3 | — | 3 | | `X402-d75fb10a6f`* | scheme_upto_svm.md § 4.2 UptoPayload (in PAYMENT-SIGNATURE.payload) | 17 | — | — | — | — | — | — | 17 | — | 16 · 1k | | `X402-eace5aece9`* | scheme_upto_svm.md § 4.2 UptoPayload (in PAYMENT-SIGNATURE.payload) | 4 | — | — | — | — | — | — | 4 | — | 3 · 1u | -| `X402-3b5914a7c5`* | scheme_upto_svm.md § 8. Security Properties | 1 | — | — | — | — | — | — | 1 | — | 1 | +| `X402-3b5914a7c5`* | scheme_upto_svm.md § 8. Security Properties | 4 | — | — | — | — | — | — | 4 | — | 4 | | `X402-076bb2bdc3`* | scheme_upto_svm.md § Canonical open instruction | 1 | — | — | — | — | — | — | 1 | — | 0 · 1k | | `X402-14b8b2b598`* | scheme_upto_svm.md § Canonical open instruction | 2 | — | — | — | — | — | — | 2 | — | 2 | | `X402-4c364688fc`* | scheme_upto_svm.md § Canonical open instruction | 1 | — | — | — | — | — | — | 1 | — | 1 | @@ -669,48 +676,51 @@ come from the same extraction as `pkc req-lint`. | `X402-e829ad118e`* | scheme_upto_svm.md § Canonical open instruction | 15 | — | — | — | — | — | — | 15 | — | 15 | | `X402-52c9f1e405`* | scheme_upto_svm.md § Client-supplied openTransaction acceptance policy | 2 | — | — | — | — | — | — | 2 | — | 2 | | `X402-005b043052`* | scheme_upto_svm.md § Message and signer rules | 4 | — | — | — | — | — | — | 4 | — | 4 | +| `X402-4de59a1f27`* | scheme_upto_svm.md § Message and signer rules | 2 | — | — | — | — | — | — | 2 | — | 2 | | `X402-9af8f33cd6`* | scheme_upto_svm.md § Message and signer rules | 2 | — | — | — | — | — | — | 2 | — | 2 | -| `X402-9d68660de5`* | scheme_upto_svm.md § Message and signer rules | 2 | — | — | — | — | — | — | 2 | — | 1 · 1k | +| `X402-9d68660de5`* | scheme_upto_svm.md § Message and signer rules | 2 | — | — | — | — | — | — | 2 | — | 2 | | `X402-bcbf7025e5`* | scheme_upto_svm.md § Message and signer rules | 2 | — | — | — | — | — | — | 2 | — | 2 | -| `X402-c1174b72d8`* | scheme_upto_svm.md § Message and signer rules | 2 | — | — | — | — | — | — | 2 | — | 2 | | `X402-f747c74e76`* | scheme_upto_svm.md § Phase 2 - Authorization | 1 | — | — | — | — | — | — | 1 | — | 1 | | `X402-11bbb0287f`* | scheme_upto_svm.md § Top-level instruction layout | 1 | — | — | — | — | — | — | 1 | — | 1 | -| `X402-233dcf8a3e`* | scheme_upto_svm.md § Top-level instruction layout | 2 | — | — | — | — | — | — | 2 | — | 2 | -| `X402-443a167ea1`* | scheme_upto_svm.md § Top-level instruction layout | 3 | — | — | — | — | — | — | 3 | — | 3 | -| `X402-683361bbae`* | scheme_upto_svm.md § Top-level instruction layout | 3 | — | — | — | — | — | — | 3 | — | 2 · 1k | +| `X402-233dcf8a3e`* | scheme_upto_svm.md § Top-level instruction layout | 5 | — | — | — | — | — | — | 5 | — | 5 | +| `X402-443a167ea1`* | scheme_upto_svm.md § Top-level instruction layout | 4 | — | — | — | — | — | — | 4 | — | 4 | +| `X402-683361bbae`* | scheme_upto_svm.md § Top-level instruction layout | 3 | — | — | — | — | — | — | 3 | — | 3 | | `X402-7cd3ca69a6`* | scheme_upto_svm.md § Top-level instruction layout | 2 | — | — | — | — | — | — | 2 | — | 2 | | `X402-b2b604a864`* | scheme_upto_svm.md § Top-level instruction layout | 4 | — | — | — | — | — | — | 4 | — | 4 | -| `X402-b4167aad45`* | scheme_upto_svm.md § Top-level instruction layout | 4 | — | — | — | — | — | — | 4 | — | 3 · 1k | +| `X402-b4167aad45`* | scheme_upto_svm.md § Top-level instruction layout | 6 | — | — | — | — | — | — | 6 | — | 6 | | `X402-c8544c0fdd`* | scheme_upto_svm.md § Top-level instruction layout | 3 | — | — | — | — | — | — | 3 | — | 3 | -| `X402-ce3692afe0`* | scheme_upto_svm.md § Top-level instruction layout | 17 | — | — | — | — | — | — | 17 | — | 12 · 5k | +| `X402-ce3692afe0`* | scheme_upto_svm.md § Top-level instruction layout | 17 | — | — | — | — | — | — | 17 | — | 17 | | `X402-d0ce5e5325`* | scheme_upto_svm.md § Top-level instruction layout | 3 | — | — | — | — | — | — | 3 | — | 3 | | `X402-d46a6b2b3b`* | scheme_upto_svm.md § Top-level instruction layout | 2 | — | — | — | — | — | — | 2 | — | 2 | -| `X402TX-4750df8921`* | scheme_batch_settlement_svm.md § 4.3 Client PaymentPayload Variants | 1 | — | — | — | — | — | — | 1 | — | 0 · 1k | +| `X402TX-4750df8921`* | scheme_batch_settlement_svm.md § 4.3 Client PaymentPayload Variants | 1 | — | — | — | — | — | — | 1 | — | 0 · 1u | | `X402TX-f39a33ff74`* | scheme_batch_settlement_svm.md § Transaction versions | 4 | 0 · 2k | — | 0 · 2k | 0 · 2u | 0 · 2u | 0 · 2k | 4 | 0 · 2k | 2 · 2u | -| `X402TX-516a2d7b57`* | scheme_exact_svm.md § 1.4 Exactly One Matching Transfer (MUST) | 1 | 0 · 1k | — | 0 · 1k | 0 · 1k | 0 · 1k | 0 · 1k | 1 | 0 · 1u | 0 · 1u | -| `X402TX-ee90546220`* | scheme_exact_svm.md § 1.4 Exactly One Matching Transfer (MUST) | 3 | 0 · 3k | — | 0 · 3k | 0 · 3k | 0 · 3k | 0 · 3k | 3 | 0 · 3u | 0 · 3u | -| `X402TX-24efe57db3`* | scheme_exact_svm.md § 1.5 Transaction Versions (MUST) | 4 | 1 · 3k | — | 1 · 3k | 1 · 3k | 1 · 3k | 1 · 3k | 4 | 0 · 4u | 0 · 2u · 2k | -| `X402TX-2909c4b4ec`* | scheme_exact_svm.md § 1.5 Transaction Versions (MUST) | 5 | 0 · 3k | — | 0 · 3u | 0 · 3u | 0 · 3k | 0 · 3u | 5 | 0 · 3k | 0 · 1u · 4k | -| `X402TX-61c735c7a9`* | scheme_exact_svm.md § 1.5 Transaction Versions (MUST) | 11 | 3 · 4k | — | 0 · 7u | 0 · 7u | 3 · 4k | 0 · 7u | 11 | 3 · 4k | 4 · 3u · 4k | -| `X402TX-644919eb3b`* | scheme_exact_svm.md § 1.5 Transaction Versions (MUST) | 10 | 3 | — | 3 | 3 | 1 · 2k | 0 · 3k | 10 | 0 · 3u | 0 · 3u · 7k | -| `X402TX-77742f428c`* | scheme_exact_svm.md § 1.5 Transaction Versions (MUST) | 2 | 0 · 1k | — | 0 · 1u | 0 · 1u | 0 · 1k | 0 · 1u | 2 | 0 · 1k | 1 · 1k | -| `X402TX-dc7b0f3305`* | scheme_exact_svm.md § 1.5 Transaction Versions (MUST) | 8 | 1 · 2k | — | 1 · 2k | 1 · 2k | 0 · 3k | 0 · 3k | 8 | 0 · 3u | 0 · 3u · 5k | -| `X402TX-9b240d95a0`* | scheme_exact_svm.md § 2.1.4 Signer Set Integrity (MUST) | 1 | 0 · 1k | — | 0 · 1k | 0 · 1k | 1 | 0 · 1k | 1 | 0 · 1u | 0 · 1u | -| `X402TX-936b492daa`* | scheme_exact_svm.md § 2.2.1 Compute Budget Controls (SHOULD) | 3 | 1 | — | 1 | 1 | 1 | 0 · 1k | 3 | 0 · 1u | 0 · 1u · 2k | -| `X402TX-eb681e1701`* | scheme_exact_svm.md § 2.2.1 Compute Budget Controls (SHOULD) | 6 | 2 · 4k | — | 2 · 4k | 2 · 4k | 0 · 6k | 0 · 6k | 6 | 0 · 6u | 0 · 6u | -| `X402TX-2ad7a3f326`* | scheme_exact_svm.md § 3.1 Path 1 — Static Layout Verification (standard wallets) | 2 | 0 · 2k | — | 0 · 2k | 0 · 2k | 0 · 2k | 0 · 2k | 2 | 0 · 2u | 0 · 2u | -| `X402TX-d188782061`* | scheme_exact_svm.md § 3.1 Path 1 — Static Layout Verification (standard wallets) | 3 | 0 · 3k | — | 0 · 3k | 0 · 3k | 0 · 3k | 0 · 3k | 3 | 0 · 3u | 0 · 3u | -| `X402TX-bc031b7add`* | scheme_exact_svm.md § 3.2 Path 2 — Simulation-Based Smart Wallet Verification | 1 | 0 · 1k | — | 0 · 1k | 0 · 1k | 0 · 1k | 0 · 1k | 1 | 0 · 1u | 0 · 1u | -| `X402TX-dd5384e0fe`* | scheme_exact_svm.md § 3.2 Path 2 — Simulation-Based Smart Wallet Verification | 1 | 0 · 1k | — | 0 · 1k | 0 · 1k | 0 · 1k | 0 · 1k | 1 | 0 · 1u | 0 · 1u | -| `X402TX-f9c2b66234`* | scheme_exact_svm.md § 3.2 Path 2 — Simulation-Based Smart Wallet Verification | 2 | 0 · 2k | — | 0 · 2k | 0 · 2k | 0 · 2k | 0 · 2k | 2 | 0 · 2u | 0 · 2u | -| `X402TX-10b3fe2ef3`* | scheme_exact_svm.md § PaymentPayload payload Field | 5 | 2 · 3k | — | 1 · 2u · 2k | 1 · 2u · 2k | 2 · 3k | 1 · 2u · 2k | 5 | 1 · 3u · 1k | 1 · 2u · 2k | -| `X402TX-d444d01b9e`* | scheme_upto_svm.md § 4.2 UptoPayload (in PAYMENT-SIGNATURE.payload) | 3 | — | — | — | — | — | — | 3 | — | 0 · 3k | -| `X402TX-4de59a1f27`* | scheme_upto_svm.md § Message and signer rules | 6 | — | — | — | — | — | — | 6 | — | 1 · 5k | -| `X402TX-0f874a9c63`* | scheme_upto_svm.md § Top-level instruction layout | 12 | — | — | — | — | — | — | 12 | — | 0 · 12k | -| `X402TX-125d312b26`* | scheme_upto_svm.md § Top-level instruction layout | 2 | — | — | — | — | — | — | 2 | — | 0 · 2k | -| `X402TX-5267172b18`* | scheme_upto_svm.md § Transaction versions | 4 | — | — | — | — | — | — | 4 | — | 0 · 4k | - -
Unmapped normative sentences by spec file and section (1307) +| `X402TX-516a2d7b57`* | scheme_exact_svm.md § 1.4 Exactly One Matching Transfer (MUST) | 1 | 0 · 1k | — | 0 · 1k | 0 · 1k | 0 · 1k | 0 · 1k | 1 | 0 · 1u | 1 | +| `X402TX-ee90546220`* | scheme_exact_svm.md § 1.4 Exactly One Matching Transfer (MUST) | 3 | 0 · 3k | — | 0 · 3k | 0 · 3k | 0 · 3k | 0 · 3k | 3 | 0 · 3u | 3 | +| `X402TX-24efe57db3`* | scheme_exact_svm.md § 1.5 Transaction Versions (MUST) | 4 | 1 · 3k | — | 1 · 3k | 1 · 3k | 1 · 3k | 1 · 3k | 4 | 0 · 4u | 2 · 2u | +| `X402TX-2909c4b4ec`* | scheme_exact_svm.md § 1.5 Transaction Versions (MUST) | 5 | 0 · 3k | — | 0 · 3u | 0 · 3u | 0 · 3k | 0 · 3u | 5 | 0 · 3k | 5 | +| `X402TX-4cd70365fd`* | scheme_exact_svm.md § 1.5 Transaction Versions (MUST) | 1 | 1 | — | 1 | 1 | 1 | 0 · 1k | 1 | 0 · 1u | 1 | +| `X402TX-61c735c7a9`* | scheme_exact_svm.md § 1.5 Transaction Versions (MUST) | 11 | 3 · 4k | — | 0 · 7u | 0 · 7u | 3 · 4k | 0 · 7u | 11 | 3 · 4k | 10 · 1u | +| `X402TX-74fb884aa9`* | scheme_exact_svm.md § 1.5 Transaction Versions (MUST) | 1 | 0 · 1k | — | 0 · 1k | 0 · 1k | 0 · 1k | 0 · 1k | 1 | 0 · 1u | 1 | +| `X402TX-77742f428c`* | scheme_exact_svm.md § 1.5 Transaction Versions (MUST) | 2 | 0 · 1k | — | 0 · 1u | 0 · 1u | 0 · 1k | 0 · 1u | 2 | 0 · 1k | 2 | +| `X402TX-927d17b62e`* | scheme_exact_svm.md § 1.5 Transaction Versions (MUST) | 2 | 0 · 2k | — | 0 · 2u | 0 · 2u | 0 · 2k | 0 · 2u | 2 | 0 · 2k | 2 | +| `X402TX-dc7b0f3305`* | scheme_exact_svm.md § 1.5 Transaction Versions (MUST) | 8 | 1 · 2k | — | 1 · 2k | 1 · 2k | 0 · 3k | 0 · 3k | 8 | 0 · 3u | 8 | +| `X402TX-f9bcc1a14a`* | scheme_exact_svm.md § 1.5 Transaction Versions (MUST) | 11 | 3 · 1k | — | 3 · 1k | 3 · 1k | 1 · 3k | 0 · 4k | 11 | 0 · 4u | 11 | +| `X402TX-9b240d95a0`* | scheme_exact_svm.md § 2.1.4 Signer Set Integrity (MUST) | 1 | 0 · 1k | — | 0 · 1k | 0 · 1k | 1 | 0 · 1k | 1 | 0 · 1u | 0 · 1k | +| `X402TX-915632f040`* | scheme_exact_svm.md § 2.2.1 Compute Budget Controls (SHOULD) | 3 | 1 | — | 1 | 1 | 1 | 0 · 1k | 3 | 0 · 1u | 3 | +| `X402TX-997feeb51d`* | scheme_exact_svm.md § 2.2.1 Compute Budget Controls (SHOULD) | 9 | 3 · 6k | — | 3 · 6k | 3 · 6k | 0 · 9k | 0 · 9k | 9 | 0 · 9u | 8 · 1k | +| `X402TX-4c2fd60e66`* | scheme_exact_svm.md § 3.1 Path 1 — Static Layout Verification (standard wallets) | 3 | 0 · 3k | — | 0 · 3k | 0 · 3k | 0 · 3k | 0 · 3k | 3 | 0 · 3u | 3 | +| `X402TX-655bb4a79a`* | scheme_exact_svm.md § 3.1 Path 1 — Static Layout Verification (standard wallets) | 2 | 0 · 2k | — | 0 · 2k | 0 · 2k | 0 · 2k | 0 · 2k | 2 | 0 · 2u | 2 | +| `X402TX-bc031b7add`* | scheme_exact_svm.md § 3.2 Path 2 — Simulation-Based Smart Wallet Verification | 1 | 0 · 1k | — | 0 · 1k | 0 · 1k | 0 · 1k | 0 · 1k | 1 | 0 · 1u | 1 | +| `X402TX-dd5384e0fe`* | scheme_exact_svm.md § 3.2 Path 2 — Simulation-Based Smart Wallet Verification | 1 | 0 · 1k | — | 0 · 1k | 0 · 1k | 0 · 1k | 0 · 1k | 1 | 0 · 1u | 1 | +| `X402TX-f9c2b66234`* | scheme_exact_svm.md § 3.2 Path 2 — Simulation-Based Smart Wallet Verification | 2 | 0 · 2k | — | 0 · 2k | 0 · 2k | 0 · 2k | 0 · 2k | 2 | 0 · 2u | 2 | +| `X402TX-10b3fe2ef3`* | scheme_exact_svm.md § PaymentPayload payload Field | 5 | 2 · 3k | — | 1 · 2u · 2k | 1 · 2u · 2k | 2 · 3k | 1 · 2u · 2k | 5 | 1 · 3u · 1k | 4 · 1u | +| `X402TX-d444d01b9e`* | scheme_upto_svm.md § 4.2 UptoPayload (in PAYMENT-SIGNATURE.payload) | 3 | — | — | — | — | — | — | 3 | — | 3 | +| `X402TX-4de59a1f27`* | scheme_upto_svm.md § Message and signer rules | 6 | — | — | — | — | — | — | 6 | — | 4 · 2u | +| `X402TX-125d312b26`* | scheme_upto_svm.md § Top-level instruction layout | 2 | — | — | — | — | — | — | 2 | — | 2 | +| `X402TX-703c03cfb5`* | scheme_upto_svm.md § Top-level instruction layout | 14 | — | — | — | — | — | — | 14 | — | 14 | +| `X402TX-5267172b18`* | scheme_upto_svm.md § Transaction versions | 4 | — | — | — | — | — | — | 4 | — | 0 · 4u | + +
Unmapped normative sentences by spec file and section (1460) | Spec file | Section | Normative | Mapped | Unmapped | | --- | --- | ---: | ---: | ---: | @@ -852,22 +862,41 @@ come from the same extraction as `pkc req-lint`. | `draft-solana-session-00.md` | Channel Exhaustion | 1 | 0 | 1 | | `draft-solana-session-00.md` | Clock Skew | 1 | 0 | 1 | | `draft-solana-session-00.md` | Solana Verification Programs | 1 | 0 | 1 | -| `x402-specification-v2.md` | X402 Protocol Specification | 10 | 0 | 10 | +| `x402-specification-v2.md` | 5.1.1 JSON Payload | 1 | 0 | 1 | +| `x402-specification-v2.md` | 5.3.2 Field Descriptions | 1 | 0 | 1 | +| `x402-specification-v2.md` | 6.1 Asset Transfer Methods and Payment Flow Models | 5 | 0 | 5 | +| `x402-specification-v2.md` | 7.1 POST /verify | 1 | 0 | 1 | +| `x402-specification-v2.md` | 7.2 POST /settle | 1 | 0 | 1 | +| `x402-specification-v2.md` | 9. Error Handling | 2 | 0 | 2 | | `scheme_exact.md` | Asset Transfer Method Families | 1 | 0 | 1 | | `scheme_exact.md` | Facilitator-submitted | 5 | 0 | 5 | | `scheme_exact.md` | Client-submitted (payment proof) | 12 | 2 | 10 | -| `scheme_exact.md` | SVM | 3 | 1 | 2 | +| `scheme_exact.md` | SVM | 5 | 1 | 4 | +| `scheme_exact.md` | Multi-Payee Splits (Optional Extension) | 9 | 0 | 9 | | `scheme_exact_svm.md` | Exact Payment Scheme for Solana Virtual Machine (SVM) (exact) | 1 | 0 | 1 | -| `scheme_exact_svm.md` | PaymentRequirements for exact | 2 | 1 | 1 | +| `scheme_exact_svm.md` | PaymentRequirements for exact | 3 | 1 | 2 | +| `scheme_exact_svm.md` | PaymentPayload payload Field | 1 | 0 | 1 | | `scheme_exact_svm.md` | 1.1 Required Payment Outcome (MUST) | 2 | 0 | 2 | | `scheme_exact_svm.md` | 1.2 Payment Identification (MUST) | 1 | 0 | 1 | +| `scheme_exact_svm.md` | 1.4 Exactly One Matching Transfer (MUST) | 5 | 4 | 1 | +| `scheme_exact_svm.md` | 1.5 Transaction Versions (MUST) | 12 | 0 | 12 | +| `scheme_exact_svm.md` | 2.1.1 Fee Payer Isolation (MUST) | 4 | 3 | 1 | | `scheme_exact_svm.md` | 2.1.2 Address Lookup Table Visibility (MUST) | 3 | 0 | 3 | | `scheme_exact_svm.md` | 2.1.5 Exact Payment Verification (MUST) | 1 | 0 | 1 | +| `scheme_exact_svm.md` | 2.2.1 Compute Budget Controls (SHOULD) | 2 | 0 | 2 | | `scheme_exact_svm.md` | 2.3 Policy Flexibility (Explicit) | 1 | 0 | 1 | | `scheme_exact_svm.md` | 3. Reference Verification Implementation (Two-Path) | 1 | 0 | 1 | -| `scheme_exact_svm.md` | 3.2 Path 2 — Simulation-Based Smart Wallet Verification | 5 | 0 | 5 | +| `scheme_exact_svm.md` | 3.1 Path 1 — Static Layout Verification (standard wallets) | 7 | 4 | 3 | +| `scheme_exact_svm.md` | 3.2 Path 2 — Simulation-Based Smart Wallet Verification | 6 | 0 | 6 | | `scheme_exact_svm.md` | 3.3 Path Selection (Path 1 → Path 2) | 1 | 0 | 1 | -| `scheme_exact_svm.md` | 3.4 Post-Settlement Verification (TOCTOU defense) | 2 | 1 | 1 | +| `scheme_exact_svm.md` | 3.4 Post-Settlement Verification (TOCTOU defense) | 3 | 1 | 2 | +| `scheme_exact_svm.md` | 5.1 extra.splits Schema | 7 | 0 | 7 | +| `scheme_exact_svm.md` | 5.2 Amount Semantics (MUST) | 4 | 0 | 4 | +| `scheme_exact_svm.md` | 5.3 Payment Outcome with Splits (MUST) | 5 | 0 | 5 | +| `scheme_exact_svm.md` | 5.4 Recipient ATA Creation (MUST) | 7 | 0 | 7 | +| `scheme_exact_svm.md` | 5.5 Capability Advertisement and Sponsor Acceptance with Splits (MUST) | 5 | 0 | 5 | +| `scheme_exact_svm.md` | 5.6 Client-Side Verification (MUST) | 2 | 0 | 2 | +| `scheme_exact_svm.md` | 5.7 Static Layout with Splits (MUST) | 3 | 0 | 3 | | `scheme_upto.md` | Core Properties (MUST) | 1 | 0 | 1 | | `scheme_upto.md` | 1. Single-Use Authorization | 2 | 0 | 2 | | `scheme_upto.md` | 2. Time-Bound Authorization | 2 | 1 | 1 | @@ -877,17 +906,19 @@ come from the same extraction as `pkc req-lint`. | `scheme_upto_svm.md` | 1. Purpose | 1 | 0 | 1 | | `scheme_upto_svm.md` | 3. Payment-channel Method | 2 | 1 | 1 | | `scheme_upto_svm.md` | 4. Wire Format | 1 | 0 | 1 | -| `scheme_upto_svm.md` | 4.2 UptoPayload (in PAYMENT-SIGNATURE.payload) | 7 | 6 | 1 | +| `scheme_upto_svm.md` | 4.2 UptoPayload (in PAYMENT-SIGNATURE.payload) | 8 | 6 | 2 | | `scheme_upto_svm.md` | 4.3 SettlementResponse (in PAYMENT-RESPONSE) | 1 | 0 | 1 | | `scheme_upto_svm.md` | Phase 1 - Setup | 1 | 0 | 1 | | `scheme_upto_svm.md` | Phase 2 - Authorization | 3 | 1 | 2 | | `scheme_upto_svm.md` | Phase 3 - Deposit settle (before resource execution) | 1 | 0 | 1 | | `scheme_upto_svm.md` | Client-supplied openTransaction acceptance policy | 2 | 1 | 1 | +| `scheme_upto_svm.md` | Transaction versions | 12 | 0 | 12 | | `scheme_upto_svm.md` | Message and signer rules | 6 | 5 | 1 | -| `scheme_upto_svm.md` | Top-level instruction layout | 13 | 12 | 1 | +| `scheme_upto_svm.md` | Top-level instruction layout | 16 | 12 | 4 | | `scheme_upto_svm.md` | Canonical open instruction | 9 | 7 | 2 | | `scheme_upto_svm.md` | Server-initiated /settle request | 3 | 0 | 3 | | `scheme_upto_svm.md` | Facilitator settlement procedure | 6 | 0 | 6 | +| `scheme_upto_svm.md` | Facilitator-built transactions | 2 | 0 | 2 | | `scheme_upto_svm.md` | Duplicate Settlement Mitigation | 5 | 0 | 5 | | `scheme_upto_svm.md` | 6. Asynchronous Recovery and Channel Discovery | 1 | 0 | 1 | | `scheme_upto_svm.md` | 6.1 Discovery RPC | 4 | 0 | 4 | @@ -897,25 +928,27 @@ come from the same extraction as `pkc req-lint`. | `scheme_batch_settlement.md` | Commitment identifier | 1 | 0 | 1 | | `scheme_batch_settlement.md` | Network requirements | 1 | 0 | 1 | | `scheme_batch_settlement_svm.md` | 1. Purpose | 1 | 0 | 1 | +| `scheme_batch_settlement_svm.md` | 2. Mapping the Core Requirements to SVM | 1 | 0 | 1 | | `scheme_batch_settlement_svm.md` | 3. Payment-Channel Method | 22 | 4 | 18 | | `scheme_batch_settlement_svm.md` | 4. Wire Format | 1 | 0 | 1 | | `scheme_batch_settlement_svm.md` | 4.1 PaymentRequirements (in PAYMENT-REQUIRED.accepts[]) | 13 | 6 | 7 | | `scheme_batch_settlement_svm.md` | 4.2 Shared Wire Objects and Program Mapping | 22 | 10 | 12 | -| `scheme_batch_settlement_svm.md` | 4.3 Client PaymentPayload Variants | 10 | 6 | 4 | +| `scheme_batch_settlement_svm.md` | 4.3 Client PaymentPayload Variants | 12 | 6 | 6 | | `scheme_batch_settlement_svm.md` | 4.4 SettlementResponse (in PAYMENT-RESPONSE) | 2 | 1 | 1 | | `scheme_batch_settlement_svm.md` | POST /verify | 5 | 3 | 2 | -| `scheme_batch_settlement_svm.md` | POST /settle | 28 | 7 | 21 | -| `scheme_batch_settlement_svm.md` | GET /supported | 3 | 1 | 2 | +| `scheme_batch_settlement_svm.md` | POST /settle | 30 | 8 | 22 | +| `scheme_batch_settlement_svm.md` | GET /supported | 3 | 2 | 1 | | `scheme_batch_settlement_svm.md` | 4.6 Corrective PaymentRequired | 3 | 2 | 1 | | `scheme_batch_settlement_svm.md` | Phase 1 - Open or Top Up | 5 | 3 | 2 | +| `scheme_batch_settlement_svm.md` | Transaction versions | 12 | 0 | 12 | | `scheme_batch_settlement_svm.md` | Message and signer rules | 9 | 7 | 2 | -| `scheme_batch_settlement_svm.md` | Top-level instruction layout | 13 | 10 | 3 | -| `scheme_batch_settlement_svm.md` | Canonical open | 3 | 1 | 2 | -| `scheme_batch_settlement_svm.md` | Canonical top_up | 11 | 4 | 7 | +| `scheme_batch_settlement_svm.md` | Top-level instruction layout | 15 | 10 | 5 | +| `scheme_batch_settlement_svm.md` | Canonical open | 3 | 2 | 1 | +| `scheme_batch_settlement_svm.md` | Canonical top_up | 11 | 5 | 6 | | `scheme_batch_settlement_svm.md` | Canonical refund request_close | 8 | 4 | 4 | | `scheme_batch_settlement_svm.md` | Phase 2 - Steady-State Request | 3 | 0 | 3 | | `scheme_batch_settlement_svm.md` | Phase 3 - Voucher Acceptance (before serving) | 14 | 5 | 9 | -| `scheme_batch_settlement_svm.md` | Phase 4 - Batched Redemption (out of band) | 2 | 0 | 2 | +| `scheme_batch_settlement_svm.md` | Facilitator-built transactions and batching capacity | 6 | 0 | 6 | | `scheme_batch_settlement_svm.md` | Phase 5 - Duplicate and Concurrent Operation Handling | 6 | 0 | 6 | | `scheme_batch_settlement_svm.md` | 6. Asynchronous Recovery and Channel Discovery | 1 | 0 | 1 | | `scheme_batch_settlement_svm.md` | 6.1 getProgramAccounts Discovery | 5 | 0 | 5 | @@ -1040,23 +1073,30 @@ come from the same extraction as `pkc req-lint`. | `draft-solana-session-00.md` | Clock Skew | 1 | 0 | 1 | | `draft-solana-session-00.md` | Solana Verification Programs | 1 | 0 | 1 | | `scheme_exact_svm.md` | Exact Payment Scheme for Solana Virtual Machine (SVM) (exact) | 1 | 0 | 1 | -| `scheme_exact_svm.md` | PaymentRequirements for exact | 2 | 0 | 2 | +| `scheme_exact_svm.md` | PaymentRequirements for exact | 3 | 0 | 3 | | `scheme_exact_svm.md` | 1.1 Required Payment Outcome (MUST) | 2 | 0 | 2 | | `scheme_exact_svm.md` | 1.2 Payment Identification (MUST) | 1 | 0 | 1 | -| `scheme_exact_svm.md` | 1.4 Exactly One Matching Transfer (MUST) | 4 | 2 | 2 | -| `scheme_exact_svm.md` | 1.5 Transaction Versions (MUST) | 8 | 7 | 1 | +| `scheme_exact_svm.md` | 1.4 Exactly One Matching Transfer (MUST) | 5 | 2 | 3 | +| `scheme_exact_svm.md` | 1.5 Transaction Versions (MUST) | 12 | 10 | 2 | | `scheme_exact_svm.md` | 2.1 Minimal Safety Baseline (Normative MUSTs) | 1 | 0 | 1 | -| `scheme_exact_svm.md` | 2.1.1 Fee Payer Isolation (MUST) | 3 | 0 | 3 | +| `scheme_exact_svm.md` | 2.1.1 Fee Payer Isolation (MUST) | 4 | 0 | 4 | | `scheme_exact_svm.md` | 2.1.2 Address Lookup Table Visibility (MUST) | 3 | 0 | 3 | | `scheme_exact_svm.md` | 2.1.3 Fee Payer Fund Safety (MUST) | 1 | 0 | 1 | | `scheme_exact_svm.md` | 2.1.4 Signer Set Integrity (MUST) | 2 | 1 | 1 | | `scheme_exact_svm.md` | 2.1.5 Exact Payment Verification (MUST) | 1 | 0 | 1 | | `scheme_exact_svm.md` | 2.3 Policy Flexibility (Explicit) | 1 | 0 | 1 | | `scheme_exact_svm.md` | 3. Reference Verification Implementation (Two-Path) | 1 | 0 | 1 | -| `scheme_exact_svm.md` | 3.1 Path 1 — Static Layout Verification (standard wallets) | 6 | 2 | 4 | -| `scheme_exact_svm.md` | 3.2 Path 2 — Simulation-Based Smart Wallet Verification | 5 | 3 | 2 | +| `scheme_exact_svm.md` | 3.1 Path 1 — Static Layout Verification (standard wallets) | 7 | 2 | 5 | +| `scheme_exact_svm.md` | 3.2 Path 2 — Simulation-Based Smart Wallet Verification | 6 | 3 | 3 | | `scheme_exact_svm.md` | 3.3 Path Selection (Path 1 → Path 2) | 1 | 0 | 1 | -| `scheme_exact_svm.md` | 3.4 Post-Settlement Verification (TOCTOU defense) | 2 | 0 | 2 | +| `scheme_exact_svm.md` | 3.4 Post-Settlement Verification (TOCTOU defense) | 3 | 0 | 3 | +| `scheme_exact_svm.md` | 5.1 extra.splits Schema | 7 | 0 | 7 | +| `scheme_exact_svm.md` | 5.2 Amount Semantics (MUST) | 4 | 0 | 4 | +| `scheme_exact_svm.md` | 5.3 Payment Outcome with Splits (MUST) | 5 | 0 | 5 | +| `scheme_exact_svm.md` | 5.4 Recipient ATA Creation (MUST) | 7 | 0 | 7 | +| `scheme_exact_svm.md` | 5.5 Capability Advertisement and Sponsor Acceptance with Splits (MUST) | 5 | 0 | 5 | +| `scheme_exact_svm.md` | 5.6 Client-Side Verification (MUST) | 2 | 0 | 2 | +| `scheme_exact_svm.md` | 5.7 Static Layout with Splits (MUST) | 3 | 0 | 3 | | `scheme_upto_svm.md` | 1. Purpose | 1 | 0 | 1 | | `scheme_upto_svm.md` | 2. Mapping the five core requirements to SVM | 3 | 0 | 3 | | `scheme_upto_svm.md` | 3. Payment-channel Method | 2 | 0 | 2 | @@ -1068,7 +1108,7 @@ come from the same extraction as `pkc req-lint`. | `scheme_upto_svm.md` | Phase 2 - Authorization | 3 | 0 | 3 | | `scheme_upto_svm.md` | Phase 3 - Deposit settle (before resource execution) | 1 | 0 | 1 | | `scheme_upto_svm.md` | Client-supplied openTransaction acceptance policy | 2 | 0 | 2 | -| `scheme_upto_svm.md` | Transaction versions | 8 | 7 | 1 | +| `scheme_upto_svm.md` | Transaction versions | 12 | 9 | 3 | | `scheme_upto_svm.md` | Message and signer rules | 6 | 1 | 5 | | `scheme_upto_svm.md` | Top-level instruction layout | 16 | 3 | 13 | | `scheme_upto_svm.md` | Canonical open instruction | 9 | 0 | 9 | @@ -1091,11 +1131,11 @@ come from the same extraction as `pkc req-lint`. | `scheme_batch_settlement_svm.md` | 4.4 SettlementResponse (in PAYMENT-RESPONSE) | 2 | 0 | 2 | | `scheme_batch_settlement_svm.md` | 4.5 Facilitator Interface | 2 | 0 | 2 | | `scheme_batch_settlement_svm.md` | POST /verify | 5 | 0 | 5 | -| `scheme_batch_settlement_svm.md` | POST /settle | 28 | 0 | 28 | +| `scheme_batch_settlement_svm.md` | POST /settle | 30 | 0 | 30 | | `scheme_batch_settlement_svm.md` | GET /supported | 3 | 0 | 3 | | `scheme_batch_settlement_svm.md` | 4.6 Corrective PaymentRequired | 3 | 0 | 3 | | `scheme_batch_settlement_svm.md` | Phase 1 - Open or Top Up | 5 | 0 | 5 | -| `scheme_batch_settlement_svm.md` | Transaction versions | 8 | 7 | 1 | +| `scheme_batch_settlement_svm.md` | Transaction versions | 12 | 9 | 3 | | `scheme_batch_settlement_svm.md` | Message and signer rules | 9 | 1 | 8 | | `scheme_batch_settlement_svm.md` | Top-level instruction layout | 15 | 3 | 12 | | `scheme_batch_settlement_svm.md` | Canonical open | 3 | 0 | 3 | @@ -1103,7 +1143,7 @@ come from the same extraction as `pkc req-lint`. | `scheme_batch_settlement_svm.md` | Canonical refund request_close | 8 | 0 | 8 | | `scheme_batch_settlement_svm.md` | Phase 2 - Steady-State Request | 3 | 0 | 3 | | `scheme_batch_settlement_svm.md` | Phase 3 - Voucher Acceptance (before serving) | 14 | 0 | 14 | -| `scheme_batch_settlement_svm.md` | Facilitator-built transactions and batching capacity | 4 | 0 | 4 | +| `scheme_batch_settlement_svm.md` | Facilitator-built transactions and batching capacity | 6 | 0 | 6 | | `scheme_batch_settlement_svm.md` | Phase 5 - Duplicate and Concurrent Operation Handling | 6 | 0 | 6 | | `scheme_batch_settlement_svm.md` | 6. Asynchronous Recovery and Channel Discovery | 1 | 0 | 1 | | `scheme_batch_settlement_svm.md` | 6.1 getProgramAccounts Discovery | 5 | 0 | 5 | @@ -1128,9 +1168,10 @@ case is in no scheduled shard. | Intent | Claimed cases | Must pass | Known failing | | --- | ---: | ---: | ---: | -| charge | 159 | 136 | 23 | -| x402-exact | 75 | 58 | 17 | -| x402-upto | 12 | 9 | 3 | +| charge | 159 | 138 | 21 | +| x402-exact | 78 | 61 | 17 | +| x402-upto | 15 | 11 | 4 | +| x402-batch | 1 | 1 | 0 | **charge**: claimed cases per SDK as client (against the Rust server) and as server (against the Rust client); `k` known failing. @@ -1144,7 +1185,7 @@ case is in no scheduled shard. | ruby | | 13 | | rust | 17 | (control) | | swift | 15 · 3k | | -| typescript | 19 · 3k | 13 | +| typescript | 19 · 1k | 13 | **x402-exact**: claimed cases per SDK as client (against the Rust server) and as server (against the Rust client); `k` known failing. @@ -1156,9 +1197,9 @@ case is in no scheduled shard. | php | | 6 · 2k | | python | 5 · 1k | 6 · 2k | | ruby | | 12 · 4k | -| rust | 7 | (control) | +| rust | 8 | (control) | | swift | 5 · 1k | | -| typescript | 5 | 6 · 1k | +| typescript | 6 | 7 · 1k | **x402-upto**: claimed cases per SDK as client (against the Rust server) and as server (against the Rust client); `k` known failing. @@ -1166,9 +1207,16 @@ case is in no scheduled shard. | --- | :---: | :---: | | go | 2 · 2k | 1 · 1k | | kotlin | 2 | | -| python | 2 | 1 | -| rust | 2 | (control) | +| python | 2 | 1 · 1k | +| rust | 3 | (control) | | swift | 2 | | +| typescript | | 2 | + +**x402-batch**: claimed cases per SDK as client (against the Rust server) and as server (against the Rust client); `k` known failing. + +| SDK | as client | as server | +| --- | :---: | :---: | +| rust | 1 | (control) | 9 SDK shards, each one `Conformance / ` job in `.github/workflows/conformance.yml` on every pull request. Source: `harness/expectations/.toml` and the scenario registry in `rust/crates/conformance/src/interop/scenarios.rs`. diff --git a/harness/expectations/FINDINGS.md b/harness/expectations/FINDINGS.md index bcacb5f3d..91c136458 100644 --- a/harness/expectations/FINDINGS.md +++ b/harness/expectations/FINDINGS.md @@ -5,32 +5,6 @@ Open gaps referenced from `[[known_failing]]` entries by when it does, replace the tracking value with the issue URL and delete the section here. -Open findings from the phase-1 vectors (pinned spec text, RULINGS ids): - -## x402-overpayment-rejected - -**Case:** `vector/x402-exact-verify-overpayment-accept` -**SDKs:** typescript - -`@solana/pay-kit` verifies x402 exact payments with the vendored upstream -reference facilitator, `@x402/svm` 2.26.0. Its static-layout path (Path 1) -requires the transfer amount to equal the requirement -(`typescript/packages/pay-kit/node_modules/@x402/svm/dist/esm/exact/facilitator/index.mjs:765`, -`amount !== BigInt(requirements.amount)`), which is what the spec text for -that path describes: scheme_exact_svm.md §3.1, “Fee payer isolation, compute -budget validity (compute unit price ≤ 5 lamports/CU on this path), -destination ATA derivation, and exact amount match are enforced as before.” - -The normative outcome is looser: §1.4, “A matching transfer MAY exceed -`PaymentRequirements.amount` ... it MUST NOT be less.” §2.3 lets a sponsor be -stricter (“Sponsors MAY introduce stricter limits but MUST NOT relax the §2.1 -MUSTs.”), so RULINGS S5 reads the reference implementation's exact-amount -check as a stricter sponsor policy, which pay-kit inherits by default. -Default verifiers accept overpayment; pay-kit does not re-implement the -facilitator to get there. The fix belongs upstream, in the x402 fork -(`typescript/external/x402`): accept `amount >= requirements.amount` on the -static path and align the §3.1 wording with §1.4. - Open findings from the requirement-gap cases (`charge-*-policy.json`, `x402-*-policy.json`, added from the `pkc req-lint` gap list on 2026-10-20). Paths are file:line at the commit that recorded them. @@ -38,7 +12,7 @@ Paths are file:line at the commit that recorded them. ## x402-extra-required-signer-accepted **Case:** `vector/x402-exact-verify-extra-required-signer-reject` -**SDKs:** go, lua, php, python, ruby, typescript +**SDKs:** go, lua, php, ruby, typescript scheme_exact_svm.md §2.1.4: “The transaction MUST NOT require any signatures beyond the client and the sponsor (feePayer).” The vector adds a third key as @@ -49,7 +23,6 @@ x402 verifier accepts, because none compares the header's required signers with {fee payer, transfer authority}: - Go `go/protocols/x402/verify.go:81` (`VerifyExactTransaction`) -- Python `python/src/solana_pay_kit/protocols/x402/exact/verify.py:83` - Ruby `ruby/lib/pay_kit/protocols/x402/protocol/schemes/exact/verify.rb:33`; `verify_client_signatures!` (`:68`) only checks that each extra signer signed - PHP `php/src/Protocols/X402/Exact/Verifier.php:61` @@ -225,27 +198,38 @@ first and report `unknown_fourth_instruction` `python/src/solana_pay_kit/protocols/x402/exact/verify.py:154` before `:169`). The verdict is right; the reason hides the fund-safety violation, and a smart-wallet path that relaxes the layout would have to catch it again. -## x402-priority-fee-product-uncapped - -**Case:** `vector/x402-exact-verify-priority-fee-over-cap-reject` -**SDKs:** go, lua, php, python, ruby, typescript - -scheme_exact_svm.md §2.2.1: “Sponsors SHOULD bound their fee exposure by -enforcing maximum compute unit limits and maximum compute unit (priority fee) -price”. The vector pairs the static layout's 200,000 unit limit with a -5,000,000 micro-lamport unit price: each is within its own cap, and the -sponsor pays a 1,000,000 lamport priority fee. Rust bounds the product at -2,000 lamports (`core::tx::check_priority_fee`, SOLA1-340, RULINGS S6); every -other x402 verifier caps the unit price alone: - -- Go `go/protocols/x402/verify.go:21` -- Python `python/src/solana_pay_kit/protocols/x402/exact/verify.py:57` -- PHP `php/src/Protocols/X402/Exact/Verifier.php:184` -- Lua `lua/pay_kit/protocols/x402/exact/verify.lua:109` -- Ruby `ruby/lib/pay_kit/protocols/x402/protocol/schemes/exact/verify.rb:147` -- TypeScript: the vendored upstream `@x402/svm` static path - (`typescript/external/x402/typescript/packages/mechanisms/svm/src/exact/facilitator/scheme.ts:1246`). - SOLA1-340 bounded the product in the TypeScript MPP charge only. +## upto-settlement-funds-recipient-ata + +**Case:** `interop/x402-upto-basic/rust/python` +**SDKs:** python + +An upto settlement co-signed by the fee payer that also creates each +distribution recipient's token account pays that account's rent, even for a +zero-amount settlement. A recipient the operator does not control can close +the account after each settlement and keep the rent. Rust creates only the +fee payer's payee account and the treasury account, and instead refuses an +open whose recipients lack a usable token account (scheme_upto_svm.md Phase 3 +settlement readiness), so a payout is never forfeited to the treasury. Python +appends `create_idempotent_associated_token_account` for every recipient +(`python/src/solana_pay_kit/protocols/x402/upto/__init__.py:446`). Fix: drop +the recipient creations and check recipient token accounts before co-signing +the open; dropping the creations alone would forfeit payouts to accounts that +do not exist. + +## batch-deposit-balance-unchecked + +**Case:** `vector/batch-verify-open-unfunded-payer-reject`, +`vector/batch-verify-top-up-unfunded-payer-reject` +**SDKs:** typescript + +scheme_batch_settlement_svm.md, canonical `open` and `top_up`: "It MUST +confirm the payer has sufficient tokens". The pay-kit gate broadcasts the +deposit only after the handler runs, so Rust reads the payer's token account +and the transaction's blockhash before it reserves the request +(`X402BatchSettlement::check_deposit_can_land`). The vendored `@x402/svm` +2.28.0 verify reads no balance; its deposit settle simulates the +transaction, which the offline harness signer stubs, so the vector cannot +observe it there. ## session-open-initial-voucher-accepted @@ -374,7 +358,7 @@ Open findings from the x402 `upto` (SVM) vectors (`x402-upto-*.json`, 2026-10-21). Rust is driven through `x402::server::upto::testkit::verify_open_pre_broadcast` (the pre-broadcast half of `X402Upto::verify_open_for_route`, co-signature included); -TypeScript through the vendored `@x402/svm` 2.26.0 upto facilitator's +TypeScript through the vendored `@x402/svm` 2.28.0 upto facilitator's read-only `verify` (pay-kit's `X402Upto.verifyOpen` calls `settle`, which broadcasts). @@ -439,29 +423,6 @@ with `getOpenInstructionDataDecoder().decode` (`typescript/external/x402/typescript/packages/mechanisms/svm/src/payment-channels/open.ts:969`), which ignores bytes past the arguments. The fix belongs in the x402 fork. -## ts-upto-open-size-unbounded - -**Case:** `vector/x402-upto-verify-v0-oversize-reject` -**SDKs:** typescript - -x402-txv1 scheme_upto_svm.md: “A legacy or version-0 transaction MUST NOT -exceed 1232 serialized bytes”. The vendored `verifyOpenTransaction` never -measures the transaction, so an oversize open is accepted and only fails at -broadcast. - -## ts-upto-no-transaction-versions - -**Cases:** every `x402-upto-txv1.json` vector that builds or verifies a version-1 open, plus `vector/x402-upto-build-no-common-version-reject` -**SDKs:** typescript - -The vendored `@x402/svm` 2.26.0 (`typescript/external/x402` at 03b3919b) -predates transaction-version negotiation, x402-foundation/x402 PR 3710 (branch -`feat/svm-transaction-versions-upto`), which implements the x402-txv1 draft -(PR 3473). Its client builds version 0 whatever `extra.transactionVersions` -advertises, and its facilitator cannot decode a version-1 message (it throws -reading the absent lookup-table list), so neither -`unsupported_transaction_version` nor the version-1 budget rules are reachable. -Resolved by bumping the vendored x402 packages once PR 3710 lands. ## txv1-ts-mpp-no-transaction-versions **Cases:** `vector/charge-wire-transaction-versions-*`, `vector/session-wire-transaction-versions-*` @@ -496,20 +457,18 @@ throws while decoding (`Cannot read properties of undefined (reading version-0 transaction is accepted for a challenge that advertises `[1]` only, legacy is accepted, and the version-0 size limit is not applied. -## txv1-ts-x402-pre-3474 +## txv1-ts-x402-v1-policy -**Cases:** `vector/x402-build-v1-advertised`, `vector/x402-build-duplicate-advertisement`, `vector/x402-build-empty-advertisement-reject`, `vector/x402-build-legacy-only-reject`, `vector/x402-verify-v1-not-accepted-reject`, `vector/x402-verify-v1-explicit-v0-sponsor-reject` +**Cases:** `vector/x402-verify-v1-compute-limit-over-cap-reject` **SDKs:** typescript -The vendored x402 (`typescript/external/x402` @03b3919b) predates -x402-foundation/x402 PR 3474 (feat/svm-transaction-versions-exact). The exact -client ignores `extra.transactionVersions` (always version 0, never -refuses), and the facilitator has no version gate: a version-1 transaction -fails as `invalid_exact_svm_payload_signature_invalid` instead of -`unsupported_transaction_version`. PR 3474 adds the gate and the client -intersection but advertises `[0]` only; version 1 itself is not implemented -upstream yet, so the version-1 accept and policy vectors stay -`[[unsupported]]` (no accepted-version set to configure) until it is. +The `@x402/svm` exact static path applies no compute unit cap unless +`maxComputeUnits` is configured, and neither the runner nor pay-kit +(`typescript/packages/pay-kit/src/config.ts`) sets it, so a version-1 +`computeUnitLimit` of 400,001 is sponsored. scheme_exact_svm.md §2.2.1 gives +400,000 as the reference default (“Max compute units | `400,000`”), which +the Rust kit now applies. Fix: default `maxComputeUnits` to 400,000 in +pay-kit or upstream. ## txv1-go @@ -600,6 +559,40 @@ regression tests, against [RULINGS.md](RULINGS.md): - `@solana/mpp` has no stateless subscription usability check and no subscriptions instruction encoder, so the `subscription-active-*` and `subscription-instruction-*` vectors are unsupported for TypeScript. +- The vendored `@x402/svm` exact, upto and batch facilitators accept a fixed + transaction-version set (legacy, 0 and 1) with no option to narrow it, so + the vectors that configure a sponsor with `[0]` + (`input.x402ServerTransactionVersions`, `batchServer.transactionVersions`) + are unsupported for TypeScript. The spec gives the sponsor's own set no + default (“The sponsor enforces its own accepted set”), so those vectors + state it. +- The TypeScript batch testee drives the stateless upstream facilitator, so + the vectors whose verdict rests on the resource server's store record alone + (`batchVerdictFromStore`, RULINGS B1: one-above, one-below, stale, + close-pending, refund at an older cumulative) are unsupported for it. + +## Reclassified on 2026-10-27 + +Findings that were the harness's, not the SDK's, and were closed by fixing +the vectors or adapters instead: + +| Finding | Resolution | +| --- | --- | +| `x402-overpayment-rejected` (TS) | §3.1 “exact amount match” and §2.3 sponsor policy make an exact-amount sponsor conformant: `x402-exact-verify-overpayment-accept` also allows `reject amount-mismatch` (`expect.alsoConformant`) | +| `x402-priority-fee-product-uncapped` (Go, Python, Ruby, PHP, Lua, TS), `x402-channel-priority-fee-product-uncapped` (TS) | the 2,000 lamport cap on limit times price is pay-kit's stricter sponsor policy (RULINGS S6); the cap vectors also allow `accept` | +| `txv1-ts-x402-v1-policy` decimals half, `batch-ts-receiver-authorizer-missing-code`, server-mode `channelConfig` in `ts-batch-client-terms`, top-up trailing byte in `ts-batch-setup-reason-code` | the spec does not fix that verdict or code; the vectors list the other conformant verdict | +| `upto-client-blockhash-not-checked` | `extra.recentBlockhash` is a hint the client MAY use (“Pre-fetched blockhash so the client can build `openTransaction` without an RPC round trip.”); the vector pinned Rust policy and was removed | +| `ts-upto-open-size-unbounded`, `ts-upto-no-transaction-versions`, `ts-batch-transaction-versions` (client), the network half of `ts-batch-accepted-not-checked` | the vendored 2.28.0 implements them; the testee mis-mapped the reasons or ignored `batchClient.maxTransactionVersion` | +| `ts-batch-open-binding-memo` (client) | the client opens with the binding memo; the build judge required the caller's `openSlot` where the spec lets the client fetch the cluster slot or use `extra.recentSlot` | +| `txv1-ts-x402-fixed-accepted-set`, `ts-batch-facilitator-stateless` | declared limitations above (`[[unsupported]]`) | + +## Fixed in the SDKs on 2026-10-27 + +| Finding | Fix | +| --- | --- | +| `ts-batch-setup-reason-code` (codes), `ts-batch-refund-cooperative` (sealed refund), `ts-batch-accepted-not-checked`, `batch-ts-receiver-authorizer-missing-code` | `@x402/svm` batch facilitator reports the spec 7 codes and compares `accepted` with the requirements (x402-foundation/x402 PR 3971, vendored at `d411aea1`) | +| `ts-charge-client-split-cap`, `charge-client-sol-token-program-ignored`, `charge-client-unknown-network`, `charge-client-amount-not-u64-validated`, `ts-charge-ata-empty-data-crash`, `session-open-initial-voucher-accepted`, the 1232-byte case of `txv1-ts-mpp-server-no-version-admission` | `@solana/mpp` charge client and server, session open schema | +| `subscription-ts-program-not-pinned`, `subscription-ts-currency-not-mint`, `subscription-ts-request-format`, `subscription-ts-plan-pullers-destinations`, `subscription-ts-recipient-ata`, `subscription-ts-push-mode`, `subscription-source-not-verified`, `subscription-ts-scope-accounts` | `@solana/mpp` subscription client and server | ## Subscription findings (`subscription-*.json`, 2026-10-21) @@ -870,89 +863,66 @@ steady-state voucher. discriminator is not `Channel` (1) with `channel_state`, so a refresh onto a `ClosedChannel` account refuses the voucher. -### TypeScript: vendored upstream `@x402/svm` 2.26.0 +### TypeScript: vendored upstream `@x402/svm` 2.28.0 pay-kit has no batch-settlement implementation of its own; the TypeScript testee drives the upstream mechanism pay-kit bundles -(`typescript/.x402-vendor/x402-svm-2.26.0.tgz`). That tarball was packed -before the pinned spec commit (it has no receiver-binding memo, no `seal`, -no transaction versions), so most of these are the tarball lagging the spec, -cross-checked against the same vectors as the Rust kit. - -## ts-batch-open-binding-memo - -**Cases:** `batch-build-deposit-open`, `batch-build-terms-payment-flow-authorization`, -`batch-verify-open-*` (typescript) - -Same rule as [batch-open-binding-memo](#batch-open-binding-memo): the client -opens without the binding memo and `verifyOpenTransaction` reports “expected -exactly one Memo instruction matching extra.memo, found 2” for the spec's open -(under the generic `transaction_failed` reason). - -## ts-batch-transaction-versions - -**Cases:** `batch-txv1-top-up-*`, `batch-build-version-intersection-empty-reject` (typescript) - -The tarball predates SVM transaction versions (x402-foundation/x402 PR 3473, -pinned as `external/x402-txv1`). A version-1 top-up crashes verification -(“Cannot read properties of undefined (reading 'length')”), a version-0 top-up -over 1232 serialized bytes is accepted, and the client builds version 0 for a -challenge that advertises only `[1]`. +(`typescript/.x402-vendor/x402-svm-2.28.0.tgz`, solana-foundation/x402 +`feat/svm-client-transaction-v1` at `f7043a1`). It implements the +receiver-binding memo and SVM transaction versions; what remains is mostly +reason codes (the generic `transaction_failed` where the scheme names a +specific code, being fixed in x402-foundation/x402 PR 3971) and a few +unchecked rules, cross-checked against the same vectors as the Rust kit. ## ts-batch-refund-cooperative -**Cases:** `batch-verify-refund-*`, `batch-txv1-refund-v1-not-advertised-reject`, -`batch-wire-payload-refund-*` (typescript) +**Cases:** `batch-verify-refund-sealed-channel-reject` (typescript) -The facilitator refuses a refund carrying the voucher with -`close_authorization` (“cooperative close requires a trusted server binding”) -instead of falling back to the `request_close` retry the pinned spec defines -for an unavailable binding, and accepts a client-mode refund without the -voucher. `isBatchPayload` applies the same superseded shape. +The refund retry (voucher plus `request_close`, RULINGS B2) now verifies. A +refund for a channel the server already sealed is refused as +`invalid_batch_settlement_svm_channel_state`; the vector expects +`invalid_batch_settlement_svm_close_state` (“the channel cannot be closed, or a +cooperative voucher does not equal server state or is behind the channel's +onchain `settled` value”). The payment is refused; only the reason differs. ## ts-batch-setup-reason-code -**Cases:** `batch-verify-top-up-*` (typescript) +**Cases:** `vector/batch-verify-top-up-frozen-payer-ata-reject` (typescript) -Every static policy violation of a top-up comes back as -`transaction_failed: verifyTopUpTransaction: …` / `verifyOpenTransaction: …` -instead of `invalid_batch_settlement_svm_setup_transaction` (spec §7: “setup -transaction fails the sponsor safety checks”). Two are not rejected at all: a -`top_up` with a trailing data byte (“The facilitator MUST fully decode the -instruction data, reject truncated data or trailing bytes”) and a top-up -whose payer return ATA is frozen (“it MUST reject before escrowing when a -settlement account is missing, frozen, has the wrong owner or mint”). A -voucher over the topped-up ceiling is `cumulative_amount_mismatch`, not -`cumulative_exceeds_deposit`. The accepting top-up and voucher cases, and the -onchain binding rejects of `batch-voucher-onchain-bindings`, pass. +The reason codes this section used to track (`transaction_failed` for every +setup-transaction violation, `cumulative_amount_mismatch` for an over-deposit +voucher, a foreign binding reported as missing) are fixed in +x402-foundation/x402 PR 3971 (`56ff3cd5`, `d411aea1`). One top-up is still not +rejected at `/verify`: a payer return ATA that is frozen (“it MUST reject +before escrowing when a settlement account is missing, frozen, has the wrong +owner or mint”). `assertSettlementAccounts` checks only that the account +exists and its owner; the top-up simulation at settle would fail it. -## ts-batch-facilitator-stateless +## ts-batch-open-slot-window -**Cases:** `batch-verify-voucher-{one-above,one-below,stale}-reject`, -`batch-verify-voucher-close-pending-in-store-reject` (typescript) +**Cases:** `batch-verify-open-stale-slot-reject`, `batch-verify-open-future-slot-reject` (typescript) -RULINGS.md B1: the vectors judge the resource server's Phase 3 rule against -its stored `chargedCumulativeAmount`; the upstream facilitator the testee -drives is stateless and applies only the onchain floor. Upstream's resource -server (`BatchSvmScheme` server hooks) holds that state, but has no -single-shot entry point the vector ABI can drive. +Phase 1: “The facilitator MUST reject an expired transaction blockhash and an +`openSlot` outside the program's accepted window.” The batch facilitator's +`verify` compares `channelConfig.openSlot` with the open instruction only; it +never reads the cluster slot, so an open 1,501 slots stale or one slot in the +future is accepted and fails only when it lands. ## ts-batch-accepted-not-checked -**Cases:** `batch-verify-accepted-{amount,pay-to,network}-mismatch-reject` (typescript) +**Cases:** `batch-verify-accepted-{amount,pay-to}-mismatch-reject` (typescript) “For every request, `paymentPayload.accepted` MUST equal -`paymentRequirements`.” The facilitator verifies against -`paymentRequirements` without comparing `accepted` (amount and payTo -mismatches are accepted) and reports a network mismatch as `network_mismatch`. +`paymentRequirements`.” The facilitator compares `accepted` with the +requirements on scheme and network only (a network mismatch is refused as +`network_mismatch`, which the harness reads as `accepted-mismatch`), so an +amount or payTo mismatch is verified against `paymentRequirements` and +accepted. ## ts-batch-client-terms -**Cases:** `batch-build-deposit-payer-is-fee-payer-reject`, -`batch-verify-voucher-server-mode-config-reject` (typescript) +**Cases:** `batch-build-deposit-payer-is-fee-payer-reject` (typescript) The client opens a channel whose payer is the challenge's own `feePayer` (“`channelConfig.payer` and `channelConfig.payerAuthorizer` MUST NOT equal -`extra.feePayer`.”). A `channelConfig.voucherSigner` that disagrees with the -route is reported as `payload_type`; the vectors use `channel_state`, the -code for a channel configuration that does not match the requirements. +`extra.feePayer`.”). diff --git a/harness/expectations/RULINGS.md b/harness/expectations/RULINGS.md index 37a347bb9..430034a44 100644 --- a/harness/expectations/RULINGS.md +++ b/harness/expectations/RULINGS.md @@ -46,8 +46,10 @@ sentence fixes the shape of a client-paid transaction; it does not oblige a client to accept the challenge, and Client-Side Verification leaves split acceptance to the client. A client that will not fund that rent declines the challenge, which is conformant; it never builds a transaction without the -instruction. Rust's low-level builder includes the creation by default, and -`PayKitClient`, whose spend cap covers only `amount`, declines. +instruction. Rust's builders decline unless the caller opts in +(`PayerFundedAtaCreation::Include`), since the rent sits outside any amount +cap; the conformance testee opts in so the vectors can pin the client-paid +shape. ## MPP core @@ -103,27 +105,45 @@ accepts a credential without decoding its transaction does not conform. 16–128 characters of `[A-Za-z0-9_-]`. A server that advertises the extension as required MUST reject a payload without a valid id. -**S5. Overpayment is tolerated by default.** scheme_exact_svm.md §1.4: “A -matching transfer MAY exceed PaymentRequirements.amount ... it MUST NOT be -less.” The generic scheme_exact.md SVM bullet (“Amount exactness: the -transferred amount MUST equal maxAmountRequired”) is listed under “Examples -include”, uses the v1 field name, and is superseded by the network binding's -normative §1 outcome definition. §2.3 lets a sponsor reject overpayment only -as an explicit stricter policy; default verifiers MUST accept it. - -**S6. A sponsor bounds the priority fee as limit times price.** +**S5. Overpayment is tolerated; an exact-amount sponsor is conformant too.** +scheme_exact_svm.md §1.4: “A matching transfer MAY exceed +PaymentRequirements.amount ... it MUST NOT be less.” The generic +scheme_exact.md SVM bullet once required the transferred amount to equal +maxAmountRequired; it now agrees with the network binding (“Amount: the +transfer to `payTo` MUST be at least `amount`”). But §3.1 still says “exact +amount match are enforced on both layouts”, and §2.3 lets a sponsor refuse a +scheme-valid transaction (“A transaction MAY be valid under the `exact` scheme +while being rejected by a sponsor's policy.”). The Rust sponsor accepts +overpayment; `x402-exact-verify-overpayment-accept` pins that and also +admits `reject amount-mismatch` (`expect.alsoConformant`). Upstream: align +the §3.1 wording with §1.4. + +**S6. A cap on limit times price is sponsor policy, not spec.** scheme_exact_svm.md §2.2.1: “Sponsors SHOULD bound their fee exposure by enforcing maximum compute unit limits and maximum compute unit (priority fee) -price”. Capping each field alone still lets the largest limit pair with the -largest price, so the fee the sponsor pays is bounded as their product. The -pay-kit sponsors cap it at 2,000 lamports; a 200,000 unit limit at 5,000,000 -micro-lamports per unit (each within its own cap, a 1,000,000 lamport fee) is -refused as `compute-price-over-cap`. Vector: -`x402-exact-verify-priority-fee-over-cap-reject`. A version-1 header -`priorityFee` is the same product, so the cap applies to it unchanged; the -txv1 per-unit cap (5 lamports per unit) still holds below it, and -`x402-verify-v1-priority-fee-{at,over}-cap-*` pin that boundary at a 300 unit -limit, where it binds before the total does. +price”, with reference defaults of 400,000 units and 5,000,000 +micro-lamports per unit, each capped on its own. Capping each field alone +still lets the largest limit pair with the largest price, so the pay-kit +sponsors also bound the fee they pay as the product, at 2,000 lamports; a +200,000 unit limit at 5,000,000 micro-lamports per unit (each within its own +cap, a 1,000,000 lamport fee) is refused as `compute-price-over-cap`. The spec +fixes no such total, so it is a stricter local policy (“Sponsors MAY +introduce stricter limits but MUST NOT relax the §2.1 MUSTs.”): the vectors +pin pay-kit's reject and also admit `accept` (`expect.alsoConformant`). +Vector: `x402-exact-verify-priority-fee-over-cap-reject`. A version-1 header +`priorityFee` is the same product; the txv1 per-unit cap (5 lamports per +unit) is spec and holds below it, and `x402-verify-v1-priority-fee-{at,over}-cap-*` +pin that boundary at a 300 unit limit, where it binds before the total does. +The same policy covers the payment-channel transactions an x402 sponsor +co-signs (upto `open`, batch `open`, `top_up` and refund `request_close`), +whose spec ceilings (400,000 units, 5,000,000 micro-lamports) are absolute +maxima a sponsor MAY tighten (“A sponsor MAY apply a stricter local policy for +compute-unit limit, compute-unit price, and required-signature count”); +without a declared limit pay-kit charges the price on the runtime default of +200,000 units per non-ComputeBudget instruction. Vectors (reject, or accept): +`x402-upto-verify-{priority-fee,implicit-limit-priority-fee,v1-priority-fee-over-sponsor}-*` +and `batch-verify-top-up-{priority-fee,implicit-limit-priority-fee}-over-cap-reject`, +`batch-txv1-top-up-v1-priority-fee-over-sponsor-cap-reject`. ## x402 upto on SVM @@ -276,9 +296,12 @@ Associated Token program. Both SDK clients prepend a `CreateIdempotent` of the subscriber's own ATA so a first-time wallet can activate; it moves no tokens. Until the draft lists it, vectors accept that one instruction and reject any other ATA creation (the recipient's, a third party's) as -`unexpected-instruction`: “MUST NOT reference writable accounts that could -redirect funds away from recipient.” Upstream: list the subscriber's -idempotent ATA creation explicitly. +`unexpected-instruction`, on the client list's closing MUST: the activation +must “contain no instructions other than those above plus optional +compute-budget and memo instructions.” Creating the recipient's ATA moves no +funds away from `recipient`, so the writable-account rule is not what refuses +it; it is an instruction the list does not name. Upstream: list the +subscriber's idempotent ATA creation explicitly. **SUB2. Activation is `type="transaction"` only.** “Solana subscription activation uses type="transaction".” and “Solana transactions containing @@ -296,6 +319,28 @@ cancellation (`delegation.expires_at_ts`) equal to `now` has taken effect: “a non-zero timestamp only blocks renewal once the current time is at or after that timestamp.” +**SUB4. The subscription authority is initialized before the activation, +not inside it (spec bug).** The client list says the activation must +“contain an `initialize_subscription_authority` instruction prepended only +when the `(subscriber, mint)` authority does not yet exist on-chain;”. But +`subscribe` commits the subscriber's signature to the authority's `init_id`, +which the program sets when `initialize_subscription_authority` lands (from +that slot), and every later access check must “require its current `init_id` +to equal the delegation header's `init_id`.” A client that signs one +transaction carrying both instructions cannot know the slot it lands in, so +it cannot sign the `init_id` `subscribe` needs: the prescribed shape cannot be +built. The Rust client sends `initialize_subscription_authority` first, in +its own subscriber-signed and subscriber-paid transaction, reads the +resulting `init_id`, then signs the activation; the Rust server refuses an +activation carrying the instruction (`invalid-payload`). The vectors do not +depend on it: every subscription fixture serves an existing authority, so no +conformant activation carries the instruction, and +`subscription-verify-unrelated-authority-init-reject` refuses one for another +mint (`unexpected-instruction`). Upstream: drop the prepended initialization from +the activation list and say the authority MUST exist before the client signs +the activation (or let `subscribe` take the `init_id` from the same +transaction). + ## x402 batch-settlement on SVM Pinned `scheme_batch_settlement_svm.md` (x402 @03b3919b); transaction-version @@ -310,9 +355,12 @@ the vector's `batchServerChannel`), so `charged + amount + 1` is rejected with `cumulative-amount-mismatch`. A stateless facilitator cannot apply this rule: it sees only onchain `settled`, and the txv1 draft gives it a floor instead (“the facilitator MUST require `maxClaimableAmount >= Channel.settled + -PaymentRequirements.amount`”). An SDK whose only verify entry point is a -facilitator therefore fails the above-amount vectors; that is a known -failure of the facilitator-only testee, not a reading of the server rule. +PaymentRequirements.amount`”). The vectors whose verdict rests on the store +record alone (above, below and at the charged watermark, a close-pending +mark, a refund at an older accepted cumulative) carry +`batchVerdictFromStore: true`; a testee whose only verify entry point is a +stateless facilitator reports them unsupported, since it cannot express the +resource server they judge. **B2. A client-mode refund carries the voucher.** “| `voucher` | `BatchVoucher` | REQUIRED in client mode.” The `request_close` transaction is the retry path @@ -331,19 +379,24 @@ requirement) is `invalid-challenge`; wire objects that do not parse are Pinned drafts: `external/mpp-specs-txv1` (solana-foundation/mpp-specs feat/solana-transaction-versions `77aa6a1`, charge and session) and -`external/x402-txv1` (x402-foundation/x402 PR 3473, solana-foundation/x402 -`3d723dd`, scheme_exact_svm.md §1.5). +`external/x402-txv1` (x402-foundation/x402 PR 3473, merged; solana-foundation/x402 +`f7043a1`, scheme_exact_svm.md §1.5). **T1. `transactionVersions` is an array of the integers 0 and 1, read as a set.** MPP: “Each entry is the integer `0` or `1`, the Wallet Standard `supportedTransactionVersions` vocabulary without `"legacy"`.” x402: “Entries -are the integers `0` and `1`”. Neither text allows a string entry, a bare +MUST be the JSON integers `0` and `1` only.” Neither text allows a string entry, a bare integer or another version, so an MPP charge or session request carrying one is malformed and the SDK's request type refuses it (`invalid-payload` in the wire vectors). A repeated entry names the same version: `[1, 1]` advertises -{1}, and a client builds version 1. x402 clients intersect the advertisement -with what they can build, so an unknown entry in an x402 offer is not by -itself a reason to refuse; the vectors pin no x402 verdict for one. +{1}, and a client builds version 1. x402 is explicit about the rest: “A +client or server MUST treat a field containing any non-integer entry (a +string, null, or "legacy") or any integer other than 0 or 1 as invalid and +fail closed with unsupported_transaction_version.” An x402 client therefore +refuses the whole offer (`unsupported-version`) rather than dropping the +entries it does not know and building from the rest +(`x402-build-unknown-entry-reject`, `x402-build-string-entry-reject`, +`x402-build-legacy-only-reject`). **T2. Present and empty is not absent.** Only an omitted field defaults: MPP “Defaults to `[0]` when omitted”, x402 “When the field is absent, the @@ -366,12 +419,19 @@ advertised version. A lookup table, a size over the version's limit, or a version-1 header without `computeUnitLimit` or `loadedAccountsDataSizeLimit` is `invalid-payload`. A ComputeBudget instruction in a version-1 message is `unexpected-instruction` for MPP charge (“Any unexpected instructions MUST -cause rejection.”) and `invalid-payload` for x402 (the static layout -mismatch). A charge or session server accepts exactly the versions its -challenge's `methodDetails.transactionVersions` lists; an x402 sponsor its -own configured set (`input.x402ServerTransactionVersions`), since “The -sponsor enforces its own accepted set; it does not read -`PaymentRequirements.extra.transactionVersions`.” +cause rejection.”), `invalid-payload` for x402 exact (the static layout +mismatch), `unexpected-instruction` for an upto open (an instruction outside +the open) and `setup-transaction` for a batch top-up. A version-1 header over +the compute caps is `compute-limit-over-cap` / `compute-price-over-cap` for +x402 exact and upto. A charge or session server accepts exactly the versions +its challenge's `methodDetails.transactionVersions` lists; an x402 sponsor +its own configured set (`input.x402ServerTransactionVersions`, +`batchServer.transactionVersions`), since “The sponsor enforces its own +accepted set; it does not read `PaymentRequirements.extra.transactionVersions`.” +That set has no default (“When the field is absent, the accepted set is +`[0]`” is about the advertised field), so every vector whose verdict depends +on it states it; an SDK whose sponsor cannot be narrowed reports those +unsupported. ## Signatures (both protocols) @@ -396,6 +456,12 @@ both specs' verification steps. ## Harness consequences +- Where the specs leave a verdict to the implementation (a sponsor's + stricter local policy, two checks in no prescribed order, a rule stated for + another instruction), a vector pins the Rust kit's verdict and lists the + other conformant ones in `expect.alsoConformant`, with the reason + (`alsoConformantReason`). The judge passes either; an accepted build is + still judged on its artifact. - Vectors encode these rulings. Runners pass chain state through the fixture RPC (`input.rpcUrl`) and MUST NOT inject defaults, resolve token programs or apply field precedence themselves. diff --git a/harness/expectations/go.toml b/harness/expectations/go.toml index 1af6b55a4..c37158c07 100644 --- a/harness/expectations/go.toml +++ b/harness/expectations/go.toml @@ -208,7 +208,11 @@ ids = [ "vector/x402-build-no-intersection-reject", "vector/x402-build-empty-advertisement-reject", "vector/x402-build-legacy-only-reject", + "vector/x402-build-unknown-entry-reject", + "vector/x402-build-string-entry-reject", "vector/x402-verify-v1-accept", + "vector/x402-verify-v1-loaded-data-limit-4mib-accept", + "vector/x402-verify-v1-loaded-data-limit-small-accept", "vector/x402-verify-v1-not-accepted-reject", "vector/x402-verify-v1-explicit-v0-sponsor-reject", "vector/x402-verify-v1-over-1232-accept", @@ -265,6 +269,8 @@ tracking = "FINDINGS.md#txv1-go" ids = [ "cross/x402-build-duplicate-advertisement/rust/go", "cross/x402-build-v1-advertised/rust/go", + "cross/x402-build-duplicate-advertisement/typescript/go", + "cross/x402-build-v1-advertised/typescript/go", ] reason = "refuses a valid version-1 x402 build: the verifier cannot decode or admit version 1" tracking = "FINDINGS.md#txv1-go" @@ -272,10 +278,6 @@ tracking = "FINDINGS.md#txv1-go" [[unsupported]] reason = "the runner's session verify path drives only the SDK's voucher verifier (input.sessionVoucherVerify); it has no path to the session server's open checks (input.sessionOpenVerify, input.sessionServerVerify)" pattern = "vector/session-open-*" -[[known_failing]] -id = "vector/x402-exact-verify-priority-fee-over-cap-reject" -reason = "the x402 exact verifier caps the unit price alone (go/protocols/x402/verify.go:21), so the 200,000 unit limit at 5,000,000 micro-lamports per unit (a 1,000,000 lamport priority fee) is sponsored (RULINGS S6)" -tracking = "FINDINGS.md#x402-priority-fee-product-uncapped" [[known_failing]] ids = [ diff --git a/harness/expectations/lua.toml b/harness/expectations/lua.toml index 6538456ae..9ae26a148 100644 --- a/harness/expectations/lua.toml +++ b/harness/expectations/lua.toml @@ -148,6 +148,8 @@ ids = [ "vector/x402-build-no-intersection-reject", "vector/x402-build-empty-advertisement-reject", "vector/x402-build-legacy-only-reject", + "vector/x402-build-unknown-entry-reject", + "vector/x402-build-string-entry-reject", ] [[known_failing]] @@ -197,6 +199,8 @@ tracking = "FINDINGS.md#txv1-lua" [[known_failing]] ids = [ "vector/x402-verify-v1-accept", + "vector/x402-verify-v1-loaded-data-limit-4mib-accept", + "vector/x402-verify-v1-loaded-data-limit-small-accept", "vector/x402-verify-v1-not-accepted-reject", "vector/x402-verify-v1-explicit-v0-sponsor-reject", "vector/x402-verify-v1-over-1232-accept", @@ -253,10 +257,8 @@ tracking = "FINDINGS.md#txv1-lua" ids = [ "cross/x402-build-duplicate-advertisement/rust/lua", "cross/x402-build-v1-advertised/rust/lua", + "cross/x402-build-duplicate-advertisement/typescript/lua", + "cross/x402-build-v1-advertised/typescript/lua", ] reason = "refuses a valid version-1 x402 build: the verifier cannot decode or admit version 1" tracking = "FINDINGS.md#txv1-lua" -[[known_failing]] -id = "vector/x402-exact-verify-priority-fee-over-cap-reject" -reason = "the x402 exact verifier caps the unit price alone (lua/pay_kit/protocols/x402/exact/verify.lua:109), so the 200,000 unit limit at 5,000,000 micro-lamports per unit (a 1,000,000 lamport priority fee) is sponsored (RULINGS S6)" -tracking = "FINDINGS.md#x402-priority-fee-product-uncapped" diff --git a/harness/expectations/php.toml b/harness/expectations/php.toml index f6004b1ca..cd416d279 100644 --- a/harness/expectations/php.toml +++ b/harness/expectations/php.toml @@ -38,7 +38,6 @@ ids = [ "vector/charge-build-zero-amount-reject", ] - [[unsupported]] reason = "php is server-only: x402 build-transaction is not supported (no client envelope builder)" ids = [ @@ -143,6 +142,8 @@ ids = [ "vector/x402-build-no-intersection-reject", "vector/x402-build-empty-advertisement-reject", "vector/x402-build-legacy-only-reject", + "vector/x402-build-unknown-entry-reject", + "vector/x402-build-string-entry-reject", ] [[known_failing]] @@ -189,6 +190,8 @@ tracking = "FINDINGS.md#txv1-php" [[known_failing]] ids = [ "vector/x402-verify-v1-accept", + "vector/x402-verify-v1-loaded-data-limit-4mib-accept", + "vector/x402-verify-v1-loaded-data-limit-small-accept", "vector/x402-verify-v1-not-accepted-reject", "vector/x402-verify-v1-explicit-v0-sponsor-reject", "vector/x402-verify-v1-over-1232-accept", @@ -245,10 +248,8 @@ tracking = "FINDINGS.md#txv1-php" ids = [ "cross/x402-build-duplicate-advertisement/rust/php", "cross/x402-build-v1-advertised/rust/php", + "cross/x402-build-duplicate-advertisement/typescript/php", + "cross/x402-build-v1-advertised/typescript/php", ] reason = "refuses a valid version-1 x402 build: the verifier cannot decode or admit version 1" tracking = "FINDINGS.md#txv1-php" -[[known_failing]] -id = "vector/x402-exact-verify-priority-fee-over-cap-reject" -reason = "the x402 exact verifier caps the unit price alone (php/src/Protocols/X402/Exact/Verifier.php:184), so the 200,000 unit limit at 5,000,000 micro-lamports per unit (a 1,000,000 lamport priority fee) is sponsored (RULINGS S6)" -tracking = "FINDINGS.md#x402-priority-fee-product-uncapped" diff --git a/harness/expectations/python.toml b/harness/expectations/python.toml index 80cca36aa..e2e72c1fc 100644 --- a/harness/expectations/python.toml +++ b/harness/expectations/python.toml @@ -15,11 +15,6 @@ interop = ["x402:exact:client", "x402:exact:server", "x402:upto:client", "x402:u # Cross-checked against the testee `capabilities` op. honours_clock = true -[[known_failing]] -id = "vector/x402-exact-verify-extra-required-signer-reject" -reason = "the x402 exact verifier accepts a third required signer (scheme_exact_svm.md §2.1.4); python/src/solana_pay_kit/protocols/x402/exact/verify.py:83 never checks the header's signer set" -tracking = "FINDINGS.md#x402-extra-required-signer-accepted" - [[known_failing]] id = "vector/charge-build-sol-token-program-reject" reason = "the client builds a SOL charge whose challenge carries tokenProgram (python/src/solana_pay_kit/protocols/mpp/client/charge.py:208)" @@ -76,6 +71,13 @@ ids = [ reason = "the x402 server adapter does not mount MPP_HARNESS_REPLAY_SOURCE_PATH, so the cheap route a cross-route payment comes from does not exist" tracking = "FINDINGS.md#x402-replay-route-missing" +[[known_failing]] +ids = [ + "interop/x402-upto-basic/rust/python", +] +reason = "upto settlement idempotently creates every distribution recipient's token account with the fee payer as funder (python/src/solana_pay_kit/protocols/x402/upto/__init__.py:446), one instruction more than the settlement shape the Rust server now sends" +tracking = "FINDINGS.md#upto-settlement-funds-recipient-ata" + # Transaction versions (SIMD-0385; mpp-specs-txv1, x402-txv1). [[unsupported]] @@ -148,7 +150,12 @@ ids = [ "vector/x402-build-no-intersection-reject", "vector/x402-build-empty-advertisement-reject", "vector/x402-build-legacy-only-reject", + "vector/x402-build-unknown-entry-reject", + "vector/x402-build-string-entry-reject", "vector/x402-verify-v1-accept", + "vector/x402-verify-v1-loaded-data-limit-4mib-accept", + "vector/x402-verify-v1-loaded-data-limit-small-accept", + "vector/x402-verify-v1-heap-size-reject", "vector/x402-verify-v1-not-accepted-reject", "vector/x402-verify-v1-explicit-v0-sponsor-reject", "vector/x402-verify-v1-over-1232-accept", @@ -195,6 +202,8 @@ tracking = "FINDINGS.md#txv1-python" ids = [ "cross/x402-build-duplicate-advertisement/rust/python", "cross/x402-build-v1-advertised/rust/python", + "cross/x402-build-duplicate-advertisement/typescript/python", + "cross/x402-build-v1-advertised/typescript/python", ] reason = "refuses a valid version-1 x402 build: the verifier cannot decode or admit version 1" tracking = "FINDINGS.md#txv1-python" @@ -202,10 +211,6 @@ tracking = "FINDINGS.md#txv1-python" [[unsupported]] reason = "the runner's session verify path drives only the SDK's voucher verifier (input.sessionVoucherVerify); it has no path to the session server's open checks (input.sessionOpenVerify, input.sessionServerVerify)" pattern = "vector/session-open-*" -[[known_failing]] -id = "vector/x402-exact-verify-priority-fee-over-cap-reject" -reason = "the x402 exact verifier caps the unit price alone (python/src/solana_pay_kit/protocols/x402/exact/verify.py:57), so the 200,000 unit limit at 5,000,000 micro-lamports per unit (a 1,000,000 lamport priority fee) is sponsored (RULINGS S6)" -tracking = "FINDINGS.md#x402-priority-fee-product-uncapped" # draft-solana-session-00 server, client build and strict wire vectors # (rust/crates/conformance/src/cases/session_server.rs). diff --git a/harness/expectations/ruby.toml b/harness/expectations/ruby.toml index 1ea14c4a5..0e5def8b7 100644 --- a/harness/expectations/ruby.toml +++ b/harness/expectations/ruby.toml @@ -38,7 +38,6 @@ ids = [ "vector/charge-build-zero-amount-reject", ] - [[unsupported]] reason = "ruby SDK is server-only: x402 build-transaction has no client builder" ids = [ @@ -105,6 +104,8 @@ ids = [ "vector/x402-build-no-intersection-reject", "vector/x402-build-empty-advertisement-reject", "vector/x402-build-legacy-only-reject", + "vector/x402-build-unknown-entry-reject", + "vector/x402-build-string-entry-reject", ] [[known_failing]] @@ -152,6 +153,9 @@ tracking = "FINDINGS.md#txv1-ruby" [[known_failing]] ids = [ "vector/x402-verify-v1-accept", + "vector/x402-verify-v1-loaded-data-limit-4mib-accept", + "vector/x402-verify-v1-loaded-data-limit-small-accept", + "vector/x402-verify-v1-heap-size-reject", "vector/x402-verify-v1-not-accepted-reject", "vector/x402-verify-v1-explicit-v0-sponsor-reject", "vector/x402-verify-v1-over-1232-accept", @@ -212,10 +216,8 @@ tracking = "FINDINGS.md#txv1-ruby" ids = [ "cross/x402-build-duplicate-advertisement/rust/ruby", "cross/x402-build-v1-advertised/rust/ruby", + "cross/x402-build-duplicate-advertisement/typescript/ruby", + "cross/x402-build-v1-advertised/typescript/ruby", ] reason = "refuses a valid version-1 x402 build: the verifier cannot decode or admit version 1" tracking = "FINDINGS.md#txv1-ruby" -[[known_failing]] -id = "vector/x402-exact-verify-priority-fee-over-cap-reject" -reason = "the x402 exact verifier caps the unit price alone (ruby/lib/pay_kit/protocols/x402/protocol/schemes/exact/verify.rb:147), so the 200,000 unit limit at 5,000,000 micro-lamports per unit (a 1,000,000 lamport priority fee) is sponsored (RULINGS S6)" -tracking = "FINDINGS.md#x402-priority-fee-product-uncapped" diff --git a/harness/expectations/rust.toml b/harness/expectations/rust.toml index a30f534c8..4ce26abe5 100644 --- a/harness/expectations/rust.toml +++ b/harness/expectations/rust.toml @@ -17,7 +17,7 @@ flow = false # (`pkc run --cross --require`); cells are cross///. cross = true # Interop roles (pkc run --tier interop), ::; cases are interop///. -interop = ["mpp:charge:client", "mpp:charge:server", "x402:exact:client", "x402:exact:server", "x402:upto:client", "x402:upto:server"] +interop = ["mpp:charge:client", "mpp:charge:server", "x402:exact:client", "x402:exact:server", "x402:upto:client", "x402:upto:server", "x402:batch-settlement:client", "x402:batch-settlement:server"] # Whether the testee drives the SDK at the clock a vector pins; the runner drives the session voucher verifier at sessionVoucherVerify.nowSeconds. # Cross-checked against the testee `capabilities` op. honours_clock = true diff --git a/harness/expectations/swift.toml b/harness/expectations/swift.toml index da497ddcd..c38860db4 100644 --- a/harness/expectations/swift.toml +++ b/harness/expectations/swift.toml @@ -203,6 +203,9 @@ ids = [ reason = "unsupported-mode: swift is a client-only SDK and does not implement x402 verify-transaction" ids = [ "vector/x402-verify-v1-accept", + "vector/x402-verify-v1-loaded-data-limit-4mib-accept", + "vector/x402-verify-v1-loaded-data-limit-small-accept", + "vector/x402-verify-v1-heap-size-reject", "vector/x402-verify-v1-not-accepted-reject", "vector/x402-verify-v1-explicit-v0-sponsor-reject", "vector/x402-verify-v0-with-v1-sponsor-accept", @@ -261,6 +264,8 @@ ids = [ "vector/x402-build-no-intersection-reject", "vector/x402-build-empty-advertisement-reject", "vector/x402-build-legacy-only-reject", + "vector/x402-build-unknown-entry-reject", + "vector/x402-build-string-entry-reject", ] reason = "the x402 exact client and sponsor have no transaction-version support (scheme_exact_svm.md §1.5, x402-foundation/x402 PR 3473/3474): the Swift SDK models legacy and version 0 only (swift/Sources/SolanaPayKit/PayCore/Transaction.swift TransactionVersion) and reads no transactionVersions" tracking = "FINDINGS.md#txv1-swift" diff --git a/harness/expectations/typescript.toml b/harness/expectations/typescript.toml index 9bd69f419..2514df3e3 100644 --- a/harness/expectations/typescript.toml +++ b/harness/expectations/typescript.toml @@ -17,7 +17,7 @@ flow = true # (`pkc run --cross --require`); cells are cross///. cross = true # Interop roles (pkc run --tier interop), ::; cases are interop///. -interop = ["mpp:charge:client", "mpp:charge:server", "x402:exact:client", "x402:exact:server"] +interop = ["mpp:charge:client", "mpp:charge:server", "x402:exact:client", "x402:exact:server", "x402:upto:server"] # Whether the testee drives the SDK at the clock a vector pins; the runner drives the session voucher verifier at sessionVoucherVerify.nowSeconds. # Cross-checked against the testee `capabilities` op. honours_clock = true @@ -52,55 +52,11 @@ ids = [ "vector/x402-ext-preserve-unknown-verbatim", ] -[[known_failing]] -id = "vector/x402-exact-verify-overpayment-accept" -reason = "the vendored upstream @x402/svm 2.26.0 facilitator enforces an exact amount on its static path (scheme_exact_svm.md §3.1), a stricter sponsor policy pay-kit inherits by default (RULINGS S5); the fix belongs upstream in the x402 fork" -tracking = "FINDINGS.md#x402-overpayment-rejected" - [[known_failing]] id = "vector/x402-exact-verify-extra-required-signer-reject" reason = "the vendored upstream @x402/svm static path accepts a third required signer (scheme_exact_svm.md §2.1.4); maxRequiredSignatures is unset in pay-kit (typescript/packages/pay-kit/src/config.ts:48)" tracking = "FINDINGS.md#x402-extra-required-signer-accepted" -[[known_failing]] -id = "vector/charge-build-sol-token-program-reject" -reason = "the client builds a SOL charge whose challenge carries tokenProgram (typescript/packages/mpp/src/client/Charge.ts:331)" -tracking = "FINDINGS.md#charge-client-sol-token-program-ignored" - -[[known_failing]] -id = "vector/charge-build-unknown-network-reject" -reason = "the client builds for network \"testnet\" and falls back to the mainnet RPC (typescript/packages/mpp/src/client/Charge.ts:187)" -tracking = "FINDINGS.md#charge-client-unknown-network" - -[[known_failing]] -id = "vector/charge-build-too-many-splits-reject" -reason = "the client builds nine splits; no length check (typescript/packages/mpp/src/client/Charge.ts:204)" -tracking = "FINDINGS.md#ts-charge-client-split-cap" - -[[known_failing]] -id = "vector/charge-build-amount-overflow-reject" -reason = "amount 2^64 is refused only because the u64 codec throws; no u64 check at typescript/packages/mpp/src/client/Charge.ts:205" -tracking = "FINDINGS.md#charge-client-amount-not-u64-validated" - -[[known_failing]] -id = "vector/charge-verify-ata-not-idempotent-reject" -reason = "an ATA Create with empty data throws a TypeError (typescript/packages/mpp/src/server/Charge.ts:689) instead of the policy rejection" -tracking = "FINDINGS.md#ts-charge-ata-empty-data-crash" - -[[known_failing]] -ids = [ - "interop/charge-client-wrong-network/typescript/rust", -] -reason = "the client submits a credential for a challenge naming another cluster (draft-solana-charge-00: \"Clients MUST reject challenges whose network does not match their configured cluster\")" -tracking = "FINDINGS.md#charge-client-network-not-checked" - -[[known_failing]] -ids = [ - "interop/charge-client-over-asking-price/typescript/rust", -] -reason = "the client pays a challenge whose amount was multiplied by 10000 after the server bound it; nothing checks the amount against what it was asked to pay (core: \"Clients MUST verify before authorizing payment\")" -tracking = "FINDINGS.md#charge-client-request-not-verified" - [[known_failing]] ids = [ "interop/charge-client-mis-signed-challenge/typescript/rust", @@ -138,91 +94,27 @@ tracking = "FINDINGS.md#upto-slot-wire-type" [[known_failing]] ids = [ - "vector/x402-upto-verify-open-trailing-byte-reject", + "vector/batch-verify-open-unfunded-payer-reject", + "vector/batch-verify-top-up-unfunded-payer-reject", ] -reason = "verifyOpenTransaction decodes the open args with a decoder that ignores trailing bytes" -tracking = "FINDINGS.md#ts-upto-open-trailing-bytes" +reason = "the vendored @x402/svm 2.28.0 batch verify reads no payer balance: an unfunded deposit is caught only by the simulation its deposit settle runs, which the offline signer stubs (\"It MUST confirm the payer has sufficient tokens.\")" +tracking = "FINDINGS.md#batch-deposit-balance-unchecked" [[known_failing]] ids = [ - "vector/x402-upto-verify-v0-oversize-reject", + "vector/x402-upto-verify-open-trailing-byte-reject", ] -reason = "verifyOpenTransaction never bounds the serialized size of the open transaction" -tracking = "FINDINGS.md#ts-upto-open-size-unbounded" +reason = "verifyOpenTransaction decodes the open args with a decoder that ignores trailing bytes" +tracking = "FINDINGS.md#ts-upto-open-trailing-bytes" -[[known_failing]] +[[unsupported]] +reason = "the vendored @x402/svm upto facilitator's accepted transaction-version set is fixed (legacy, 0 and 1) with no option to narrow it, so a sponsor configured with [0] (input.x402ServerTransactionVersions) cannot be expressed (\"The facilitator enforces its own accepted set\")" ids = [ - "vector/x402-upto-build-v1-when-advertised", - "vector/x402-upto-build-no-common-version-reject", - "vector/x402-upto-verify-v1-accept", "vector/x402-upto-verify-v1-unadvertised-reject", "vector/x402-upto-verify-v1-unadvertised-before-layout-reject", - "vector/x402-upto-verify-v1-compute-budget-instruction-reject", - "vector/x402-upto-verify-v1-limit-over-cap-reject", - "vector/x402-upto-verify-v1-priority-fee-over-cap-reject", - "vector/x402-upto-verify-v1-priority-fee-at-cap-accept", - "vector/x402-upto-verify-v1-missing-limit-reject", - "vector/x402-upto-verify-v1-missing-loaded-limit-reject", - "vector/x402-upto-verify-v1-small-loaded-limit-accept", - "vector/x402-upto-verify-v1-large-accept", - "vector/x402-upto-verify-v1-oversize-reject", ] -reason = "the vendored @x402/svm 2.26.0 predates transaction-version negotiation (x402-foundation/x402 PR 3710): the client ignores extra.transactionVersions and the facilitator cannot decode a version-1 message" -tracking = "FINDINGS.md#ts-upto-no-transaction-versions" # subscription (draft-solana-subscription-00) vectors -[[known_failing]] -ids = [ - "vector/subscription-build-activation", - "vector/subscription-build-sponsored", - "vector/subscription-build-external-id-memo", - "vector/subscription-build-week-period", - "vector/subscription-build-token-2022", - "vector/subscription-build-plan-puller-listed", - "vector/subscription-build-spec-request", -] -reason = "the activation also creates the recipient's ATA (typescript/packages/mpp/src/client/Subscription.ts:353, :407), which the Rust server's activation scope check refuses (\"Only one idempotent subscriber ATA creation is allowed\") and the spec's instruction list does not allow" -tracking = "FINDINGS.md#subscription-ts-recipient-ata" - -[[known_failing]] -ids = [ - "vector/subscription-build-untrusted-program-reject", -] -reason = "buildSubscriptionActivationTransaction signs for whatever methodDetails.subscriptionProgram names; nothing pins the deployment (typescript/packages/mpp/src/client/Subscription.ts:297)" -tracking = "FINDINGS.md#subscription-ts-program-not-pinned" - -[[known_failing]] -ids = [ - "vector/subscription-build-currency-not-mint-reject", -] -reason = "the client builds from methodDetails.mint and never compares it with currency (typescript/packages/mpp/src/client/Subscription.ts:264)" -tracking = "FINDINGS.md#subscription-ts-currency-not-mint" - -[[known_failing]] -ids = [ - "vector/subscription-build-amount-leading-zero-reject", - "vector/subscription-build-zero-amount-reject", - "vector/subscription-build-period-count-leading-zero-reject", - "vector/subscription-build-token-program-not-spl-reject", - "vector/subscription-period-count-leading-zero-reject", - "vector/subscription-period-count-sign-reject", - "vector/subscription-period-count-decimal-point-reject", - "vector/subscription-period-count-exponent-reject", - "vector/subscription-period-count-whitespace-reject", -] -reason = "amount and periodCount are read with BigInt()/Number() (typescript/packages/mpp/src/client/Subscription.ts:273, :331), which accept leading zeros, a sign, a decimal point, an exponent and whitespace, and the client accepts any tokenProgram" -tracking = "FINDINGS.md#subscription-ts-request-format" - -[[known_failing]] -ids = [ - "vector/subscription-build-plan-puller-unauthorized-reject", - "vector/subscription-build-plan-no-destination-reject", - "vector/subscription-build-plan-two-destinations-reject", - "vector/subscription-build-plan-other-destination-reject", -] -reason = "the client checks the plan's mint, amount and period (typescript/packages/mpp/src/client/Subscription.ts:329) but not plan.owner / plan.pullers against the puller nor plan.destinations against the recipient" -tracking = "FINDINGS.md#subscription-ts-plan-pullers-destinations" - [[known_failing]] ids = [ "vector/subscription-verify-forged-challenge-id-reject", @@ -240,29 +132,6 @@ ids = [ reason = "subscription().verify trusts the echoed challenge (typescript/packages/mpp/src/server/Subscription.ts:230); the HMAC and route binding live in mppx's Mppx.create handler, which reports a generic error the testee cannot classify" tracking = "FINDINGS.md#subscription-ts-route-binding-in-mppx" -[[known_failing]] -ids = [ - "vector/subscription-verify-push-mode-reject", -] -reason = "the server accepts push-mode (type=\"signature\") activations and fetches the transaction (typescript/packages/mpp/src/server/Subscription.ts:485); the profile defines type=\"transaction\" only" -tracking = "FINDINGS.md#subscription-ts-push-mode" - -[[known_failing]] -ids = [ - "vector/subscription-verify-source-other-address-reject", - "vector/subscription-verify-source-other-method-reject", -] -reason = "verify never reads credential.source (typescript/packages/mpp/src/server/Subscription.ts:230)" -tracking = "FINDINGS.md#subscription-source-not-verified" - -[[known_failing]] -ids = [ - "vector/subscription-verify-subscribe-other-plan-reject", - "vector/subscription-verify-unrelated-authority-init-reject", -] -reason = "validateActivationInstructions checks transfer_subscription's receiver and data but not subscribe's accounts, and accepts any initialize_subscription_authority (typescript/packages/mpp/src/server/Subscription.ts:793-797)" -tracking = "FINDINGS.md#subscription-ts-scope-accounts" - [[unsupported]] ids = [ "vector/subscription-active-live", @@ -287,120 +156,45 @@ ids = [ "vector/subscription-instruction-transfer-data", ] reason = "@solana/mpp exposes no subscriptions instruction-data encoder (it builds instructions with @solana/subscriptions); the layouts are judged through the build vectors' instruction multiset" -# ── x402 batch-settlement (SVM): vendored @x402/svm 2.26.0 ── +# ── x402 batch-settlement (SVM): vendored @x402/svm 2.28.0 ── [[known_failing]] ids = [ - "vector/batch-build-deposit-open", - "vector/batch-build-terms-payment-flow-authorization", - "vector/batch-verify-open-accept", - "vector/batch-verify-open-channel-pda-mismatch-reject", - "vector/batch-verify-open-deposit-mismatch-reject", - "vector/batch-verify-open-diverting-distribution-reject", - "vector/batch-verify-open-foreign-binding-reject", "vector/batch-verify-open-future-slot-reject", - "vector/batch-verify-open-grace-period-mismatch-reject", - "vector/batch-verify-open-missing-binding-memo-reject", "vector/batch-verify-open-stale-slot-reject", ] -reason = "the vendored @x402/svm 2.26.0 predates the receiver-binding memo: its client opens with the seller memo only and its facilitator requires exactly one memo, so it accepts an unbound open and refuses the two-memo open (\"An open suffix also carries exactly one binding Memo from section 3.\")" -tracking = "FINDINGS.md#ts-batch-open-binding-memo" +reason = "the batch facilitator's verify never compares channelConfig.openSlot with the cluster slot, so an open outside the program's open-slot window is accepted (\"The facilitator MUST reject an expired transaction blockhash and an `openSlot` outside the program's accepted window.\")" +tracking = "FINDINGS.md#ts-batch-open-slot-window" -[[known_failing]] +[[unsupported]] +reason = "the upstream batch facilitator's accepted transaction-version set is fixed (legacy, 0 and 1) with no option to narrow it, so a facilitator configured with [0] (batchServer.transactionVersions) cannot be expressed (\"The facilitator enforces its own accepted set\")" ids = [ - "vector/batch-build-version-intersection-empty-reject", - "vector/batch-txv1-top-up-legacy-policed-as-v0-reject", - "vector/batch-txv1-top-up-v0-over-1232-bytes-reject", - "vector/batch-txv1-top-up-v1-advertised", - "vector/batch-txv1-top-up-v1-compute-budget-instruction-reject", - "vector/batch-txv1-top-up-v1-loaded-limit-below-max", - "vector/batch-txv1-top-up-v1-missing-loaded-limit-reject", - "vector/batch-txv1-top-up-v1-missing-unit-limit-reject", + "vector/batch-txv1-refund-v1-not-advertised-reject", "vector/batch-txv1-top-up-v1-not-advertised-reject", - "vector/batch-txv1-top-up-v1-over-1232-bytes", - "vector/batch-txv1-top-up-v1-priority-fee-at-cap", - "vector/batch-txv1-top-up-v1-priority-fee-over-cap-reject", - "vector/batch-txv1-top-up-v1-unit-limit-over-cap-reject", ] -reason = "the vendored @x402/svm 2.26.0 predates SVM transaction versions (x402-foundation/x402 PR 3473): its verifier fails on a version-1 message and does not enforce the 1232-byte version-0 limit, and its client ignores extra.transactionVersions" -tracking = "FINDINGS.md#ts-batch-transaction-versions" -[[known_failing]] +[[unsupported]] +reason = "the testee drives the stateless upstream facilitator, which never sees the resource server's store record (chargedCumulativeAmount, the accepted cumulative, a close-pending mark) these verdicts rest on (batchVerdictFromStore, RULINGS B1); upstream keeps that state in its resource server, which has no single-shot entry point" ids = [ - "vector/batch-txv1-refund-v1-not-advertised-reject", - "vector/batch-verify-refund-compute-price-over-cap-reject", - "vector/batch-verify-refund-disallowed-suffix-reject", - "vector/batch-verify-refund-extra-account-reject", - "vector/batch-verify-refund-extra-instruction-reject", - "vector/batch-verify-refund-fee-payer-not-sponsor-reject", - "vector/batch-verify-refund-invalid-payer-signature-reject", - "vector/batch-verify-refund-memo-mismatch-reject", - "vector/batch-verify-refund-prefix-only-reject", - "vector/batch-verify-refund-request-close", - "vector/batch-verify-refund-sealed-channel-reject", "vector/batch-verify-refund-voucher-not-accepted-cumulative-reject", - "vector/batch-verify-refund-without-voucher-reject", - "vector/batch-verify-refund-wrong-channel-reject", - "vector/batch-wire-payload-refund-cooperative", - "vector/batch-wire-payload-refund-transaction-without-voucher-reject", -] -reason = "the vendored facilitator refuses a client-mode refund carrying the voucher (\"cooperative close requires a trusted server binding\") instead of validating the request_close retry, and accepts a refund without the voucher; its wire guard applies the same shape (\"| voucher | BatchVoucher | REQUIRED in client mode.\")" -tracking = "FINDINGS.md#ts-batch-refund-cooperative" - -[[known_failing]] -ids = [ - "vector/batch-verify-top-up-amount-mismatch-reject", - "vector/batch-verify-top-up-ata-instruction-reject", - "vector/batch-verify-top-up-compute-limit-over-cap-reject", - "vector/batch-verify-top-up-compute-price-over-cap-reject", - "vector/batch-verify-top-up-duplicate-limit-reject", - "vector/batch-verify-top-up-exceeds-deposit-reject", - "vector/batch-verify-top-up-extra-signer-reject", - "vector/batch-verify-top-up-fee-payer-as-account-reject", - "vector/batch-verify-top-up-fee-payer-in-memo-reject", - "vector/batch-verify-top-up-fee-payer-not-sponsor-reject", - "vector/batch-verify-top-up-four-lighthouse-reject", - "vector/batch-verify-top-up-frozen-payer-ata-reject", - "vector/batch-verify-top-up-memo-mismatch-reject", - "vector/batch-verify-top-up-missing-memo-reject", - "vector/batch-verify-top-up-missing-payer-signature-reject", - "vector/batch-verify-top-up-oversized-memo-reject", - "vector/batch-verify-top-up-price-before-limit-reject", - "vector/batch-verify-top-up-second-setup-instruction-reject", - "vector/batch-verify-top-up-smuggled-transfer-reject", - "vector/batch-verify-top-up-trailing-bytes-reject", - "vector/batch-verify-top-up-two-memos-reject", - "vector/batch-verify-top-up-unsupported-compute-budget-reject", - "vector/batch-verify-top-up-wrong-channel-reject", -] -reason = "the vendored facilitator rejects every setup-transaction policy violation with the generic transaction_failed reason (and an over-deposit top-up voucher as cumulative_amount_mismatch) rather than invalid_batch_settlement_svm_setup_transaction / cumulative_exceeds_deposit; it accepts a top_up with trailing data bytes and does not check the payer return ATA on a top-up" -tracking = "FINDINGS.md#ts-batch-setup-reason-code" - -[[known_failing]] -ids = [ "vector/batch-verify-voucher-close-pending-in-store-reject", "vector/batch-verify-voucher-one-above-reject", "vector/batch-verify-voucher-one-below-reject", "vector/batch-verify-voucher-stale-reject", ] -reason = "the testee drives the stateless upstream facilitator, which never sees the resource server's chargedCumulativeAmount or close-pending mark: it accepts any voucher above the onchain settled floor (RULINGS.md B1)" -tracking = "FINDINGS.md#ts-batch-facilitator-stateless" [[known_failing]] ids = [ - "vector/batch-verify-accepted-amount-mismatch-reject", - "vector/batch-verify-accepted-network-mismatch-reject", - "vector/batch-verify-accepted-pay-to-mismatch-reject", + "vector/batch-verify-top-up-frozen-payer-ata-reject", ] -reason = "the vendored facilitator does not compare paymentPayload.accepted with paymentRequirements (amount, payTo) and reports a network mismatch as network_mismatch (\"For every request, paymentPayload.accepted MUST equal paymentRequirements.\")" -tracking = "FINDINGS.md#ts-batch-accepted-not-checked" +reason = "the batch facilitator's verify checks only that the payer return ATA exists and its owner, not its token state, so a top-up whose payer return ATA is frozen is accepted (\"Before co-signing ... MUST reject ... frozen\"); the top-up simulation at settle would fail it" +tracking = "FINDINGS.md#ts-batch-setup-reason-code" [[known_failing]] ids = [ "vector/batch-build-deposit-payer-is-fee-payer-reject", - "vector/batch-verify-voucher-server-mode-config-reject", ] -reason = "the vendored client builds an open whose payer is the challenge's own feePayer, and refuses a mismatched channelConfig.voucherSigner as payload_type rather than channel_state" +reason = "the upstream batch client builds an open whose payer is the challenge's own extra.feePayer (\"`channelConfig.payer` and `channelConfig.payerAuthorizer` MUST NOT equal `extra.feePayer`.\")" tracking = "FINDINGS.md#ts-batch-client-terms" [[unsupported]] @@ -424,6 +218,7 @@ ids = [ "vector/batch-wire-payment-payload-frozen", "vector/batch-wire-requirements-frozen", "vector/batch-wire-requirements-transaction-versions", + "vector/batch-wire-requirements-redemption-capacity", "vector/batch-wire-requirements-unknown-transaction-version-reject", "vector/batch-wire-settlement-response-voucher-acceptance", ] @@ -452,39 +247,29 @@ ids = [ # Transaction versions (SIMD-0385; mpp-specs-txv1, x402-txv1). [[unsupported]] -reason = "neither @solana/mpp buildChargeTransaction nor the @solana/pay-kit x402 client takes a highest signable transaction version (input.signerMaxTransactionVersion)" +reason = "@solana/mpp buildChargeTransaction takes no highest signable transaction version (input.signerMaxTransactionVersion); the @solana/pay-kit x402 client does (maxTransactionVersion)" ids = [ "vector/charge-build-signer-v0-picks-v0", "vector/charge-build-no-buildable-version-reject", - "vector/x402-build-signer-v0-picks-v0", - "vector/x402-build-no-intersection-reject", ] [[unsupported]] -reason = "the vendored @x402/svm exact facilitator (x402 @03b3919b, before x402-foundation/x402 PR 3474) has no accepted transaction-version set to configure (input.x402ServerTransactionVersions other than [0])" +reason = "the @x402/svm exact facilitator's accepted transaction-version set is fixed at [0, 1] (legacy tolerated) with no option to narrow it, so a sponsor configured with [0] (input.x402ServerTransactionVersions) cannot be expressed (scheme_exact_svm.md §1.5: \"The sponsor enforces its own accepted set\")" ids = [ - "vector/x402-verify-v1-accept", - "vector/x402-verify-v0-with-v1-sponsor-accept", - "vector/x402-verify-v1-over-1232-accept", - "vector/x402-verify-v0-over-1232-reject", - "vector/x402-verify-v1-over-4096-reject", - "vector/x402-verify-v1-compute-budget-instruction-reject", - "vector/x402-verify-v1-missing-compute-unit-limit-reject", - "vector/x402-verify-v1-missing-loaded-data-limit-reject", - "vector/x402-verify-v1-compute-limit-at-cap-accept", - "vector/x402-verify-v1-compute-limit-over-cap-reject", - "vector/x402-verify-v1-priority-fee-at-cap-accept", - "vector/x402-verify-v1-priority-fee-over-cap-reject", - "vector/x402-verify-v1-too-many-instructions-reject", - "vector/x402-verify-v1-underpay-reject", - "vector/x402-verify-v1-wrong-recipient-reject", - "vector/x402-verify-v1-wrong-mint-reject", - "vector/x402-verify-v1-decimals-reject", - "vector/x402-verify-v1-fee-payer-authority-reject", - "vector/x402-verify-v1-fee-payer-in-accounts-reject", - "vector/x402-verify-v1-extra-signer-reject", + "vector/x402-verify-v1-explicit-v0-sponsor-reject", + "vector/x402-verify-v1-not-accepted-reject", ] +[[known_failing]] +id = "vector/x402-verify-v1-compute-limit-over-cap-reject" +reason = "the @x402/svm exact facilitator has no default compute unit cap (maxComputeUnits is unset in the runner and in pay-kit), so a version-1 computeUnitLimit of 400001, over the 400,000 reference default, is sponsored (scheme_exact_svm.md §2.2.1 \"MUST NOT exceed the configured maximum\")" +tracking = "FINDINGS.md#txv1-ts-x402-v1-policy" + +[[known_failing]] +id = "vector/x402-verify-v1-extra-signer-reject" +reason = "as for version 0: the @x402/svm static path accepts a third required signer (scheme_exact_svm.md §2.1.4); maxRequiredSignatures is unset in pay-kit (typescript/packages/pay-kit/src/config.ts)" +tracking = "FINDINGS.md#x402-extra-required-signer-accepted" + [[known_failing]] ids = [ "vector/charge-wire-transaction-versions-both-golden", @@ -525,11 +310,8 @@ ids = [ "vector/charge-verify-v0-to-v1-only-reject", "vector/charge-verify-legacy-reject", "vector/charge-verify-legacy-default-reject", - "vector/charge-verify-v0-oversize-reject", "vector/charge-verify-v1-large-memos-accept", "vector/charge-verify-v1-compute-budget-instruction-reject", - "vector/charge-verify-v1-missing-compute-unit-limit-reject", - "vector/charge-verify-v1-missing-loaded-data-limit-reject", "vector/charge-verify-v1-priority-fee-at-cap-accept", "vector/charge-verify-v1-priority-fee-over-cap-reject", "vector/charge-verify-v1-sponsored-priority-fee-at-cap-accept", @@ -545,18 +327,6 @@ ids = [ reason = "verifyChargeTransaction does not admit by advertised version: it throws on a version-1 message (decoded instructions undefined), accepts version 0 for a version-1-only challenge, accepts legacy, and applies no per-version size limit (mpp-specs-txv1 Transaction Versions)" tracking = "FINDINGS.md#txv1-ts-mpp-server-no-version-admission" -[[known_failing]] -ids = [ - "vector/x402-build-v1-advertised", - "vector/x402-build-duplicate-advertisement", - "vector/x402-build-empty-advertisement-reject", - "vector/x402-build-legacy-only-reject", - "vector/x402-verify-v1-not-accepted-reject", - "vector/x402-verify-v1-explicit-v0-sponsor-reject", -] -reason = "the vendored x402 @03b3919b predates x402-foundation/x402 PR 3474: the exact client ignores extra.transactionVersions (always builds version 0, never refuses), and the facilitator has no version gate, so a version-1 transaction fails as signature_invalid instead of unsupported_transaction_version (scheme_exact_svm.md §1.5)" -tracking = "FINDINGS.md#txv1-ts-x402-pre-3474" - # Cross-verification of the transaction-version builds. [[known_failing]] @@ -565,10 +335,6 @@ ids = [ "cross/charge-build-duplicate-advertisement/python/typescript", "cross/charge-build-duplicate-advertisement/swift/typescript", "cross/charge-build-duplicate-advertisement/typescript/typescript", - "cross/charge-build-v1-large-memos/go/typescript", - "cross/charge-build-v1-large-memos/python/typescript", - "cross/charge-build-v1-large-memos/swift/typescript", - "cross/charge-build-v1-large-memos/typescript/typescript", "cross/charge-build-v1-only-advertised/go/typescript", "cross/charge-build-v1-only-advertised/python/typescript", "cross/charge-build-v1-only-advertised/swift/typescript", @@ -590,31 +356,12 @@ reason = "refuses a valid version-1 charge build (the Rust kit's, or another SDK tracking = "FINDINGS.md#txv1-ts-mpp-server-no-version-admission" [[unsupported]] -reason = "the vendored @x402/svm exact facilitator (x402 @03b3919b, before x402-foundation/x402 PR 3474) has no accepted transaction-version set to configure (input.x402ServerTransactionVersions other than [0])" -ids = [ - "cross/x402-build-duplicate-advertisement/go/typescript", - "cross/x402-build-duplicate-advertisement/python/typescript", - "cross/x402-build-duplicate-advertisement/rust/typescript", - "cross/x402-build-duplicate-advertisement/swift/typescript", - "cross/x402-build-duplicate-advertisement/typescript/typescript", - "cross/x402-build-signer-v0-picks-v0/go/typescript", - "cross/x402-build-signer-v0-picks-v0/python/typescript", - "cross/x402-build-signer-v0-picks-v0/rust/typescript", - "cross/x402-build-signer-v0-picks-v0/swift/typescript", - "cross/x402-build-v1-advertised/go/typescript", - "cross/x402-build-v1-advertised/python/typescript", - "cross/x402-build-v1-advertised/rust/typescript", - "cross/x402-build-v1-advertised/swift/typescript", - "cross/x402-build-v1-advertised/typescript/typescript", -] +reason = "the @x402/svm exact facilitator's accepted transaction-version set is fixed at [0, 1] (legacy tolerated) with no option to narrow it, so a sponsor configured with [0] explicitly (input.x402ServerTransactionVersions) cannot be expressed" +pattern = "cross/x402-build-v0-advertised/*/typescript" [[unsupported]] reason = "the runner's session verify path drives only the SDK's voucher verifier (input.sessionVoucherVerify); it has no path to the session server's open checks (input.sessionOpenVerify, input.sessionServerVerify)" pattern = "vector/session-open-*" -[[known_failing]] -id = "vector/x402-exact-verify-priority-fee-over-cap-reject" -reason = "the x402 exact verifier caps the unit price alone (typescript/external/x402/typescript/packages/mechanisms/svm/src/exact/facilitator/scheme.ts:1246), so the 200,000 unit limit at 5,000,000 micro-lamports per unit (a 1,000,000 lamport priority fee) is sponsored (RULINGS S6)" -tracking = "FINDINGS.md#x402-priority-fee-product-uncapped" # draft-solana-session-00 server, client build and strict wire vectors # (rust/crates/conformance/src/cases/session_server.rs). @@ -639,7 +386,3 @@ pattern = "vector/session-use-*" reason = "the runner has no path to the SDK's session client open builder (input.sessionOpenBuild)" pattern = "vector/session-build-*" -[[known_failing]] -id = "vector/session-wire-action-open-initial-voucher-reject" -reason = "the session open schema accepts an open payload carrying a signed voucher (typescript/packages/mpp/src/Methods.ts: the open object schema forbids `bump` but zod strips any other unknown key); draft-solana-session-00 Action open: \"MUST NOT carry an initial voucher\"" -tracking = "FINDINGS.md#session-open-initial-voucher-accepted" diff --git a/harness/interop-plan.json b/harness/interop-plan.json index ed5d143c7..3ce8d7aad 100644 --- a/harness/interop-plan.json +++ b/harness/interop-plan.json @@ -37,6 +37,8 @@ "rust": [ "mpp:charge:client", "mpp:charge:server", + "x402:batch-settlement:client", + "x402:batch-settlement:server", "x402:exact:client", "x402:exact:server", "x402:upto:client", @@ -51,7 +53,8 @@ "mpp:charge:client", "mpp:charge:server", "x402:exact:client", - "x402:exact:server" + "x402:exact:server", + "x402:upto:server" ] }, "cases": [ @@ -214,6 +217,7 @@ "interop/charge-token2022-split-ata/rust/typescript", "interop/charge-token2022-split-ata/swift/rust", "interop/charge-token2022-split-ata/typescript/rust", + "interop/x402-batch-v1-redeem/rust/rust", "interop/x402-exact-basic/go/rust", "interop/x402-exact-basic/kotlin/rust", "interop/x402-exact-basic/python/rust", @@ -289,13 +293,19 @@ "interop/x402-exact-idempotent-resubmit/swift/rust", "interop/x402-exact-idempotent-resubmit/typescript/rust", "interop/x402-exact-network-mismatch/rust/lua", + "interop/x402-exact-v1/rust/rust", + "interop/x402-exact-v1/rust/typescript", + "interop/x402-exact-v1/typescript/rust", "interop/x402-upto-basic/go/rust", "interop/x402-upto-basic/kotlin/rust", "interop/x402-upto-basic/python/rust", "interop/x402-upto-basic/rust/go", "interop/x402-upto-basic/rust/python", "interop/x402-upto-basic/rust/rust", + "interop/x402-upto-basic/rust/typescript", "interop/x402-upto-basic/swift/rust", + "interop/x402-upto-v1/rust/rust", + "interop/x402-upto-v1/rust/typescript", "interop/x402-upto-zero-actual/go/rust", "interop/x402-upto-zero-actual/kotlin/rust", "interop/x402-upto-zero-actual/python/rust", @@ -578,7 +588,7 @@ "protocol": true, "flow": false }, - "caseCount": 26, + "caseCount": 29, "cases": [ "interop/charge-basic/rust/rust", "interop/charge-client-expired-challenge/rust/rust", @@ -597,6 +607,7 @@ "interop/charge-split-ata/rust/rust", "interop/charge-symbol-usdc-localnet/rust/rust", "interop/charge-token2022-split-ata/rust/rust", + "interop/x402-batch-v1-redeem/rust/rust", "interop/x402-exact-basic/rust/rust", "interop/x402-exact-client-wrong-network/rust/rust", "interop/x402-exact-cross-route-replay/rust/rust", @@ -604,7 +615,9 @@ "interop/x402-exact-fault-wrong-amount/rust/rust", "interop/x402-exact-fault-wrong-recipient/rust/rust", "interop/x402-exact-idempotent-resubmit/rust/rust", + "interop/x402-exact-v1/rust/rust", "interop/x402-upto-basic/rust/rust", + "interop/x402-upto-v1/rust/rust", "interop/x402-upto-zero-actual/rust/rust" ] }, @@ -654,13 +667,13 @@ "typescript", "rust" ], - "needsProgram": false, + "needsProgram": true, "offline": { "vector": true, "protocol": true, "flow": true }, - "caseCount": 43, + "caseCount": 47, "cases": [ "interop/charge-basic/rust/typescript", "interop/charge-basic/typescript/rust", @@ -704,7 +717,11 @@ "interop/x402-exact-fault-wrong-amount/rust/typescript", "interop/x402-exact-fault-wrong-recipient/rust/typescript", "interop/x402-exact-idempotent-resubmit/rust/typescript", - "interop/x402-exact-idempotent-resubmit/typescript/rust" + "interop/x402-exact-idempotent-resubmit/typescript/rust", + "interop/x402-exact-v1/rust/typescript", + "interop/x402-exact-v1/typescript/rust", + "interop/x402-upto-basic/rust/typescript", + "interop/x402-upto-v1/rust/typescript" ] } ] diff --git a/harness/package.json b/harness/package.json index 9a6d9ccb4..fce50c3aa 100644 --- a/harness/package.json +++ b/harness/package.json @@ -13,10 +13,10 @@ "coverage:check": "tsx coverage-table.ts --check" }, "dependencies": { - "@solana/kit": "^6.5.0", + "@solana/kit": "^8.5.0", "@solana/mpp": "file:../typescript/packages/mpp", "@solana/pay-kit": "file:../typescript/packages/pay-kit", - "@solana/surfpool": "1.4.0", + "@solana/surfpool": "1.5.0", "mppx": "^0.8.2" }, "devDependencies": { @@ -26,9 +26,9 @@ "ajv": "^8.17.1", "express": "^4.21.0", "smol-toml": "^1.9.1", - "tsx": "^4.19.2", + "tsx": "^4.23.15", "typescript": "^5.9.3", - "vitest": "^4.1.11", + "vitest": "^4.1.12", "yaml": "^2.8.3" } } diff --git a/harness/pnpm-lock.yaml b/harness/pnpm-lock.yaml index 1ec228cbf..dde1c4190 100644 --- a/harness/pnpm-lock.yaml +++ b/harness/pnpm-lock.yaml @@ -6,7 +6,9 @@ settings: overrides: '@toon-format/toon': 2.3.1 - fast-uri: 4.1.5 + body-parser@1: 1.20.9 + esbuild: 0.28.2 + fast-uri: 4.2.3 hono: 4.13.7 ip-address: 10.7.2 nanoid@3.3.11: 3.3.18 @@ -14,32 +16,33 @@ overrides: proxy-addr: 2.0.8 qs: 6.16.0 source-map-js: 1.2.2 - vite: 8.0.16 + vite: 8.3.5 ws: 8.21.0 + zod: 4.6.7 importers: .: dependencies: '@solana/kit': - specifier: ^6.5.0 - version: 6.8.0(typescript@5.9.3) + specifier: ^8.5.0 + version: 8.5.0(typescript@5.9.3) '@solana/mpp': specifier: file:../typescript/packages/mpp - version: file:../typescript/packages/mpp(@solana/kit@6.8.0(typescript@5.9.3))(mppx@0.8.19(express@4.22.2)(typescript@5.9.3)(viem@2.57.2(typescript@5.9.3)(zod@4.4.3)))(typescript@5.9.3) + version: file:../typescript/packages/mpp(@solana/kit@8.5.0(typescript@5.9.3))(mppx@0.8.19(express@4.22.2)(typescript@5.9.3)(viem@2.57.2(typescript@5.9.3)(zod@4.6.7)))(typescript@5.9.3) '@solana/pay-kit': specifier: file:../typescript/packages/pay-kit - version: file:../typescript/packages/pay-kit(@solana/addresses@7.1.1(typescript@5.9.3))(@solana/codecs-core@7.1.1(typescript@5.9.3))(@solana/codecs-strings@7.1.1(typescript@5.9.3))(@solana/keys@7.1.1(typescript@5.9.3))(@solana/signers@7.1.1(typescript@5.9.3))(@solana/transactions@7.1.1(typescript@5.9.3))(express@4.22.2)(typescript@5.9.3)(viem@2.57.2(typescript@5.9.3)(zod@4.4.3)) + version: file:../typescript/packages/pay-kit(@solana/addresses@8.5.0(typescript@5.9.3))(@solana/codecs-core@8.5.0(typescript@5.9.3))(@solana/codecs-strings@8.5.0(typescript@5.9.3))(@solana/keys@8.5.0(typescript@5.9.3))(@solana/signers@8.5.0(typescript@5.9.3))(@solana/transactions@8.5.0(typescript@5.9.3))(express@4.22.2)(typescript@5.9.3)(viem@2.57.2(typescript@5.9.3)(zod@4.6.7)) '@solana/surfpool': - specifier: 1.4.0 - version: 1.4.0 + specifier: 1.5.0 + version: 1.5.0(@solana/kit-plugin-rpc@0.15.0(@solana/kit@8.5.0(typescript@5.9.3)))(@solana/kit-plugin-signer@0.13.0(@solana/kit@8.5.0(typescript@5.9.3)))(@solana/kit@8.5.0(typescript@5.9.3)) mppx: specifier: ^0.8.2 - version: 0.8.19(express@4.22.2)(typescript@5.9.3)(viem@2.57.2(typescript@5.9.3)(zod@4.4.3)) + version: 0.8.19(express@4.22.2)(typescript@5.9.3)(viem@2.57.2(typescript@5.9.3)(zod@4.6.7)) devDependencies: '@solana-program/token': specifier: ^0.11.0 - version: 0.11.0(@solana/kit@6.8.0(typescript@5.9.3)) + version: 0.11.0(@solana/kit@8.5.0(typescript@5.9.3)) '@types/express': specifier: ^5.0.0 version: 5.0.6 @@ -56,14 +59,14 @@ importers: specifier: ^1.9.1 version: 1.9.1 tsx: - specifier: ^4.19.2 - version: 4.21.0 + specifier: ^4.23.15 + version: 4.23.15 typescript: specifier: ^5.9.3 version: 5.9.3 vitest: - specifier: ^4.1.11 - version: 4.1.11(@types/node@25.6.0)(vite@8.0.16(@types/node@25.6.0)(esbuild@0.27.7)(tsx@4.21.0)(yaml@2.8.3)) + specifier: ^4.1.12 + version: 4.1.12(@types/node@25.6.0)(vite@8.3.5(@types/node@25.6.0)(esbuild@0.28.2)(tsx@4.23.15)(yaml@2.8.3)) yaml: specifier: ^2.8.3 version: 2.8.3 @@ -73,167 +76,158 @@ packages: '@adraffy/ens-normalize@1.11.1': resolution: {integrity: sha512-nhCBV3quEgesuf7c7KYfperqSS14T8bYuvJ8PcLJp6znkZpFc0AuW4qBtr8eKVyPPe/8RSr7sglCWPU5eaxwKQ==} - '@emnapi/core@1.10.0': - resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==} - - '@emnapi/runtime@1.10.0': - resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} - - '@emnapi/wasi-threads@1.2.1': - resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} - - '@esbuild/aix-ppc64@0.27.7': - resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==} + '@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==} + '@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==} + '@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==} + '@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==} + '@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==} + '@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==} + '@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==} + '@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==} + '@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==} + '@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==} + '@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==} + '@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==} + '@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==} + '@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==} + '@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==} + '@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==} + '@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==} + '@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==} + '@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==} + '@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==} + '@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==} + '@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==} + '@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==} + '@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==} + '@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==} + '@esbuild/win32-x64@0.28.2': + resolution: {integrity: sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==} engines: {node: '>=18'} cpu: [x64] os: [win32] @@ -241,12 +235,6 @@ packages: '@jridgewell/sourcemap-codec@1.5.5': resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} - '@napi-rs/wasm-runtime@1.1.4': - resolution: {integrity: sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==} - peerDependencies: - '@emnapi/core': ^1.7.1 - '@emnapi/runtime': ^1.7.1 - '@noble/ciphers@1.3.0': resolution: {integrity: sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==} engines: {node: ^14.21.3 || >=16} @@ -263,100 +251,101 @@ packages: resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==} engines: {node: ^14.21.3 || >=16} - '@oxc-project/types@0.133.0': - resolution: {integrity: sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==} + '@oxc-project/types@0.155.0': + resolution: {integrity: sha512-SeE8JPwW1xs1tHeNycjUtUBdhorRa8o4jlvjwk49R7/Z291i+4DQa7JJIgOm/TaYQZx+QrPQbVJ/9c8dMIZN8Q==} + + '@rolldown/binding-android-arm-eabi@1.2.15': + resolution: {integrity: sha512-aLcgK9gIJ3YRvrrtfSBbRa27F5WrpiTaPulnFpsHPxpUHgFlSgnU4854MHwoRGEBhfRJDWCS2WQ7lIjskE9Olw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [android] - '@rolldown/binding-android-arm64@1.0.3': - resolution: {integrity: sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==} + '@rolldown/binding-android-arm64@1.2.15': + resolution: {integrity: sha512-xD7DdZCrbThKuxNg7ooQmvp07ys4J/pnSEMTG3/OdOWl6daC67m/Q4fL78sRHMxTH/N4fGUbYhcPM0MF5WFHkg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@rolldown/binding-darwin-arm64@1.0.3': - resolution: {integrity: sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA==} + '@rolldown/binding-darwin-arm64@1.2.15': + resolution: {integrity: sha512-m2WuQ6r0B4OTYxyPpNLtXaMRbRDUbG8YQV2Q3KTdSSK8Th6KHCnC8jVCJt8bvYeSB5WivkkNbc85mKadaSdOxA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@rolldown/binding-darwin-x64@1.0.3': - resolution: {integrity: sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg==} + '@rolldown/binding-darwin-x64@1.2.15': + resolution: {integrity: sha512-5RtnsHM36nodM9WbMy+zip0LGS/G+y5wro5RHrpOlr4ac24+1zSi9kiV2MP1myZeZ/ifEHfulQcWjnAXzc2C2A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@rolldown/binding-freebsd-x64@1.0.3': - resolution: {integrity: sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g==} + '@rolldown/binding-freebsd-x64@1.2.15': + resolution: {integrity: sha512-g3l09pyFqhu+135JKkbkwiKGQmwU5hUMUPJ4VdBADvuqR8d33L6H578rh8m7rtxbdp+VmX/+nzI7nvhSZlzpUQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@rolldown/binding-linux-arm-gnueabihf@1.0.3': - resolution: {integrity: sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw==} + '@rolldown/binding-linux-arm-gnueabihf@1.2.15': + resolution: {integrity: sha512-nIe3VugI97nGQtspPxDqA4sXMUpeiocKIP/CqpY/u/vgbT+alX+cVxu1C/oVBPKg4feNTmYovE91v4DgXvXNwQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@rolldown/binding-linux-arm64-gnu@1.0.3': - resolution: {integrity: sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw==} + '@rolldown/binding-linux-arm64-gnu@1.2.15': + resolution: {integrity: sha512-iTBjXx+B5QSvgI89lJfmqh4wTh8NabR1YZIIN3hNx4zSG0EVfVqkOvLulNpG4251pbd6/IAmZ/LefVk1Y4rPhw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-arm64-musl@1.0.3': - resolution: {integrity: sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==} + '@rolldown/binding-linux-arm64-musl@1.2.15': + resolution: {integrity: sha512-uN26XOnVR7rqQupG3V9oAG2EGGatWjcJHOeDOHUFCh4TBWmP2tHTFoVN13aYbwfm0aHqJAEmcwhAu6sooIjfqQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] - '@rolldown/binding-linux-ppc64-gnu@1.0.3': - resolution: {integrity: sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==} + '@rolldown/binding-linux-ppc64-gnu@1.2.15': + resolution: {integrity: sha512-9nWkcdd+H+XhaA3fQIwpHnKIrfx/PQ6rO0pivr78Og07tXlUlctBBJoEYLPfhTmCR/QxEVdn6uPjHV5SymPhdw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-s390x-gnu@1.0.3': - resolution: {integrity: sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==} + '@rolldown/binding-linux-s390x-gnu@1.2.15': + resolution: {integrity: sha512-Ggh0ciFjLwIusLSLz7LZYEaGdxOAUJXI+Qu5JCbhPJJHEt8vP+IjRATTJheiJsdzzTYgUiHUiw3X1Ea3ZpMBdA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] libc: [glibc] - '@rolldown/binding-linux-x64-gnu@1.0.3': - resolution: {integrity: sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==} + '@rolldown/binding-linux-x64-gnu@1.2.15': + resolution: {integrity: sha512-FHg60rS6DBePAYZ9X9F67x+JObFdmgn6tupA1C/a3B+CufFmTD4mX+e8M75tCiAO3foR/6xwVBI0KQiI7sn/rw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-x64-musl@1.0.3': - resolution: {integrity: sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==} + '@rolldown/binding-linux-x64-musl@1.2.15': + resolution: {integrity: sha512-/cvV/7v5VGz/moiz0XKRj2dE8DzsKyhIu1KpOvJGPjRywg3yscON889UGvAe8zfiJLHup7VLjBduoGWi3HusWQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [musl] - '@rolldown/binding-openharmony-arm64@1.0.3': - resolution: {integrity: sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==} + '@rolldown/binding-openharmony-arm64@1.2.15': + resolution: {integrity: sha512-MyzC5Hrv/sm+Z7TSGKP/j8001RO2xQm1zOpCNVL4j0cY/VhBZviludA2YFQ7i4lH6ZAXxQm0lcMdBzM+99mE7w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@rolldown/binding-wasm32-wasi@1.0.3': - resolution: {integrity: sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [wasm32] - - '@rolldown/binding-win32-arm64-msvc@1.0.3': - resolution: {integrity: sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g==} + '@rolldown/binding-win32-arm64-msvc@1.2.15': + resolution: {integrity: sha512-+PgYiS+AH5omy6L45ZLxybasauJaj3M8buoT83D+nzPmCayXlxUV9hydhciCKVyIg0B/v0BtXPDE1uGqNwCPpg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@rolldown/binding-win32-x64-msvc@1.0.3': - resolution: {integrity: sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA==} + '@rolldown/binding-win32-x64-msvc@1.2.15': + resolution: {integrity: sha512-HFZd2QNQYn1JbIi+Hpd7H+r/lkWxcfIu28nirZ6eCn2LafuvmExMlb/P96Sfx5tf7pPArw39IdhmCF8vmV+NhQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] @@ -378,12 +367,22 @@ packages: peerDependencies: '@solana/kit': ^6.3.0 + '@solana-program/compute-budget@0.20.0': + resolution: {integrity: sha512-7SrwpFVNX6R5sjmPnqHUohCwZ3167TsWtE1Htg5wVrnsSoKfS8o1JxH033S/mYE56jGLwusYgNAwJn+Md1JmTQ==} + peerDependencies: + '@solana/kit': ^8.5.0 + '@solana-program/record@0.3.0': resolution: {integrity: sha512-q8z86INfXRQ5357qgVBrw05vC+u3xg8Vb4E1gEwnYUvAkL3cbJSjWVfTlGRiGWYmPNq/FYIWbsFrhsxXyhaJ+w==} engines: {node: '>=24.0.0'} peerDependencies: '@solana/kit': ^7.0.0 + '@solana-program/record@0.6.0': + resolution: {integrity: sha512-8NeDjYA8OVWiL7sZqURsYFPXoT/i1c2A1Wt4k5MOMEItehX8fUOj7uCspU85lC+so+tsEmJ09qO0t8vN8kk/ZQ==} + peerDependencies: + '@solana/kit': ^8.5.0 + '@solana-program/system@0.12.0': resolution: {integrity: sha512-ZnAAWeGVMWNtJhw3GdifI2HnhZ0A0H0qs8tBkcFvxp/8wIavvO+GOM4Jd0N22u2+Lni2zcwvcrxrsxj6Mjphng==} peerDependencies: @@ -394,15 +393,10 @@ packages: peerDependencies: '@solana/kit': ^7.0.0 - '@solana-program/token-2022@0.11.0': - resolution: {integrity: sha512-4yhSajmlZdMl98vJvt63kW6L0ERtV7UFcfZGJFyUVfTMxTrgghp8BNyhh5S1Ho3p4yHqfgL4N9VgVQ9GCnqqbg==} + '@solana-program/system@0.16.0': + resolution: {integrity: sha512-/RG6q2E2vG/XpdOt8Jj/kbQktPlL5JyJuNGAeN9wDcxKDKQtrGTJpDrJgQUxiEy23fsPNXQbLN8XeCtYoMof3Q==} peerDependencies: - '@solana/kit': ^6.0.0 - '@solana/sysvars': ^5.0 - '@solana/zk-sdk': ^0.4.2 - peerDependenciesMeta: - '@solana/zk-sdk': - optional: true + '@solana/kit': ^8.5.0 '@solana-program/token-2022@0.14.1': resolution: {integrity: sha512-8yDF8xgEYU3HyfT4o7nLKHKMWQr3r2+1zBFojWYMkRyVh6YjuPO6Sxzf+p9trvL9Ddwp0d8SvqmMdYeErBZROA==} @@ -415,32 +409,42 @@ packages: '@solana/zk-sdk': optional: true + '@solana-program/token-2022@0.20.0': + resolution: {integrity: sha512-MMi+1szfgSHUdtk1drBbQsMVdTOOdGjzgH9i3IN42EZC07x5ZrXcgraZanrFSoS+DnSlTF+vFVOvmFE38rQBXA==} + peerDependencies: + '@solana/kit': ^8.5.0 + '@solana/sysvars': ^8.0.0 + '@solana/zk-sdk': ^0.5.4 + peerDependenciesMeta: + '@solana/zk-sdk': + optional: true + '@solana-program/token@0.11.0': resolution: {integrity: sha512-/lB72Pcmkn5kjUfP1Vd8F86HBlhN9RN4hJYgUG5csc23w9LCdYom2CiRdGsK25KkR9UFf6ndCCAMh83hMo+ftw==} peerDependencies: '@solana/kit': ^6.1.0 - '@solana-program/token@0.13.0': - resolution: {integrity: sha512-/Apjrd5lwOJGrPB0J5Rv7EBeclvyEBQPAGA85Scm7wBH+GpkbdLDM9uK3TNg8jjFKyWQYai/JtPHbrx7VgFLSg==} - peerDependencies: - '@solana/kit': ^6.5.0 - '@solana-program/token@0.15.0': resolution: {integrity: sha512-SeLm08EYIfT453I6lo7wTGgfMbz1s7bJ1jSHFHBFebSJHD3xF46zRgMxq3YKRlr/RM8jN0cG8SjZVu+IDvMxEA==} engines: {node: '>=24.0.0'} peerDependencies: '@solana/kit': ^7.0.0 - '@solana-program/zk-elgamal-proof@0.1.0': - resolution: {integrity: sha512-MKyeapz8P7SqkkC7h53ARFLoanb59ylVzokSMyINDH7hxY3JyiZs92/VfPa/qedhLAEHLd8jcc8sQ3pr3GyXtw==} + '@solana-program/token@0.18.0': + resolution: {integrity: sha512-YNN13I4BxBnGPGk0NzP/LLQMCmJVdunbtgqjl7/Gfp1fDXQrKXh9df8xu+2ayNdvjGJYC4c9D5vZpVetHdyJaQ==} peerDependencies: - '@solana/kit': ^5.0 + '@solana/kit': ^8.5.0 '@solana-program/zk-elgamal-proof@0.3.2': resolution: {integrity: sha512-bCiRVKtqYZpajgC2RVypZL4A0xHjQYVEsVSNMTtPJ1jjE5KOUvsXhnngGMYShK6BHv+fQP4F8QKvEVW/HOSFAg==} peerDependencies: '@solana/kit': ^7.0.0 + '@solana-program/zk-elgamal-proof@0.5.0': + resolution: {integrity: sha512-2shlu/0a/WFjERyFyhZevXG7WXRUz0kmy5DPEse3TOjH0s4fTU+Uk9kE5ijPhF85Fh662m4xT1ZZm+KBGq5y1g==} + peerDependencies: + '@solana/kit': ^8.5.0 + '@solana/accounts@6.10.0': resolution: {integrity: sha512-+FxfDOrnifoPlBkF+fr8eeQdgM6xtIgAg9xKMu3WnIz60oZd4Xnry6+ff6t+ePPoZZp397FSg9ZJet68VCWm5Q==} engines: {node: '>=20.18.0'} @@ -450,17 +454,17 @@ packages: typescript: optional: true - '@solana/accounts@6.8.0': - resolution: {integrity: sha512-rXjFYVopaEw1H2PTBQbRjKr+0i4EFuBEhRT5E0dI4cMaabSb4KKypC2gaf47+6cjU3hMlM1AcsyIs72/MqAVBw==} + '@solana/accounts@7.1.1': + resolution: {integrity: sha512-7sy9VIFMdmu/7+2kVBRMU6mEvYx/DDjfam8DsBXbh+JszaTNZH3V8FutQYHRxrca3jxiumVfsy5USwKfVg8ElQ==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: '>=5.0.0' + typescript: '>=5.4.0' peerDependenciesMeta: typescript: optional: true - '@solana/accounts@7.1.1': - resolution: {integrity: sha512-7sy9VIFMdmu/7+2kVBRMU6mEvYx/DDjfam8DsBXbh+JszaTNZH3V8FutQYHRxrca3jxiumVfsy5USwKfVg8ElQ==} + '@solana/accounts@8.5.0': + resolution: {integrity: sha512-vwwXYCobg1oG4kFeUEsGiNORjPujI2ff3yKLp6lCa7QBIlKaD7kZ2QRI3PZFYcNrMJ6HYNwNeZXR7ixg02pWdA==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -477,17 +481,17 @@ packages: typescript: optional: true - '@solana/addresses@6.8.0': - resolution: {integrity: sha512-xVlA0DNX1LVfTueVsbhxDDoqr1VxeXvgJEh2GcIN/vcJPhY3GE3AYtjTbJJmTDgPrzOccI0t6ElVb1gelJH/PQ==} + '@solana/addresses@7.1.1': + resolution: {integrity: sha512-/Tk2aTOT7UEcaJrdEcB3+SK09v5cZ/92NWqHBzEobxusTPNoeOFxa3MwV74Q1MgPecWdLz7TPreEhAKpcvV/vw==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: '>=5.0.0' + typescript: '>=5.4.0' peerDependenciesMeta: typescript: optional: true - '@solana/addresses@7.1.1': - resolution: {integrity: sha512-/Tk2aTOT7UEcaJrdEcB3+SK09v5cZ/92NWqHBzEobxusTPNoeOFxa3MwV74Q1MgPecWdLz7TPreEhAKpcvV/vw==} + '@solana/addresses@8.5.0': + resolution: {integrity: sha512-LwTrDbDSJBng9y0vwiKqb/kSS9daspTGrSYoZPafeMWpAlpmutdD1KXPDHVTa4Xz00hcAfOJXYxRXX5VAoiOag==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -504,17 +508,17 @@ packages: typescript: optional: true - '@solana/assertions@6.8.0': - resolution: {integrity: sha512-OU6prCq39fSvGL8xY1C/9vhghasvAkMiRlituzJxzJpZRfpVRrwhzLd6P5NPAPoQ28qKcenA50kFdw9+ZyneJQ==} + '@solana/assertions@7.1.1': + resolution: {integrity: sha512-tD07UKuw5i9Tw5xloVH+TUMrLzbHKixaB4DlGXumMEQU+JbYRPtFNqtMlrpVLuVM45nkbPfFp2Da0sXNRIqFHA==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: '>=5.0.0' + typescript: '>=5.4.0' peerDependenciesMeta: typescript: optional: true - '@solana/assertions@7.1.1': - resolution: {integrity: sha512-tD07UKuw5i9Tw5xloVH+TUMrLzbHKixaB4DlGXumMEQU+JbYRPtFNqtMlrpVLuVM45nkbPfFp2Da0sXNRIqFHA==} + '@solana/assertions@8.5.0': + resolution: {integrity: sha512-EZDY5rJIV8Mv9xYJ7P+jvE5pihG7pmKZ6pTqbunba/4uZSQN4Klw0FX54LDDklfDvhzmAdXN0nYAnjovTGAPEg==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -531,17 +535,17 @@ packages: typescript: optional: true - '@solana/codecs-core@6.8.0': - resolution: {integrity: sha512-udFO8TrvzgROonwX3rY3E2SG675RehILNb4ZYcKlf1mL7vkDJ9bEJnBxi87AEwl8RWZFTl+MhT0MmrJnbpvdug==} + '@solana/codecs-core@7.1.1': + resolution: {integrity: sha512-C1UOAQ7LH8RuCTfaij6hthTZeBlpp8GuD2g9Nag/xgiNKJGvAfVrcorb+kO/sufdYI8Lu+BiVvPeKOjQDQiKqg==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: '>=5.0.0' + typescript: '>=5.4.0' peerDependenciesMeta: typescript: optional: true - '@solana/codecs-core@7.1.1': - resolution: {integrity: sha512-C1UOAQ7LH8RuCTfaij6hthTZeBlpp8GuD2g9Nag/xgiNKJGvAfVrcorb+kO/sufdYI8Lu+BiVvPeKOjQDQiKqg==} + '@solana/codecs-core@8.5.0': + resolution: {integrity: sha512-ou38qNrf9XOzCWsu/I4sTzRmnrKqhblwMVvpXwXPKAAUZwkSAKQXonwgZFY68I5HK6nkfq1NLWfZFmTEIZYLiw==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -558,17 +562,17 @@ packages: typescript: optional: true - '@solana/codecs-data-structures@6.8.0': - resolution: {integrity: sha512-lHr0F+nNwgm9c+tWQX398yzYh1qDi7QSCJpY9MQ2azW4FfY2IyPSo7bqzTaWNnJh9pmJx3ZI6jHfXBnLD5k/SQ==} + '@solana/codecs-data-structures@7.1.1': + resolution: {integrity: sha512-MO+wMAuaatAQ96N3HhTsd7Uno+79rJw88P+OiU2n+pHK/rZuyu1yB2j12veqK4jUNWPR0aOyCuZ4rB2idrDjpg==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: '>=5.0.0' + typescript: '>=5.4.0' peerDependenciesMeta: typescript: optional: true - '@solana/codecs-data-structures@7.1.1': - resolution: {integrity: sha512-MO+wMAuaatAQ96N3HhTsd7Uno+79rJw88P+OiU2n+pHK/rZuyu1yB2j12veqK4jUNWPR0aOyCuZ4rB2idrDjpg==} + '@solana/codecs-data-structures@8.5.0': + resolution: {integrity: sha512-CnnNriyltkgxZAKgAJoVRsRnrtdW4KCX37BUoIsquCM+AgSvhSbxaZNz0iaHjGOX7o1Z4s6+j7nAUgad0N/w5A==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -585,17 +589,17 @@ packages: typescript: optional: true - '@solana/codecs-numbers@6.8.0': - resolution: {integrity: sha512-ebf4f1D19EAe0uhdUYOCEYnn5+EellsBxbJ42tM2yYEoIBVz5FoBBC0gSsq+UTNbQHFa7XagyBT3LewxXttiTQ==} + '@solana/codecs-numbers@7.1.1': + resolution: {integrity: sha512-TWWrQq6Wp5Yf5bSc6RbxDDYCRUBBmRtRgjvUMHGp0P9K+4uFwxllRjSZFzBPHgXj3UTeZmFJdcoD271QhAgibg==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: '>=5.0.0' + typescript: '>=5.4.0' peerDependenciesMeta: typescript: optional: true - '@solana/codecs-numbers@7.1.1': - resolution: {integrity: sha512-TWWrQq6Wp5Yf5bSc6RbxDDYCRUBBmRtRgjvUMHGp0P9K+4uFwxllRjSZFzBPHgXj3UTeZmFJdcoD271QhAgibg==} + '@solana/codecs-numbers@8.5.0': + resolution: {integrity: sha512-6Vtf52rHzjf98ykejn9bNGMaQ2k1f4UMIa+BGMbBy4mIRQ5ggdI5oCAb3sZPfJcel2JQHwDlsLHCYdpqC+n6Mg==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -615,20 +619,20 @@ packages: typescript: optional: true - '@solana/codecs-strings@6.8.0': - resolution: {integrity: sha512-Rpk5NVhbKYcPnE7wz3IpTp0GVNVs0IYKdmyzByiimgPTiII8eb8ay4wQiYHGHrpYh62hD14Qy3GiGDFgipRKqA==} + '@solana/codecs-strings@7.1.1': + resolution: {integrity: sha512-6qWl+atG60D2LmP47GyGapQFhVsG1sVhVrEaM3lV09vwrGOMeOZARZ4ObaQ5m6uQmM04G+f8dY9d17nCMbGHGg==} engines: {node: '>=20.18.0'} peerDependencies: fastestsmallesttextencoderdecoder: ^1.0.22 - typescript: '>=5.0.0' + typescript: '>=5.4.0' peerDependenciesMeta: fastestsmallesttextencoderdecoder: optional: true typescript: optional: true - '@solana/codecs-strings@7.1.1': - resolution: {integrity: sha512-6qWl+atG60D2LmP47GyGapQFhVsG1sVhVrEaM3lV09vwrGOMeOZARZ4ObaQ5m6uQmM04G+f8dY9d17nCMbGHGg==} + '@solana/codecs-strings@8.5.0': + resolution: {integrity: sha512-9lCSCUVkbPLb1o9PLDsaOatdVgrUqqWMrAqJvZPyyuvrC5++wPuKRIGq+5iU3lICY+AwWxrzVyiwdu4xaZVCiw==} engines: {node: '>=20.18.0'} peerDependencies: fastestsmallesttextencoderdecoder: ^1.0.22 @@ -639,11 +643,11 @@ packages: typescript: optional: true - '@solana/codecs@6.8.0': - resolution: {integrity: sha512-qCSAaw1qszeQflavkIM7c21qJ3BHReP/qgDelZbhsEXpZc852CCZM00FOIWuxePr6X+JjSNqJquxwdDSoZe7Bw==} + '@solana/codecs@8.5.0': + resolution: {integrity: sha512-wALOoEuL7HAaahZnrhxCwYz10p23hku/LPNfXjlvwgjVYJL08PH3uyWDFO8e9zhcNLOaR13IREE9z8zPUhJjDQ==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: '>=5.0.0' + typescript: '>=5.4.0' peerDependenciesMeta: typescript: optional: true @@ -658,18 +662,18 @@ packages: typescript: optional: true - '@solana/errors@6.8.0': - resolution: {integrity: sha512-HRTrLgTn0c99GKz4v4IKgz2+6soaRY1mh2tLW4sk1Fe4Zzv85Q6ZLK1mXrVGL73z1apyHDrr9/Sd/9ZhUsUvpA==} + '@solana/errors@7.1.1': + resolution: {integrity: sha512-q35qck8rBnNvJlPU00mnHEQm7gWvghzYz8khqVoLhjgodTzGp46VqnIOyI1LXOAF6XDal58bMNDO980MQgq8yw==} engines: {node: '>=20.18.0'} hasBin: true peerDependencies: - typescript: '>=5.0.0' + typescript: '>=5.4.0' peerDependenciesMeta: typescript: optional: true - '@solana/errors@7.1.1': - resolution: {integrity: sha512-q35qck8rBnNvJlPU00mnHEQm7gWvghzYz8khqVoLhjgodTzGp46VqnIOyI1LXOAF6XDal58bMNDO980MQgq8yw==} + '@solana/errors@8.5.0': + resolution: {integrity: sha512-y/XTiwAZsm2kHoEDJ3ac3NUq/0E4uCbOnBe2m5mmBXF3TGmF562tDKgN5pQ+thiRABvi7b2LqwTBCg4kAdtgRg==} engines: {node: '>=20.18.0'} hasBin: true peerDependencies: @@ -678,11 +682,11 @@ packages: typescript: optional: true - '@solana/fast-stable-stringify@6.8.0': - resolution: {integrity: sha512-lZa3Qnsn+9ew6rHTXkPc+uqSa3i+AWqSBhV6oYxxBc+smvuxovItU4TPIs30cTfA7lAP+j+oYAQtUDu2dLy0hA==} + '@solana/fast-stable-stringify@8.5.0': + resolution: {integrity: sha512-CTIoOwJ0NScrB8KTzr/V4PJrNHrBAz1zvamM0opgDPQZGzLrBhca1e4eQcGmF6o7Dv3Ve0HdvDJx0B2uG6YxVA==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: '>=5.0.0' + typescript: '>=5.4.0' peerDependenciesMeta: typescript: optional: true @@ -705,8 +709,8 @@ packages: typescript: optional: true - '@solana/functional@6.10.0': - resolution: {integrity: sha512-P8cevu4mAqHTXC37h1TVoOh8zhWB2tlOI/R9vWjYPpcLwcyWf8p2qq4LEGHl5kY+1C+4PNX39HsmCocXOPCDkQ==} + '@solana/fixed-points@8.5.0': + resolution: {integrity: sha512-hkB7dUAD/oxXeNOvdMXVqfKZAvOJ1o50gBwzh8yLP1ihdSxVgssb36Vg7806C5HzmIxmTKZclJJokG0cRUXVSw==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -714,11 +718,11 @@ packages: typescript: optional: true - '@solana/functional@6.8.0': - resolution: {integrity: sha512-oMSAD/8w9ujx7OplvwRWwHHFnaaxi/Xrji1XH3xAB+gzxupUpBbOmgxQ+e84x+9VN8QWk5aU3L7gmCqdTAR6OA==} + '@solana/functional@6.10.0': + resolution: {integrity: sha512-P8cevu4mAqHTXC37h1TVoOh8zhWB2tlOI/R9vWjYPpcLwcyWf8p2qq4LEGHl5kY+1C+4PNX39HsmCocXOPCDkQ==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: '>=5.0.0' + typescript: '>=5.4.0' peerDependenciesMeta: typescript: optional: true @@ -732,8 +736,8 @@ packages: typescript: optional: true - '@solana/instruction-plans@6.10.0': - resolution: {integrity: sha512-YG7mo4zykzdc6ZTV0BuN6pveK9qeBySzlYYerq578A4eQu3xcypMAYRGAvhMZtWTanjjmD6CKtM0M7kVp0TNxg==} + '@solana/functional@8.5.0': + resolution: {integrity: sha512-+8pgF1rVW78FfT0d+ceADFLKpSh/8/o9Ldx5tEkI6paiv0QeClL1rlU5nFs5tjoFkf+92x8PpiLEEGkm0CifOQ==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -741,11 +745,11 @@ packages: typescript: optional: true - '@solana/instruction-plans@6.8.0': - resolution: {integrity: sha512-osAsY8ozqohrcTcHlG1EmO3i9flc0eESMIy9akTHyVvqk915gZgkaTmt4IjcYSwBGt7i+Rh8TmLj27RrTpCKvg==} + '@solana/instruction-plans@6.10.0': + resolution: {integrity: sha512-YG7mo4zykzdc6ZTV0BuN6pveK9qeBySzlYYerq578A4eQu3xcypMAYRGAvhMZtWTanjjmD6CKtM0M7kVp0TNxg==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: '>=5.0.0' + typescript: '>=5.4.0' peerDependenciesMeta: typescript: optional: true @@ -759,8 +763,8 @@ packages: typescript: optional: true - '@solana/instructions@6.10.0': - resolution: {integrity: sha512-0TToYF+8LXQ3ofPMx+yF6yaM9l4YJvcAPMy0qV5JsrBUFlWXBSANRuudKBQLHMvb+a3OiUTq5X7omuorKMBB3A==} + '@solana/instruction-plans@8.5.0': + resolution: {integrity: sha512-cES8TzRGuJ5cdVn3hr6GskwwG68rLd8R0FqmzB9NeU/nzPnW/50nRrg36DYX1Nh+OwuU/ehg6zkNNu1Vo72lKQ==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -768,11 +772,11 @@ packages: typescript: optional: true - '@solana/instructions@6.8.0': - resolution: {integrity: sha512-dTtykhS9IeN3npCfnd7wSS6KmKAh54+g90JRtLYy5/31L2Zvunf3AJz2QUk58vgsAGZ5fuoiMyhCxRJm4rHUBQ==} + '@solana/instructions@6.10.0': + resolution: {integrity: sha512-0TToYF+8LXQ3ofPMx+yF6yaM9l4YJvcAPMy0qV5JsrBUFlWXBSANRuudKBQLHMvb+a3OiUTq5X7omuorKMBB3A==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: '>=5.0.0' + typescript: '>=5.4.0' peerDependenciesMeta: typescript: optional: true @@ -786,6 +790,15 @@ packages: typescript: optional: true + '@solana/instructions@8.5.0': + resolution: {integrity: sha512-LSMOQRicz8OalMM2DT60PtAaPjvkHPhIvmPEI8KpyWOuNRwABJBRAfn5ypcdSa69VVj4IdOY10tDWZzjN4dviA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + '@solana/keychain-core@1.4.0': resolution: {integrity: sha512-WhNYopIPdHAEwJ3RDQ7VtUbKrOa2sEV9Z/Q9RxQNlfVDykzC7j/hQrlMcl5Uc3HTTA1J1/3Hg3wbnZPshSy6xg==} peerDependencies: @@ -814,17 +827,17 @@ packages: typescript: optional: true - '@solana/keys@6.8.0': - resolution: {integrity: sha512-Wo8CnbrVfCP1Jbsb3ElMej/3dmMrl4ArPhI1mDcqIIz/O4j4HmxZYbn2BCWtnV9V/LPM638EMO2r1x6GzDNrPA==} + '@solana/keys@7.1.1': + resolution: {integrity: sha512-Rx+vzWAXUa/Ko7W6wG1HOG9B3nQFZ5dALz113WoAmBZf7iQvaLG7U4ECDM/ydR+Nbdy6wYww7zQKRIye+1d+Nw==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: '>=5.0.0' + typescript: '>=5.4.0' peerDependenciesMeta: typescript: optional: true - '@solana/keys@7.1.1': - resolution: {integrity: sha512-Rx+vzWAXUa/Ko7W6wG1HOG9B3nQFZ5dALz113WoAmBZf7iQvaLG7U4ECDM/ydR+Nbdy6wYww7zQKRIye+1d+Nw==} + '@solana/keys@8.5.0': + resolution: {integrity: sha512-mq6amguPYLklpAOC9A+boXQhpcHGjcn4QN40J0l1TvUkfWyFJ4HBbNb35fyWldqqDUV5ujOpaPZmmVvWJBK2Kw==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -847,11 +860,11 @@ packages: peerDependencies: '@solana/kit': ^7.0.0 - '@solana/kit@6.8.0': - resolution: {integrity: sha512-+McC1aCgcUBdM7Cd7U6k2ZHJ9OKCy5mzpb0XWrhkrgsFxT0QoRr0AcWJc85o6tIDfG6Jz7vVhbS3l8ugYz2Vzw==} + '@solana/kit@8.5.0': + resolution: {integrity: sha512-bMnXXADeyZFe3XyqzPhlQAIsmPYRiojaRO4JQxwGOmMwiQ5f13ZQodmsOqnt8W/n40P7r/+/pDqWuqG0TUv+yA==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: '>=5.0.0' + typescript: '>=5.4.0' peerDependenciesMeta: typescript: optional: true @@ -871,17 +884,17 @@ packages: typescript: optional: true - '@solana/nominal-types@6.8.0': - resolution: {integrity: sha512-mLmHr92pM4mEfe49GUmZ5Ry0RMqtMuFQqZYnxQqhDKMcl+Wtt820ezxYgwPhqcMxRzfqaQSO3ZxpSB0RlLBa/Q==} + '@solana/nominal-types@7.1.1': + resolution: {integrity: sha512-do4rmmOlSplVYN92zV6nROJxkiRn0c7juoH1lka2Pmq+cAC3QhQXKYAwWffTFYDJJDO9qCOh00uv2hhSZi6RDw==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: '>=5.0.0' + typescript: '>=5.4.0' peerDependenciesMeta: typescript: optional: true - '@solana/nominal-types@7.1.1': - resolution: {integrity: sha512-do4rmmOlSplVYN92zV6nROJxkiRn0c7juoH1lka2Pmq+cAC3QhQXKYAwWffTFYDJJDO9qCOh00uv2hhSZi6RDw==} + '@solana/nominal-types@8.5.0': + resolution: {integrity: sha512-OfTZ+w/C59Zkp51RJ3dzn2GXUojf9p/PMmSrOpxrj+hci3bdh4e6XDGY+mvP8HGPH+m0nfKWTBCygEslfoX6bg==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -898,17 +911,17 @@ packages: typescript: optional: true - '@solana/offchain-messages@6.8.0': - resolution: {integrity: sha512-HoniTs2uoCHGicD0dTTJ3YBhLZC9URxdXXUf0CHalLFwAidF9iNuB8dsuKk16Euu68L4/ERKKGfyC0QobBvahw==} + '@solana/offchain-messages@7.1.1': + resolution: {integrity: sha512-Py0/8HaIF0y+KSXHAWdQYDdZlGNoaqOZonTFuGKyDsrkgvod3wRc0cpZ5I/D/Rei4tVpvjNUfCXLpyoiJAZ7kg==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: '>=5.0.0' + typescript: '>=5.4.0' peerDependenciesMeta: typescript: optional: true - '@solana/offchain-messages@7.1.1': - resolution: {integrity: sha512-Py0/8HaIF0y+KSXHAWdQYDdZlGNoaqOZonTFuGKyDsrkgvod3wRc0cpZ5I/D/Rei4tVpvjNUfCXLpyoiJAZ7kg==} + '@solana/offchain-messages@8.5.0': + resolution: {integrity: sha512-C7qBBD1Gfbdv99uoQnuc8XZYwttTQJOYEG2v6z7q3mAL03PN7zdItAlBa+M2tpeRKjTJObRYnUUJDfiIyyGD/Q==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -916,11 +929,11 @@ packages: typescript: optional: true - '@solana/options@6.8.0': - resolution: {integrity: sha512-T5441HHeucFaLtaMAJQJl79T7mX007oAFPunpPebBphRvCXGv+qQwQvqa4HkYct6Jf2O0aKLBL9GSe/kfdCk9A==} + '@solana/options@8.5.0': + resolution: {integrity: sha512-Ron9FrWDkwxlmuI6D+NmrZZRngC1MUncglgyN77ThAoxDE1gGMOB88mQvEILeeqONeTA1rDg1uBvbewQcILp+w==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: '>=5.0.0' + typescript: '>=5.4.0' peerDependenciesMeta: typescript: optional: true @@ -928,11 +941,11 @@ packages: '@solana/pay-kit@file:../typescript/packages/pay-kit': resolution: {directory: ../typescript/packages/pay-kit, type: directory} - '@solana/plugin-core@6.8.0': - resolution: {integrity: sha512-kdqFIhQvJP2BDUsMOIbor35esj8u78SO33Xv0Wmo+uTRg6yKONKVK53ghw235pWrinOT4f0VnVe6MN6ciYiQVA==} + '@solana/plugin-core@8.5.0': + resolution: {integrity: sha512-1zmh+UC47yxsZHleDpH4AEVkm9yXIATkWm8v33DJuXaqX3TQXMXuxP39cXAyObIQEpCG8DK8lyAeFTUrIFcDmA==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: '>=5.0.0' + typescript: '>=5.4.0' peerDependenciesMeta: typescript: optional: true @@ -946,17 +959,17 @@ packages: typescript: optional: true - '@solana/plugin-interfaces@6.8.0': - resolution: {integrity: sha512-4olaMKGUVA7wG6BBWM5A31bQsUWBlfcL1pjhq6ZTqVEJ7vshHXGwHVlWYXYyYn9ixozGDpGSl553yaRY9jQwWw==} + '@solana/plugin-interfaces@7.1.1': + resolution: {integrity: sha512-2SHkGiftGmxg5xA5esxbwiY5wf+BOUsJG5rxD64/SHadUMaN3L0SDUSJfAXETJq5dCmVWxWGGPf2yVox4RIfdA==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: '>=5.0.0' + typescript: '>=5.4.0' peerDependenciesMeta: typescript: optional: true - '@solana/plugin-interfaces@7.1.1': - resolution: {integrity: sha512-2SHkGiftGmxg5xA5esxbwiY5wf+BOUsJG5rxD64/SHadUMaN3L0SDUSJfAXETJq5dCmVWxWGGPf2yVox4RIfdA==} + '@solana/plugin-interfaces@8.5.0': + resolution: {integrity: sha512-+s/+cCuzk23/a1ViTIugvXFYHN0txxmvqfuL4qx81NlmGawqEYws6xD+L02wNzJ5rbJeAaBhw2pUFStMfG4vYg==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -973,17 +986,17 @@ packages: typescript: optional: true - '@solana/program-client-core@6.8.0': - resolution: {integrity: sha512-eOZtEnwl+vdiy9x/rFF89NDtnvt+Q3H04A/0u4GoHnt+fFkQG3JS+ChWG9c77izmpmRuz5C1GptOPDGNDnIUgQ==} + '@solana/program-client-core@7.1.1': + resolution: {integrity: sha512-zoMq8Qg6psj6tFYpA35xKhSrF/LpdiVflV6nKohxZg3ocwtRqRhQfbY8/mjCA9EfH8vqvsn5il5CnxALRqmJJA==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: '>=5.0.0' + typescript: '>=5.4.0' peerDependenciesMeta: typescript: optional: true - '@solana/program-client-core@7.1.1': - resolution: {integrity: sha512-zoMq8Qg6psj6tFYpA35xKhSrF/LpdiVflV6nKohxZg3ocwtRqRhQfbY8/mjCA9EfH8vqvsn5il5CnxALRqmJJA==} + '@solana/program-client-core@8.5.0': + resolution: {integrity: sha512-HJcnbuvQRcWOV3nTUjzgmQRIs0Of1973UU8uOvSEEW7rxycQwNxJ7fVgxQ5sYOCbT+7rlqqTkDeczvB7I4OwoA==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -991,11 +1004,11 @@ packages: typescript: optional: true - '@solana/programs@6.8.0': - resolution: {integrity: sha512-8hSKGfPTLX9Sm7KGV/UtiGCeSzptT/9vcjbodE+ZGHKFefo5vES4UAW+qD01LjL7IumGtMJvnfhCWt81qT/jbQ==} + '@solana/programs@8.5.0': + resolution: {integrity: sha512-8PC2E/d5rwCRw1tFwQlpG65YDN56bYmPiBl99QqCP2RzhNdFJ/52xgFumL2G0uLfD3xsuFaWuOIGNxkyfXYm/Q==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: '>=5.0.0' + typescript: '>=5.4.0' peerDependenciesMeta: typescript: optional: true @@ -1009,17 +1022,17 @@ packages: typescript: optional: true - '@solana/promises@6.8.0': - resolution: {integrity: sha512-kIypZG83ZbADbrAq9/LS7LuWlVxlgJSzIpic75+9IuAfC3k5/KSus8LrvggBkCzfAyIslrUh70iz4JcnzUZrOw==} + '@solana/promises@7.1.1': + resolution: {integrity: sha512-d3lhCfiFwiVyTRR6zhy1lcjDIh+l0a5gp1WPe64Vfa2gP0myC8P5C1Tknfjrp4d97DF3uBPqKAb5vV8hahNcNA==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: '>=5.0.0' + typescript: '>=5.4.0' peerDependenciesMeta: typescript: optional: true - '@solana/promises@7.1.1': - resolution: {integrity: sha512-d3lhCfiFwiVyTRR6zhy1lcjDIh+l0a5gp1WPe64Vfa2gP0myC8P5C1Tknfjrp4d97DF3uBPqKAb5vV8hahNcNA==} + '@solana/promises@8.5.0': + resolution: {integrity: sha512-qWJbU6RGuZVrtvsGZ+2F46jccaIZDX4czYRRhS3m38cCdE+wKMbqGvWND50xP7D9egOxYKHMqJAJbLQH4gspvQ==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1036,17 +1049,17 @@ packages: typescript: optional: true - '@solana/rpc-api@6.8.0': - resolution: {integrity: sha512-v8ZKWgPtKbF6HeJcfC4ciwI8mwDCizBtRLYYjjHOu+9S9IJYyefQzsQxL5P8OjJPpI4gFauT6gsjQLo76BoojA==} + '@solana/rpc-api@7.1.1': + resolution: {integrity: sha512-ELGIqNbz8apeAxCLdD1PEPAnu6KtgHmWvUbH4VqqNg2jgWquyUOfTI5rblvdflx2Hcb7GK05w8/iiUaknOQKnw==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: '>=5.0.0' + typescript: '>=5.4.0' peerDependenciesMeta: typescript: optional: true - '@solana/rpc-api@7.1.1': - resolution: {integrity: sha512-ELGIqNbz8apeAxCLdD1PEPAnu6KtgHmWvUbH4VqqNg2jgWquyUOfTI5rblvdflx2Hcb7GK05w8/iiUaknOQKnw==} + '@solana/rpc-api@8.5.0': + resolution: {integrity: sha512-qlRZ2yC8WEWNg3VX8UEqlZOitKZaeE6KWbn3A/ybtJAYz+mvr3RMDhnQ89RDqIuxPuAFZNV21BRJv3yB9xR44Q==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1063,17 +1076,17 @@ packages: typescript: optional: true - '@solana/rpc-parsed-types@6.8.0': - resolution: {integrity: sha512-jYddZviBSUYbuUKqvNthet7KbJVI7me6xfRH2znv1SjIpmvhSPJcGN5QrlHVOasHdzEWSpvZa5VYDfnqH3aYvA==} + '@solana/rpc-parsed-types@7.1.1': + resolution: {integrity: sha512-DiQSj2rNnhOKOTs6YDjQ2y4KuOkv8lh6moLFiQnY0+TvanJrGrQjxLSrHdCUQxymQcUxzrraZL9k6vxNzId4gw==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: '>=5.0.0' + typescript: '>=5.4.0' peerDependenciesMeta: typescript: optional: true - '@solana/rpc-parsed-types@7.1.1': - resolution: {integrity: sha512-DiQSj2rNnhOKOTs6YDjQ2y4KuOkv8lh6moLFiQnY0+TvanJrGrQjxLSrHdCUQxymQcUxzrraZL9k6vxNzId4gw==} + '@solana/rpc-parsed-types@8.5.0': + resolution: {integrity: sha512-ktygZ019trgAyjr8y1GN1x4x6wJYw2Ola6UogAfJT5LoNs6kV3k84yCNAlGv34xRPqCVxlWo4nsIWJf8yWQQ2w==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1090,17 +1103,17 @@ packages: typescript: optional: true - '@solana/rpc-spec-types@6.8.0': - resolution: {integrity: sha512-ebCWgiQbIgFOehU7PdRFmYCzda3Azc/qa2Y3P8gexSHSsDAO27VwS4E05XSY+a7cIL5MYmvUa1vpDynl1Rkakw==} + '@solana/rpc-spec-types@7.1.1': + resolution: {integrity: sha512-FDDgXfAPfq28sQNnGhZr/+2kp5QTTcNZ5m/Q9y9Jrlux6brdPsbf9Sh1Q/lgz7i76arzNW/rzRY125RzqGWANg==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: '>=5.0.0' + typescript: '>=5.4.0' peerDependenciesMeta: typescript: optional: true - '@solana/rpc-spec-types@7.1.1': - resolution: {integrity: sha512-FDDgXfAPfq28sQNnGhZr/+2kp5QTTcNZ5m/Q9y9Jrlux6brdPsbf9Sh1Q/lgz7i76arzNW/rzRY125RzqGWANg==} + '@solana/rpc-spec-types@8.5.0': + resolution: {integrity: sha512-YUTMKWWlHCGBmA1wxhIilbxJlad5vEsvc8dDO9VWr7GVkQUlipEU79iGaKk4xQ6Oo1mZWxpGz5mAJUqGraTK4A==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1117,17 +1130,17 @@ packages: typescript: optional: true - '@solana/rpc-spec@6.8.0': - resolution: {integrity: sha512-kE5uOspxCVFJKNUu73hlebGiAFosjfYXbbTXAbGKfksPzy84u1oJFC2IVIobLRnqUCw1x7oJcvfnX00Zs0Itpg==} + '@solana/rpc-spec@7.1.1': + resolution: {integrity: sha512-1FwhgL18qasRYlWffdBNIUoxQyGLzdh3YMQW3y33M61vk/q1ldEGJRypV9B/SrXmxwqDiUbQ+m+zgainCTp1ZA==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: '>=5.0.0' + typescript: '>=5.4.0' peerDependenciesMeta: typescript: optional: true - '@solana/rpc-spec@7.1.1': - resolution: {integrity: sha512-1FwhgL18qasRYlWffdBNIUoxQyGLzdh3YMQW3y33M61vk/q1ldEGJRypV9B/SrXmxwqDiUbQ+m+zgainCTp1ZA==} + '@solana/rpc-spec@8.5.0': + resolution: {integrity: sha512-0oET5yc880zFGqBMJE2UB7sxW8sIs4hmsP4bmkR2y4ipm1aScC5U+Rd8GaIrupBOVOFj+RXIorC7kQycN/9nhw==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1135,20 +1148,20 @@ packages: typescript: optional: true - '@solana/rpc-subscriptions-api@6.8.0': - resolution: {integrity: sha512-cPJOsydyoqkztW3msEH09wPDYqxJcMvO6DBlvrboq6wGu1UjeP66w2eApzQ8POoQHxhyw+CfEXl1Gbu6kKwuMQ==} + '@solana/rpc-subscriptions-api@8.5.0': + resolution: {integrity: sha512-PJaAyqZkpG8vuzdxmdWMwp1JS5pyZ6PuL8OMhx6nCt3phkseqIs1NmAf8pQc/RZjIV3hJMMVCwSDG1DE8DY64w==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: '>=5.0.0' + typescript: '>=5.4.0' peerDependenciesMeta: typescript: optional: true - '@solana/rpc-subscriptions-channel-websocket@6.8.0': - resolution: {integrity: sha512-c3PpkorYwhAz1iuUfM5sLpZQi8xtZFGbaPbaPRELVeDjFSRzoa12KFnuQs4i9fbVbLy5Cnt1t23tf0bL2snZCQ==} + '@solana/rpc-subscriptions-channel-websocket@8.5.0': + resolution: {integrity: sha512-sRYYwBFg31z77zfKpJBcAO9MaUWa+bO1PlBcDiToa4luXGuR3dC8TSpi1Yip4T4NCONNzK3yhyeI6sHhGHc8Qw==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: '>=5.0.0' + typescript: '>=5.4.0' peerDependenciesMeta: typescript: optional: true @@ -1162,17 +1175,17 @@ packages: typescript: optional: true - '@solana/rpc-subscriptions-spec@6.8.0': - resolution: {integrity: sha512-+t4L5q9qE6IVfunW3n1amA/3EswJr64pVqRF7234vCUuVUz4PgYfbqtEBV3KkA1o0NwEHHM3pXuofT63nBb8Bg==} + '@solana/rpc-subscriptions-spec@7.1.1': + resolution: {integrity: sha512-yrqd+fV2Ae4hkzXX42aKRmTrz3FwvzKqO4h0ahs88dzSvXpy8l6Svu1k+uRgMlZ64g2P83jfQW+3Pj5fBoxmdw==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: '>=5.0.0' + typescript: '>=5.4.0' peerDependenciesMeta: typescript: optional: true - '@solana/rpc-subscriptions-spec@7.1.1': - resolution: {integrity: sha512-yrqd+fV2Ae4hkzXX42aKRmTrz3FwvzKqO4h0ahs88dzSvXpy8l6Svu1k+uRgMlZ64g2P83jfQW+3Pj5fBoxmdw==} + '@solana/rpc-subscriptions-spec@8.5.0': + resolution: {integrity: sha512-YdCPLHOcQWz8JhMaT/E+YC56nFDJ6D+XOTr6qRWHGe/1PIYGQDVvaFzI7+tF0b6tuv49GoMbpGdkiTX2v6KeUw==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1180,11 +1193,11 @@ packages: typescript: optional: true - '@solana/rpc-subscriptions@6.8.0': - resolution: {integrity: sha512-9CotreNZmKAP2z07FY1I7TPPvylKLFF5p4mujB5ZFMHQPp5JVQFVCmMIhSj5voZHAeYx7jdwJ2Kf0RDeClqJzA==} + '@solana/rpc-subscriptions@8.5.0': + resolution: {integrity: sha512-8hdWSDKKtMK3kRrR8TExwFo/bWHxVTu4zJ/JkePTQgNtm95kX25/hy+9JHKRtSsNUfXXYM60sQVE18cGgMU7dA==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: '>=5.0.0' + typescript: '>=5.4.0' peerDependenciesMeta: typescript: optional: true @@ -1198,17 +1211,17 @@ packages: typescript: optional: true - '@solana/rpc-transformers@6.8.0': - resolution: {integrity: sha512-GzcFkllym7eXbw7grdE41MCb15CjkibrXtr7EFsf4d6LD9DRvzFj2ZRYywS2FB2ibVP0LUXXGk3vmtkZJjfajA==} + '@solana/rpc-transformers@7.1.1': + resolution: {integrity: sha512-k8a/JZFso/nvPBgurOGJ/ZC6sXCtYE3lCvTj95i29pl45C4SgjdetJrAH/pWEEhQXcxaJs7OLBGmCh2enazlJw==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: '>=5.0.0' + typescript: '>=5.4.0' peerDependenciesMeta: typescript: optional: true - '@solana/rpc-transformers@7.1.1': - resolution: {integrity: sha512-k8a/JZFso/nvPBgurOGJ/ZC6sXCtYE3lCvTj95i29pl45C4SgjdetJrAH/pWEEhQXcxaJs7OLBGmCh2enazlJw==} + '@solana/rpc-transformers@8.5.0': + resolution: {integrity: sha512-JYq+EyfzJ1ksZubU9VHynQY1Z3k1tosdxG6KE4Cua/rFuXPosSn7o5h9FLLbSB5cTVcnj0lGNrBaVYW4AVK4iA==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1216,11 +1229,11 @@ packages: typescript: optional: true - '@solana/rpc-transport-http@6.8.0': - resolution: {integrity: sha512-jw/L0q2motGcx7yo6KvkKJd2HGVg9gvViXatFloLl1XmHbkwE7+97YYmG17WRuM5xauzI/UGYOXNW7cEB+Uaxw==} + '@solana/rpc-transport-http@8.5.0': + resolution: {integrity: sha512-xfIFZa+oxXLgA6BXaE2bXjiy2yZM1qO1URzzF0lmTekJM/okS8EZAQwEicWpYkvfdHJZ2x/oagD3AOSBBCWrsw==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: '>=5.0.0' + typescript: '>=5.4.0' peerDependenciesMeta: typescript: optional: true @@ -1234,17 +1247,17 @@ packages: typescript: optional: true - '@solana/rpc-types@6.8.0': - resolution: {integrity: sha512-vACMV9VR2JsZGDcgaMOFN/dwLK57CsE+erassxxtF12sSPXJooz+Vu1vyY2Yp2EkCc7mDf7BNkTKvSXajbt+Qw==} + '@solana/rpc-types@7.1.1': + resolution: {integrity: sha512-yHlSUWgynaaqevuqipGhhcZnmFVNs+F6KIlbUZ0kQY6NMVtaSzx5AQrtQjbtAQzNRsRTDYkKuQg8nOruiDoseQ==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: '>=5.0.0' + typescript: '>=5.4.0' peerDependenciesMeta: typescript: optional: true - '@solana/rpc-types@7.1.1': - resolution: {integrity: sha512-yHlSUWgynaaqevuqipGhhcZnmFVNs+F6KIlbUZ0kQY6NMVtaSzx5AQrtQjbtAQzNRsRTDYkKuQg8nOruiDoseQ==} + '@solana/rpc-types@8.5.0': + resolution: {integrity: sha512-L050pZqQ8gaFABF26NAYoatyZZeJo52AKvQQ3i58LRtUc6wcrpCF+4x4U/EDER2YVAc6Qx1xWvGnAomGhI6vzw==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1252,11 +1265,11 @@ packages: typescript: optional: true - '@solana/rpc@6.8.0': - resolution: {integrity: sha512-+jW4n9TDmBttY3bO3PdUo54GAnwFrd7UJsyfXoMgl/lWGQq5uddYDgnzQLtHOBP5zKslkR8h0RKkic0GZhMZrQ==} + '@solana/rpc@8.5.0': + resolution: {integrity: sha512-7CQFNOMhXrY/LT0qdsi3h0chy4A/Ao93pyBLqFQqxzlub0st8dC5wl+MDXhkxaBos/DZOu1V4EleWv6qbLMlow==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: '>=5.0.0' + typescript: '>=5.4.0' peerDependenciesMeta: typescript: optional: true @@ -1270,17 +1283,17 @@ packages: typescript: optional: true - '@solana/signers@6.8.0': - resolution: {integrity: sha512-7E1cAXBLOcz9kmHhzWdu5m3UJlJzxfwOl8irOMLJI6NnKB2EmU0B0h4I+Mlfs9w8Bfj0WQpUei21ammbNBq39g==} + '@solana/signers@7.1.1': + resolution: {integrity: sha512-UfWYnAglm21q5hS3Op1bU5mYiWfx0VesovZcIur0uYPc3EJlfBVikl8pf745x+bB77xG6lIzNbb+99t48SQbkg==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: '>=5.0.0' + typescript: '>=5.4.0' peerDependenciesMeta: typescript: optional: true - '@solana/signers@7.1.1': - resolution: {integrity: sha512-UfWYnAglm21q5hS3Op1bU5mYiWfx0VesovZcIur0uYPc3EJlfBVikl8pf745x+bB77xG6lIzNbb+99t48SQbkg==} + '@solana/signers@8.5.0': + resolution: {integrity: sha512-F9VvFsG9Av+Sbs4mQpuVlszb6msujxnqKQqa4TsRT24GOqKOFr4Xvs7HqgVJV/BPIDnz7u0omUhUILesHJDfkQ==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1297,17 +1310,17 @@ packages: typescript: optional: true - '@solana/subscribable@6.8.0': - resolution: {integrity: sha512-yj41Q97MiWrOmLj1iRFobvTdtU6H5wz5BlH5FHJg9lyapy1YQyaYF37MZx4LiUj4Ww0V3ReluIZTWWDBOJ53Jg==} + '@solana/subscribable@7.1.1': + resolution: {integrity: sha512-l4Wzc2L+7WQPeC/kaCiia1aaUY/SJJdrNHnLibKchS2pb7YbF7J2OygsweHXliWCVpG0jZwcvIVpusgygbZQLw==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: '>=5.0.0' + typescript: '>=5.4.0' peerDependenciesMeta: typescript: optional: true - '@solana/subscribable@7.1.1': - resolution: {integrity: sha512-l4Wzc2L+7WQPeC/kaCiia1aaUY/SJJdrNHnLibKchS2pb7YbF7J2OygsweHXliWCVpG0jZwcvIVpusgygbZQLw==} + '@solana/subscribable@8.5.0': + resolution: {integrity: sha512-v1/hL/l4kubwYVuaMNmtQcmTgDuKG6e9Hjv9fCxkYCdDIUERgmm9DX/So1386+6rkQBVRC7wTSH86Jq+RIqNGQ==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1320,49 +1333,60 @@ packages: peerDependencies: '@solana/kit': ^7.0.0 - '@solana/surfpool-darwin-arm64@1.4.0': - resolution: {integrity: sha512-/sh7zJEzulPtBbB7ykUmhhrox+X1BJ1ff/OH81C7X/W0usXZtIRuonSKA2KgWHFFUVFHYRemMv6GmkmbbPlTjQ==} + '@solana/surfpool-darwin-arm64@1.5.0': + resolution: {integrity: sha512-RdjEN7WDAr1Vrp1CD+NAS3pwT//TJclX9zyxjhAMpmBofwDzlCO8/yqv2CbD77UOuB/y3UWz3MvEEHxZfetKsw==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@solana/surfpool-darwin-x64@1.4.0': - resolution: {integrity: sha512-AZXo4a/MlmUAsfmbL7MQBf1aHOerR3K0Xj1Cjq64N7D5pXU9dJ4MbtU+xI+V+X6QFSN1WWdr9fIies6BwXl3qg==} + '@solana/surfpool-darwin-x64@1.5.0': + resolution: {integrity: sha512-8ScgLVX32JX7HH0XkijZxlpsNAALuzaJQDUTjJ1aPazKzunliek27TP9ZkVzzBHypyiY59wpwNue9PUGnGKdIw==} engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@solana/surfpool-linux-x64-gnu@1.4.0': - resolution: {integrity: sha512-hOZ+Yq52asaYyM2/mmd9iqir+1FM9aWSKGM7YHgAREy4pGdMvtcgMSAo36n/zCcWfb83Byey8SQUXRvO3CqDag==} + '@solana/surfpool-linux-x64-gnu@1.5.0': + resolution: {integrity: sha512-d+wUCBdzw7U4inKoe+Lj7XlH8Nmd6A00IZOsG3R61NQbqhRVp7zFpVCCzV00RvgAOsSedkI87I6B4ehAuyGPAg==} engines: {node: '>=18'} cpu: [x64] os: [linux] libc: [glibc] - '@solana/surfpool@1.4.0': - resolution: {integrity: sha512-YAHZz4Gkq4JKg82pVt4yENs+zxvcUliyS1Nz5JVBYiww3LZp9SG0Fsf/vHakQdgyuEaBwPuLVhS/PritsEhUbA==} + '@solana/surfpool@1.5.0': + resolution: {integrity: sha512-smTwmZpron2Zf/EcxwcjlJ5cva+nnf4GWpHf7RJj8nEzA4XcHlCDFkO+Dwoe5mapHKelePqFeWpId7Q/7zxEOg==} engines: {node: '>=18'} + peerDependencies: + '@solana/kit': ^7.0.0 + '@solana/kit-plugin-rpc': ^0.15.0 + '@solana/kit-plugin-signer': ^0.13.0 + peerDependenciesMeta: + '@solana/kit': + optional: true + '@solana/kit-plugin-rpc': + optional: true + '@solana/kit-plugin-signer': + optional: true - '@solana/sysvars@6.8.0': - resolution: {integrity: sha512-pwfMpMNL6MSmm07eHQYdTdRdzmPOd+EuVCCaNLSYdWGpYcocVJiaLiNWRV3cXA5wPj/ZFkoUGtc1bo0v7H50lw==} + '@solana/sysvars@8.5.0': + resolution: {integrity: sha512-vidKFEOAujEVizDUHFCmmIpHsS3Zu/fXJKcDUtbUn+bwD9Z1fRiper8rZW3Qdtgu1GmrH3O8MoyL2Nrp7k6QNw==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: '>=5.0.0' + typescript: '>=5.4.0' peerDependenciesMeta: typescript: optional: true - '@solana/transaction-confirmation@6.8.0': - resolution: {integrity: sha512-R6rj8y/+kZqYJr8FR/fWxgi3Pw3eCiacUyjCPTVtdVe6i+hIiBApTGLzXrSRJmAMdpZrjYBZU1cG8C6oAb+B2A==} + '@solana/transaction-confirmation@8.5.0': + resolution: {integrity: sha512-dUVHhyaJ9tt535ZJfgPAdKo6zycCAn1mqKKP/FYvCz/4FiAKnyvqj8rxd66yvvuJVhkpjbcPDDagm/P8JEYUug==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: '>=5.0.0' + typescript: '>=5.4.0' peerDependenciesMeta: typescript: optional: true - '@solana/transaction-messages@6.10.0': - resolution: {integrity: sha512-s7v8G3BTxGlKYIj3eWCG0g1296v+1LBt16mVnlRH5FuyaJ5AdhlhtRho5HUDpdwE8EXun+y1c48V6uhcZ8wdbQ==} + '@solana/transaction-introspection@8.5.0': + resolution: {integrity: sha512-VPYVLcpieu5YwwC1wmh3zZ/KHWmqJWPS7iMPVpf90L79/1Dvkg+YYQHnVeN4VQdb7VFnfpTqUnSQpfERDk0Sag==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1370,11 +1394,11 @@ packages: typescript: optional: true - '@solana/transaction-messages@6.8.0': - resolution: {integrity: sha512-jsJu9mAcN1x7onKOeC4WEvYP04UVcnkOYu/9bMe+S9jqjL+3DMy9kFZpV5FBl+TPuTNJrtOqc6Gc28hUWyyp1A==} + '@solana/transaction-messages@6.10.0': + resolution: {integrity: sha512-s7v8G3BTxGlKYIj3eWCG0g1296v+1LBt16mVnlRH5FuyaJ5AdhlhtRho5HUDpdwE8EXun+y1c48V6uhcZ8wdbQ==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: '>=5.0.0' + typescript: '>=5.4.0' peerDependenciesMeta: typescript: optional: true @@ -1388,8 +1412,8 @@ packages: typescript: optional: true - '@solana/transactions@6.10.0': - resolution: {integrity: sha512-VADSqP9OTYmhrox4pcgDd4+RjVmednXSE0+8Y7SPK4PN1pK5Az2RJ0nSsy0xcTnaOr8mF/crwFktqPrRQwSbQA==} + '@solana/transaction-messages@8.5.0': + resolution: {integrity: sha512-8SHxirU5K0kFmOwwD6XTGI5LWP/bLvLBDbemT4xDOaL+6xkLzlTMtzlgKb/Td5UtqyYOoew0FBVLJzJx/QApOw==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1397,11 +1421,11 @@ packages: typescript: optional: true - '@solana/transactions@6.8.0': - resolution: {integrity: sha512-Q46m+o3C1yL2EIZBAP5B8ou2VZwHN9wTi+muIS6/giCKO3jwUtnTEbWcZEDMj2vxUb7P2WfwTluZb/VAWxlx7Q==} + '@solana/transactions@6.10.0': + resolution: {integrity: sha512-VADSqP9OTYmhrox4pcgDd4+RjVmednXSE0+8Y7SPK4PN1pK5Az2RJ0nSsy0xcTnaOr8mF/crwFktqPrRQwSbQA==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: '>=5.0.0' + typescript: '>=5.4.0' peerDependenciesMeta: typescript: optional: true @@ -1415,6 +1439,15 @@ packages: typescript: optional: true + '@solana/transactions@8.5.0': + resolution: {integrity: sha512-IGRWI38rq5b94gy93wn/gVSQBuwNPSUv3GnWkd6R6Tc7jLbfRlYbYHJNHH5o28Fmlr+nlEn4bgu3BiqMWxuLmg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + '@standard-schema/spec@1.1.0': resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} @@ -1422,9 +1455,6 @@ packages: resolution: {integrity: sha512-/0c72BUgzzVkVTlsw5uBn8x3waTdVJ/PZGfQ6jY1eu6K7olUPf4d9lgDPA9/0sIdsR8j7o3QIG8fOCO6ItcL7A==} engines: {node: '>=12.16'} - '@tybys/wasm-util@0.10.1': - resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} - '@types/body-parser@1.19.6': resolution: {integrity: sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==} @@ -1464,40 +1494,40 @@ packages: '@types/serve-static@2.2.0': resolution: {integrity: sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==} - '@vitest/expect@4.1.11': - resolution: {integrity: sha512-VX2x5vNJXET47KAFzwERI+KRMtTTCSWTfSMKsW7JsUsXV4psq++e3DvZpuTDOpHcxytiDs6p2nhVb2tVDiiUYw==} + '@vitest/expect@4.1.12': + resolution: {integrity: sha512-vFlTt+YEu9WBpNjdGayNmlMVzrWPi1+sv853/7t2FU7hpO5gAFBKHzQmkCq5Xjpr+evegF2994LQT3hF3mRlqQ==} - '@vitest/mocker@4.1.11': - resolution: {integrity: sha512-2XJVD55d1o5AZous5CCGKS74g/riOj9odEt2bQpCVZeblHyHdnMeFl4jl0XjU21stf4mbjUkew2eXQZt65g5CQ==} + '@vitest/mocker@4.1.12': + resolution: {integrity: sha512-fKShNpKZzupWZuY0z7egydvL0sqW4INEZBEExMBMAa6izlENEVHwoXgdaTCaBZ5fwlr4xf2o1wXC83n9RpO+NA==} peerDependencies: msw: ^2.4.9 - vite: 8.0.16 + vite: 8.3.5 peerDependenciesMeta: msw: optional: true vite: optional: true - '@vitest/pretty-format@4.1.11': - resolution: {integrity: sha512-yiZzPbGTS9Sr/JpFl8zHrcIkAofNbFV6k21vIgQN/cY/oxZeXhJv5sc/MBJ5jFKWmWs+oJHw0UXLZjmf931+Vw==} + '@vitest/pretty-format@4.1.12': + resolution: {integrity: sha512-XW9O8+Mxx4VpCtkYdMJLZQQwsVryP9wk7cPKDxtXFfwSak6yRh5+2fep/Y0XF/ElBvJHq8bcYdi6aeuai0opZA==} - '@vitest/runner@4.1.11': - resolution: {integrity: sha512-LztvUgdwMNJMIkj3hQnnxiC2Xy1zNxq928W/xhjCLaNCzqTZOudjwbQf6v9IntZGPw132i2Lq2rgTRZHD3JHNw==} + '@vitest/runner@4.1.12': + resolution: {integrity: sha512-NKlVKCr5QnCe8jijdMnmkpHHU+WTqiLFR6G0pHji9uRjXK9xJl1k1nTw6F3pOOj2PDcsDt2GKQMI7wIsaT491w==} - '@vitest/snapshot@4.1.11': - resolution: {integrity: sha512-pN7ikn1ON7h8ee4gIAp4AzyK+zBtJPzVbqOgu5LCEh4VaJVbPQcgYQYJIMGQPXVeJJq1fnfazis7a5pFNPahog==} + '@vitest/snapshot@4.1.12': + resolution: {integrity: sha512-ko1y1Qgb/slzQ9mr+b89Cuqud8WG1TKtsPD8r7ZUBdvVOGt85Af2HwCqHujrhwJq95hs/9RM7fcAPg57o1vlzw==} - '@vitest/spy@4.1.11': - resolution: {integrity: sha512-apNa/prQy2qCeywhnixOHPRCgGNhvg7T4Dapfl1GahLp/R+uhBm5cPyFoNVyqsNd2h1nJxL6BqqdIjiABL60YA==} + '@vitest/spy@4.1.12': + resolution: {integrity: sha512-RGq9x4JNGNTZHEJxvN0oSiJjeSCExm0n2gZKKJZHY9cX5AVA6M7VJILBT3ZJ/tJ/0J9uWT7fETV9/btoi//vSg==} - '@vitest/utils@4.1.11': - resolution: {integrity: sha512-zTCVGpyFsGWBhllOyKlTw/vnr6D9qxsfSDyfbyZmTyjHw5N/VuvzHpHoQjm2ZJzn4RJgx5w4r7V0er69CmLgPQ==} + '@vitest/utils@4.1.12': + resolution: {integrity: sha512-Q3awXrwOfEV+qc3WmO5ONyE0yO7Q1gQ9/oyHxGLZ/pl7N3NO/ZztqQwKLuwMkV+CA1JYSIeO3gkHnRDIo4AVaA==} abitype@1.2.3: resolution: {integrity: sha512-Ofer5QUnuUdTFsBRwARMoWKOH1ND5ehwYhJ3OJ/BQO+StkwQjHw0XyVh4vDttzHB7QOFhPHa/o413PJ82gU/Tg==} peerDependencies: typescript: '>=5.0.4' - zod: ^3.22.0 || ^4.0.0 + zod: 4.6.7 peerDependenciesMeta: typescript: optional: true @@ -1508,7 +1538,7 @@ packages: resolution: {integrity: sha512-dpKH+N27vRjarMVTFFkeY445VTKftzGWpL0FiT7xmVmzQRKazZexzC5uHG0f6XKsVLAuUlndnbGau6lRejClxg==} peerDependencies: typescript: '>=5.0.4' - zod: ^3.22.0 || ^4.0.0 + zod: 4.6.7 peerDependenciesMeta: typescript: optional: true @@ -1529,8 +1559,8 @@ packages: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} - body-parser@1.20.5: - resolution: {integrity: sha512-3grm+/2tUOvu2cjJkvsIxrv/wVpfXQW4PsQHYm7yk4vfpu7Ekl6nEsYBoJUL6qDwZUx8wUhQ8tR2qz+ad9c9OA==} + body-parser@1.20.9: + resolution: {integrity: sha512-FISIQxV5u91Y9gvuFq3q/tA/qTqLJn3AhRcEvyozyhJTh5OBFFtv827AdHU7Rbyct4r+Ba1/99oFa1Y3yuFsdw==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} bytes@3.1.2: @@ -1553,10 +1583,6 @@ packages: resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} - commander@14.0.3: - resolution: {integrity: sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==} - engines: {node: '>=20'} - commander@15.0.0: resolution: {integrity: sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==} engines: {node: '>=22.12.0'} @@ -1625,8 +1651,8 @@ packages: resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==} engines: {node: '>= 0.4'} - esbuild@0.27.7: - resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==} + esbuild@0.28.2: + resolution: {integrity: sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==} engines: {node: '>=18'} hasBin: true @@ -1658,8 +1684,8 @@ packages: fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - fast-uri@4.1.5: - resolution: {integrity: sha512-vZeoMRB4epNr7QfdHxel7te/RcX16CxyXI07JCCTFWZA2s4v1azGNESRj+2EoaHSaWFL/Z3GmKT2jF6A202jLg==} + fast-uri@4.2.3: + resolution: {integrity: sha512-I1PXwP5eAhlNlcdpjt9CgB59op2ZvZfxw+BkqGFVIUOgNpCVTcTqp3HhTX7brxj5vsip+nSY4nTvff+eIA76hg==} fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} @@ -1698,9 +1724,6 @@ packages: resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} - get-tsconfig@4.14.0: - resolution: {integrity: sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==} - gopd@1.2.0: resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} engines: {node: '>= 0.4'} @@ -1736,78 +1759,78 @@ packages: json-schema-traverse@1.0.0: resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} - lightningcss-android-arm64@1.32.0: - resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} + lightningcss-android-arm64@1.33.0: + resolution: {integrity: sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [android] - lightningcss-darwin-arm64@1.32.0: - resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} + lightningcss-darwin-arm64@1.33.0: + resolution: {integrity: sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [darwin] - lightningcss-darwin-x64@1.32.0: - resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} + lightningcss-darwin-x64@1.33.0: + resolution: {integrity: sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [darwin] - lightningcss-freebsd-x64@1.32.0: - resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} + lightningcss-freebsd-x64@1.33.0: + resolution: {integrity: sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [freebsd] - lightningcss-linux-arm-gnueabihf@1.32.0: - resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} + lightningcss-linux-arm-gnueabihf@1.33.0: + resolution: {integrity: sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==} engines: {node: '>= 12.0.0'} cpu: [arm] os: [linux] - lightningcss-linux-arm64-gnu@1.32.0: - resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} + lightningcss-linux-arm64-gnu@1.33.0: + resolution: {integrity: sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] libc: [glibc] - lightningcss-linux-arm64-musl@1.32.0: - resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} + lightningcss-linux-arm64-musl@1.33.0: + resolution: {integrity: sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] libc: [musl] - lightningcss-linux-x64-gnu@1.32.0: - resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} + lightningcss-linux-x64-gnu@1.33.0: + resolution: {integrity: sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] libc: [glibc] - lightningcss-linux-x64-musl@1.32.0: - resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} + lightningcss-linux-x64-musl@1.33.0: + resolution: {integrity: sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] libc: [musl] - lightningcss-win32-arm64-msvc@1.32.0: - resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} + lightningcss-win32-arm64-msvc@1.33.0: + resolution: {integrity: sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [win32] - lightningcss-win32-x64-msvc@1.32.0: - resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} + lightningcss-win32-x64-msvc@1.33.0: + resolution: {integrity: sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [win32] - lightningcss@1.32.0: - resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} + lightningcss@1.33.0: + resolution: {integrity: sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==} engines: {node: '>= 12.0.0'} magic-string@0.30.21: @@ -1919,6 +1942,10 @@ packages: resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} engines: {node: '>=12'} + picomatch@4.0.7: + resolution: {integrity: sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==} + engines: {node: '>=12'} + postcss@8.5.23: resolution: {integrity: sha512-g50586zr4bZmwFiTlflMu8E0bDTb5I5gertgwAKmsdUlTQIhZtunzUlD1WSzwcVWPoAVpsrA6vlfCD7oXvRwgg==} engines: {node: ^10 || ^12 || >=14} @@ -1943,11 +1970,8 @@ packages: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} - resolve-pkg-maps@1.0.0: - resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} - - rolldown@1.0.3: - resolution: {integrity: sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==} + rolldown@1.2.15: + resolution: {integrity: sha512-6odND+fel5zVw3I4Yc2e69gvguDnX0CAAGiNDZSq4ik5WUcaLrkD2GLuog0XcODbor31hZ5ayEMgVDno+KPV5g==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true @@ -2016,10 +2040,6 @@ packages: resolution: {integrity: sha512-VKS/ZaQhhkKFMANmAOhhXVoIfBXblQxGX1myCQ2faQrfmobMftXeJPcZGp0gS07ocvGJWDLZGyOZDadDBqYIJg==} engines: {node: '>=18'} - tinyglobby@0.2.16: - resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==} - engines: {node: '>=12.0.0'} - tinyglobby@0.2.17: resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} engines: {node: '>=12.0.0'} @@ -2032,11 +2052,8 @@ packages: resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} engines: {node: '>=0.6'} - tslib@2.8.1: - resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - - tsx@4.21.0: - resolution: {integrity: sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==} + tsx@4.23.15: + resolution: {integrity: sha512-Yiex1Ovn8z2xPpOWckIiysV1SSyRMY9BkLF++q0yKiDxCqRhosKfMg3janKkiLBwZ5c/YryloKwGZcrEmtwxKw==} engines: {node: '>=18.0.0'} hasBin: true @@ -2052,8 +2069,8 @@ packages: undici-types@7.19.2: resolution: {integrity: sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==} - undici-types@8.1.0: - resolution: {integrity: sha512-JlLXdMmH4kxyn2JPtGK/cajzKY7F15OKYG8sO5HfkIC1AC09sLUeptGFKjnMWnprDQ2EwzYDO3kgzkK3aaoHCA==} + undici-types@8.12.3: + resolution: {integrity: sha512-EXE4ydL3S76dFb27UFjNVZHTyv/TLdATj/KUe29ptdcg6qXL48J2tZ3126E5kICj5jn781OR+XlVH1N6Mz8jbA==} unpipe@1.0.0: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} @@ -2075,14 +2092,14 @@ packages: typescript: optional: true - vite@8.0.16: - resolution: {integrity: sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==} + vite@8.3.5: + resolution: {integrity: sha512-z1YpjieJ9g0ebTmQpLBv/oq9E3F9EIlOe+7LahW8SrE3LTiG3udBRUXQOlYXP9b+IC2q2phHeVxj9xGlw34OEQ==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: '@types/node': ^20.19.0 || >=22.12.0 - '@vitejs/devtools': ^0.1.18 - esbuild: ^0.27.0 || ^0.28.0 + '@vitejs/devtools': ^0.7.1 || ^0.8.0 + esbuild: 0.28.2 jiti: '>=1.21.0' less: ^4.0.0 sass: ^1.70.0 @@ -2118,23 +2135,23 @@ packages: yaml: optional: true - vitest@4.1.11: - resolution: {integrity: sha512-fhACrNXUidIbGSBr5FlbuBkO7VWC1ZyLl0DO4CU2DrQoAPxX84Ysxs+HeGQpii5lZWV1Q4gBZTTu49mF+A6Edw==} + vitest@4.1.12: + resolution: {integrity: sha512-5eWdz2yb3ajxWF3C8C4TjkXl7FGm3n2E/VlazALrQHzK7nYMSGFnCZto0bbPNl77AwkOZVLk0YnBAejUu0NiWA==} engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@opentelemetry/api': ^1.9.0 '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/browser-playwright': 4.1.11 - '@vitest/browser-preview': 4.1.11 - '@vitest/browser-webdriverio': 4.1.11 - '@vitest/coverage-istanbul': 4.1.11 - '@vitest/coverage-v8': 4.1.11 - '@vitest/ui': 4.1.11 + '@vitest/browser-playwright': 4.1.12 + '@vitest/browser-preview': 4.1.12 + '@vitest/browser-webdriverio': ^4.1.11 + '@vitest/coverage-istanbul': 4.1.12 + '@vitest/coverage-v8': 4.1.12 + '@vitest/ui': 4.1.12 happy-dom: '*' jsdom: '*' - vite: 8.0.16 + vite: 8.3.5 peerDependenciesMeta: '@edge-runtime/vm': optional: true @@ -2181,116 +2198,93 @@ packages: engines: {node: '>= 14.6'} hasBin: true - zod@4.4.3: - resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} + zod@4.6.7: + resolution: {integrity: sha512-g8W2D2kU6a8untc053fX1uVBKzM7yqAxW/3zwk83+6RyF2+SKOuV+c0wBDhUwzV1PaGapmZH+rmcUzPf+3CGwg==} snapshots: '@adraffy/ens-normalize@1.11.1': {} - '@emnapi/core@1.10.0': - dependencies: - '@emnapi/wasi-threads': 1.2.1 - tslib: 2.8.1 - optional: true - - '@emnapi/runtime@1.10.0': - dependencies: - tslib: 2.8.1 - optional: true - - '@emnapi/wasi-threads@1.2.1': - dependencies: - tslib: 2.8.1 - optional: true - - '@esbuild/aix-ppc64@0.27.7': + '@esbuild/aix-ppc64@0.28.2': optional: true - '@esbuild/android-arm64@0.27.7': + '@esbuild/android-arm64@0.28.2': optional: true - '@esbuild/android-arm@0.27.7': + '@esbuild/android-arm@0.28.2': optional: true - '@esbuild/android-x64@0.27.7': + '@esbuild/android-x64@0.28.2': optional: true - '@esbuild/darwin-arm64@0.27.7': + '@esbuild/darwin-arm64@0.28.2': optional: true - '@esbuild/darwin-x64@0.27.7': + '@esbuild/darwin-x64@0.28.2': optional: true - '@esbuild/freebsd-arm64@0.27.7': + '@esbuild/freebsd-arm64@0.28.2': optional: true - '@esbuild/freebsd-x64@0.27.7': + '@esbuild/freebsd-x64@0.28.2': optional: true - '@esbuild/linux-arm64@0.27.7': + '@esbuild/linux-arm64@0.28.2': optional: true - '@esbuild/linux-arm@0.27.7': + '@esbuild/linux-arm@0.28.2': optional: true - '@esbuild/linux-ia32@0.27.7': + '@esbuild/linux-ia32@0.28.2': optional: true - '@esbuild/linux-loong64@0.27.7': + '@esbuild/linux-loong64@0.28.2': optional: true - '@esbuild/linux-mips64el@0.27.7': + '@esbuild/linux-mips64el@0.28.2': optional: true - '@esbuild/linux-ppc64@0.27.7': + '@esbuild/linux-ppc64@0.28.2': optional: true - '@esbuild/linux-riscv64@0.27.7': + '@esbuild/linux-riscv64@0.28.2': optional: true - '@esbuild/linux-s390x@0.27.7': + '@esbuild/linux-s390x@0.28.2': optional: true - '@esbuild/linux-x64@0.27.7': + '@esbuild/linux-x64@0.28.2': optional: true - '@esbuild/netbsd-arm64@0.27.7': + '@esbuild/netbsd-arm64@0.28.2': optional: true - '@esbuild/netbsd-x64@0.27.7': + '@esbuild/netbsd-x64@0.28.2': optional: true - '@esbuild/openbsd-arm64@0.27.7': + '@esbuild/openbsd-arm64@0.28.2': optional: true - '@esbuild/openbsd-x64@0.27.7': + '@esbuild/openbsd-x64@0.28.2': optional: true - '@esbuild/openharmony-arm64@0.27.7': + '@esbuild/openharmony-arm64@0.28.2': optional: true - '@esbuild/sunos-x64@0.27.7': + '@esbuild/sunos-x64@0.28.2': optional: true - '@esbuild/win32-arm64@0.27.7': + '@esbuild/win32-arm64@0.28.2': optional: true - '@esbuild/win32-ia32@0.27.7': + '@esbuild/win32-ia32@0.28.2': optional: true - '@esbuild/win32-x64@0.27.7': + '@esbuild/win32-x64@0.28.2': optional: true '@jridgewell/sourcemap-codec@1.5.5': {} - '@napi-rs/wasm-runtime@1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': - dependencies: - '@emnapi/core': 1.10.0 - '@emnapi/runtime': 1.10.0 - '@tybys/wasm-util': 0.10.1 - optional: true - '@noble/ciphers@1.3.0': {} '@noble/curves@1.9.1': @@ -2303,55 +2297,51 @@ snapshots: '@noble/hashes@1.8.0': {} - '@oxc-project/types@0.133.0': {} + '@oxc-project/types@0.155.0': {} - '@rolldown/binding-android-arm64@1.0.3': + '@rolldown/binding-android-arm-eabi@1.2.15': optional: true - '@rolldown/binding-darwin-arm64@1.0.3': + '@rolldown/binding-android-arm64@1.2.15': optional: true - '@rolldown/binding-darwin-x64@1.0.3': + '@rolldown/binding-darwin-arm64@1.2.15': optional: true - '@rolldown/binding-freebsd-x64@1.0.3': + '@rolldown/binding-darwin-x64@1.2.15': optional: true - '@rolldown/binding-linux-arm-gnueabihf@1.0.3': + '@rolldown/binding-freebsd-x64@1.2.15': optional: true - '@rolldown/binding-linux-arm64-gnu@1.0.3': + '@rolldown/binding-linux-arm-gnueabihf@1.2.15': optional: true - '@rolldown/binding-linux-arm64-musl@1.0.3': + '@rolldown/binding-linux-arm64-gnu@1.2.15': optional: true - '@rolldown/binding-linux-ppc64-gnu@1.0.3': + '@rolldown/binding-linux-arm64-musl@1.2.15': optional: true - '@rolldown/binding-linux-s390x-gnu@1.0.3': + '@rolldown/binding-linux-ppc64-gnu@1.2.15': optional: true - '@rolldown/binding-linux-x64-gnu@1.0.3': + '@rolldown/binding-linux-s390x-gnu@1.2.15': optional: true - '@rolldown/binding-linux-x64-musl@1.0.3': + '@rolldown/binding-linux-x64-gnu@1.2.15': optional: true - '@rolldown/binding-openharmony-arm64@1.0.3': + '@rolldown/binding-linux-x64-musl@1.2.15': optional: true - '@rolldown/binding-wasm32-wasi@1.0.3': - dependencies: - '@emnapi/core': 1.10.0 - '@emnapi/runtime': 1.10.0 - '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + '@rolldown/binding-openharmony-arm64@1.2.15': optional: true - '@rolldown/binding-win32-arm64-msvc@1.0.3': + '@rolldown/binding-win32-arm64-msvc@1.2.15': optional: true - '@rolldown/binding-win32-x64-msvc@1.0.3': + '@rolldown/binding-win32-x64-msvc@1.2.15': optional: true '@rolldown/pluginutils@1.0.1': {} @@ -2369,59 +2359,73 @@ snapshots: '@noble/hashes': 1.8.0 '@scure/base': 1.2.6 - '@solana-program/compute-budget@0.15.0(@solana/kit@6.8.0(typescript@5.9.3))': + '@solana-program/compute-budget@0.15.0(@solana/kit@8.5.0(typescript@5.9.3))': dependencies: - '@solana/kit': 6.8.0(typescript@5.9.3) + '@solana/kit': 8.5.0(typescript@5.9.3) - '@solana-program/record@0.3.0(@solana/kit@6.8.0(typescript@5.9.3))': + '@solana-program/compute-budget@0.20.0(@solana/kit@8.5.0(typescript@5.9.3))': dependencies: - '@solana/kit': 6.8.0(typescript@5.9.3) + '@solana/kit': 8.5.0(typescript@5.9.3) - '@solana-program/system@0.12.0(@solana/kit@6.8.0(typescript@5.9.3))': + '@solana-program/record@0.3.0(@solana/kit@8.5.0(typescript@5.9.3))': dependencies: - '@solana/kit': 6.8.0(typescript@5.9.3) + '@solana/kit': 8.5.0(typescript@5.9.3) - '@solana-program/system@0.13.0(@solana/kit@6.8.0(typescript@5.9.3))': + '@solana-program/record@0.6.0(@solana/kit@8.5.0(typescript@5.9.3))': dependencies: - '@solana/kit': 6.8.0(typescript@5.9.3) + '@solana-program/system': 0.16.0(@solana/kit@8.5.0(typescript@5.9.3)) + '@solana/kit': 8.5.0(typescript@5.9.3) - '@solana-program/token-2022@0.11.0(@solana/kit@6.8.0(typescript@5.9.3))': + '@solana-program/system@0.12.0(@solana/kit@8.5.0(typescript@5.9.3))': dependencies: - '@noble/curves': 1.9.7 - '@solana-program/zk-elgamal-proof': 0.1.0(@solana/kit@6.8.0(typescript@5.9.3)) - '@solana/kit': 6.8.0(typescript@5.9.3) + '@solana/kit': 8.5.0(typescript@5.9.3) + + '@solana-program/system@0.13.0(@solana/kit@8.5.0(typescript@5.9.3))': + dependencies: + '@solana/kit': 8.5.0(typescript@5.9.3) + + '@solana-program/system@0.16.0(@solana/kit@8.5.0(typescript@5.9.3))': + dependencies: + '@solana/kit': 8.5.0(typescript@5.9.3) - '@solana-program/token-2022@0.14.1(@solana/kit@6.8.0(typescript@5.9.3))': + '@solana-program/token-2022@0.14.1(@solana/kit@8.5.0(typescript@5.9.3))': dependencies: '@noble/curves': 1.9.7 - '@solana-program/record': 0.3.0(@solana/kit@6.8.0(typescript@5.9.3)) - '@solana-program/zk-elgamal-proof': 0.3.2(@solana/kit@6.8.0(typescript@5.9.3)) - '@solana/kit': 6.8.0(typescript@5.9.3) + '@solana-program/record': 0.3.0(@solana/kit@8.5.0(typescript@5.9.3)) + '@solana-program/zk-elgamal-proof': 0.3.2(@solana/kit@8.5.0(typescript@5.9.3)) + '@solana/kit': 8.5.0(typescript@5.9.3) + + '@solana-program/token-2022@0.20.0(@solana/kit@8.5.0(typescript@5.9.3))': + dependencies: + '@solana-program/record': 0.6.0(@solana/kit@8.5.0(typescript@5.9.3)) + '@solana-program/system': 0.16.0(@solana/kit@8.5.0(typescript@5.9.3)) + '@solana-program/zk-elgamal-proof': 0.5.0(@solana/kit@8.5.0(typescript@5.9.3)) + '@solana/kit': 8.5.0(typescript@5.9.3) - '@solana-program/token@0.11.0(@solana/kit@6.8.0(typescript@5.9.3))': + '@solana-program/token@0.11.0(@solana/kit@8.5.0(typescript@5.9.3))': dependencies: - '@solana-program/system': 0.12.0(@solana/kit@6.8.0(typescript@5.9.3)) - '@solana/kit': 6.8.0(typescript@5.9.3) + '@solana-program/system': 0.12.0(@solana/kit@8.5.0(typescript@5.9.3)) + '@solana/kit': 8.5.0(typescript@5.9.3) - '@solana-program/token@0.13.0(@solana/kit@6.8.0(typescript@5.9.3))': + '@solana-program/token@0.15.0(@solana/kit@8.5.0(typescript@5.9.3))': dependencies: - '@solana-program/system': 0.12.0(@solana/kit@6.8.0(typescript@5.9.3)) - '@solana/kit': 6.8.0(typescript@5.9.3) + '@solana-program/system': 0.13.0(@solana/kit@8.5.0(typescript@5.9.3)) + '@solana/kit': 8.5.0(typescript@5.9.3) - '@solana-program/token@0.15.0(@solana/kit@6.8.0(typescript@5.9.3))': + '@solana-program/token@0.18.0(@solana/kit@8.5.0(typescript@5.9.3))': dependencies: - '@solana-program/system': 0.13.0(@solana/kit@6.8.0(typescript@5.9.3)) - '@solana/kit': 6.8.0(typescript@5.9.3) + '@solana-program/system': 0.16.0(@solana/kit@8.5.0(typescript@5.9.3)) + '@solana/kit': 8.5.0(typescript@5.9.3) - '@solana-program/zk-elgamal-proof@0.1.0(@solana/kit@6.8.0(typescript@5.9.3))': + '@solana-program/zk-elgamal-proof@0.3.2(@solana/kit@8.5.0(typescript@5.9.3))': dependencies: - '@solana-program/system': 0.12.0(@solana/kit@6.8.0(typescript@5.9.3)) - '@solana/kit': 6.8.0(typescript@5.9.3) + '@solana-program/system': 0.13.0(@solana/kit@8.5.0(typescript@5.9.3)) + '@solana/kit': 8.5.0(typescript@5.9.3) - '@solana-program/zk-elgamal-proof@0.3.2(@solana/kit@6.8.0(typescript@5.9.3))': + '@solana-program/zk-elgamal-proof@0.5.0(@solana/kit@8.5.0(typescript@5.9.3))': dependencies: - '@solana-program/system': 0.13.0(@solana/kit@6.8.0(typescript@5.9.3)) - '@solana/kit': 6.8.0(typescript@5.9.3) + '@solana-program/system': 0.16.0(@solana/kit@8.5.0(typescript@5.9.3)) + '@solana/kit': 8.5.0(typescript@5.9.3) '@solana/accounts@6.10.0(typescript@5.9.3)': dependencies: @@ -2436,19 +2440,6 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/accounts@6.8.0(typescript@5.9.3)': - dependencies: - '@solana/addresses': 6.8.0(typescript@5.9.3) - '@solana/codecs-core': 6.8.0(typescript@5.9.3) - '@solana/codecs-strings': 6.8.0(typescript@5.9.3) - '@solana/errors': 6.8.0(typescript@5.9.3) - '@solana/rpc-spec': 6.8.0(typescript@5.9.3) - '@solana/rpc-types': 6.8.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - '@solana/accounts@7.1.1(typescript@5.9.3)': dependencies: '@solana/addresses': 7.1.1(typescript@5.9.3) @@ -2462,25 +2453,26 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/addresses@6.10.0(typescript@5.9.3)': + '@solana/accounts@8.5.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/addresses': 8.5.0(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-strings': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/rpc-spec': 8.5.0(typescript@5.9.3) + '@solana/rpc-types': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/addresses@6.8.0(typescript@5.9.3)': + '@solana/addresses@6.10.0(typescript@5.9.3)': dependencies: - '@solana/assertions': 6.8.0(typescript@5.9.3) - '@solana/codecs-core': 6.8.0(typescript@5.9.3) - '@solana/codecs-strings': 6.8.0(typescript@5.9.3) - '@solana/errors': 6.8.0(typescript@5.9.3) - '@solana/nominal-types': 6.8.0(typescript@5.9.3) + '@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: @@ -2498,15 +2490,21 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/assertions@6.10.0(typescript@5.9.3)': + '@solana/addresses@8.5.0(typescript@5.9.3)': dependencies: - '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/assertions': 8.5.0(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-strings': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/nominal-types': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder - '@solana/assertions@6.8.0(typescript@5.9.3)': + '@solana/assertions@6.10.0(typescript@5.9.3)': dependencies: - '@solana/errors': 6.8.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 @@ -2516,15 +2514,15 @@ snapshots: optionalDependencies: typescript: 5.9.3 - '@solana/codecs-core@6.10.0(typescript@5.9.3)': + '@solana/assertions@8.5.0(typescript@5.9.3)': dependencies: - '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 - '@solana/codecs-core@6.8.0(typescript@5.9.3)': + '@solana/codecs-core@6.10.0(typescript@5.9.3)': dependencies: - '@solana/errors': 6.8.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 @@ -2534,19 +2532,17 @@ snapshots: optionalDependencies: typescript: 5.9.3 - '@solana/codecs-data-structures@6.10.0(typescript@5.9.3)': + '@solana/codecs-core@8.5.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) + '@solana/errors': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 - '@solana/codecs-data-structures@6.8.0(typescript@5.9.3)': + '@solana/codecs-data-structures@6.10.0(typescript@5.9.3)': dependencies: - '@solana/codecs-core': 6.8.0(typescript@5.9.3) - '@solana/codecs-numbers': 6.8.0(typescript@5.9.3) - '@solana/errors': 6.8.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/errors': 6.10.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 @@ -2558,17 +2554,18 @@ snapshots: optionalDependencies: typescript: 5.9.3 - '@solana/codecs-numbers@6.10.0(typescript@5.9.3)': + '@solana/codecs-data-structures@8.5.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) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 - '@solana/codecs-numbers@6.8.0(typescript@5.9.3)': + '@solana/codecs-numbers@6.10.0(typescript@5.9.3)': dependencies: - '@solana/codecs-core': 6.8.0(typescript@5.9.3) - '@solana/errors': 6.8.0(typescript@5.9.3) + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 @@ -2579,19 +2576,18 @@ snapshots: optionalDependencies: typescript: 5.9.3 - '@solana/codecs-strings@6.10.0(typescript@5.9.3)': + '@solana/codecs-numbers@8.5.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) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 - '@solana/codecs-strings@6.8.0(typescript@5.9.3)': + '@solana/codecs-strings@6.10.0(typescript@5.9.3)': dependencies: - '@solana/codecs-core': 6.8.0(typescript@5.9.3) - '@solana/codecs-numbers': 6.8.0(typescript@5.9.3) - '@solana/errors': 6.8.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/errors': 6.10.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 @@ -2603,13 +2599,22 @@ snapshots: optionalDependencies: typescript: 5.9.3 - '@solana/codecs@6.8.0(typescript@5.9.3)': + '@solana/codecs-strings@8.5.0(typescript@5.9.3)': dependencies: - '@solana/codecs-core': 6.8.0(typescript@5.9.3) - '@solana/codecs-data-structures': 6.8.0(typescript@5.9.3) - '@solana/codecs-numbers': 6.8.0(typescript@5.9.3) - '@solana/codecs-strings': 6.8.0(typescript@5.9.3) - '@solana/options': 6.8.0(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/codecs@8.5.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-data-structures': 8.5.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.5.0(typescript@5.9.3) + '@solana/codecs-strings': 8.5.0(typescript@5.9.3) + '@solana/fixed-points': 8.5.0(typescript@5.9.3) + '@solana/options': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: @@ -2622,21 +2627,21 @@ snapshots: optionalDependencies: typescript: 5.9.3 - '@solana/errors@6.8.0(typescript@5.9.3)': + '@solana/errors@7.1.1(typescript@5.9.3)': dependencies: chalk: 5.6.2 - commander: 14.0.3 + commander: 15.0.0 optionalDependencies: typescript: 5.9.3 - '@solana/errors@7.1.1(typescript@5.9.3)': + '@solana/errors@8.5.0(typescript@5.9.3)': dependencies: chalk: 5.6.2 commander: 15.0.0 optionalDependencies: typescript: 5.9.3 - '@solana/fast-stable-stringify@6.8.0(typescript@5.9.3)': + '@solana/fast-stable-stringify@8.5.0(typescript@5.9.3)': optionalDependencies: typescript: 5.9.3 @@ -2654,11 +2659,14 @@ snapshots: optionalDependencies: typescript: 5.9.3 - '@solana/functional@6.10.0(typescript@5.9.3)': + '@solana/fixed-points@8.5.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 - '@solana/functional@6.8.0(typescript@5.9.3)': + '@solana/functional@6.10.0(typescript@5.9.3)': optionalDependencies: typescript: 5.9.3 @@ -2666,6 +2674,10 @@ snapshots: optionalDependencies: typescript: 5.9.3 + '@solana/functional@8.5.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) @@ -2679,19 +2691,6 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/instruction-plans@6.8.0(typescript@5.9.3)': - dependencies: - '@solana/errors': 6.8.0(typescript@5.9.3) - '@solana/instructions': 6.8.0(typescript@5.9.3) - '@solana/keys': 6.8.0(typescript@5.9.3) - '@solana/promises': 6.8.0(typescript@5.9.3) - '@solana/transaction-messages': 6.8.0(typescript@5.9.3) - '@solana/transactions': 6.8.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - '@solana/instruction-plans@7.1.1(typescript@5.9.3)': dependencies: '@solana/errors': 7.1.1(typescript@5.9.3) @@ -2705,17 +2704,23 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/instructions@6.10.0(typescript@5.9.3)': + '@solana/instruction-plans@8.5.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) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/instructions': 8.5.0(typescript@5.9.3) + '@solana/keys': 8.5.0(typescript@5.9.3) + '@solana/promises': 8.5.0(typescript@5.9.3) + '@solana/transaction-messages': 8.5.0(typescript@5.9.3) + '@solana/transactions': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder - '@solana/instructions@6.8.0(typescript@5.9.3)': + '@solana/instructions@6.10.0(typescript@5.9.3)': dependencies: - '@solana/codecs-core': 6.8.0(typescript@5.9.3) - '@solana/errors': 6.8.0(typescript@5.9.3) + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 @@ -2726,23 +2731,30 @@ snapshots: optionalDependencies: typescript: 5.9.3 - '@solana/keychain-core@1.4.0(@solana/addresses@7.1.1(typescript@5.9.3))(@solana/codecs-core@7.1.1(typescript@5.9.3))(@solana/codecs-strings@7.1.1(typescript@5.9.3))(@solana/keys@7.1.1(typescript@5.9.3))(@solana/signers@7.1.1(typescript@5.9.3))(@solana/transactions@7.1.1(typescript@5.9.3))': + '@solana/instructions@8.5.0(typescript@5.9.3)': dependencies: - '@solana/addresses': 7.1.1(typescript@5.9.3) - '@solana/codecs-core': 7.1.1(typescript@5.9.3) - '@solana/codecs-strings': 7.1.1(typescript@5.9.3) - '@solana/keys': 7.1.1(typescript@5.9.3) - '@solana/signers': 7.1.1(typescript@5.9.3) - '@solana/transactions': 7.1.1(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 - '@solana/keychain-memory@1.4.0(@solana/addresses@7.1.1(typescript@5.9.3))(@solana/codecs-core@7.1.1(typescript@5.9.3))(@solana/codecs-strings@7.1.1(typescript@5.9.3))(@solana/keys@7.1.1(typescript@5.9.3))(@solana/signers@7.1.1(typescript@5.9.3))(@solana/transactions@7.1.1(typescript@5.9.3))': + '@solana/keychain-core@1.4.0(@solana/addresses@8.5.0(typescript@5.9.3))(@solana/codecs-core@8.5.0(typescript@5.9.3))(@solana/codecs-strings@8.5.0(typescript@5.9.3))(@solana/keys@8.5.0(typescript@5.9.3))(@solana/signers@8.5.0(typescript@5.9.3))(@solana/transactions@8.5.0(typescript@5.9.3))': dependencies: - '@solana/addresses': 7.1.1(typescript@5.9.3) - '@solana/codecs-strings': 7.1.1(typescript@5.9.3) - '@solana/keychain-core': 1.4.0(@solana/addresses@7.1.1(typescript@5.9.3))(@solana/codecs-core@7.1.1(typescript@5.9.3))(@solana/codecs-strings@7.1.1(typescript@5.9.3))(@solana/keys@7.1.1(typescript@5.9.3))(@solana/signers@7.1.1(typescript@5.9.3))(@solana/transactions@7.1.1(typescript@5.9.3)) - '@solana/keys': 7.1.1(typescript@5.9.3) - '@solana/signers': 7.1.1(typescript@5.9.3) - '@solana/transactions': 7.1.1(typescript@5.9.3) + '@solana/addresses': 8.5.0(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-strings': 8.5.0(typescript@5.9.3) + '@solana/keys': 8.5.0(typescript@5.9.3) + '@solana/signers': 8.5.0(typescript@5.9.3) + '@solana/transactions': 8.5.0(typescript@5.9.3) + + '@solana/keychain-memory@1.4.0(@solana/addresses@8.5.0(typescript@5.9.3))(@solana/codecs-core@8.5.0(typescript@5.9.3))(@solana/codecs-strings@8.5.0(typescript@5.9.3))(@solana/keys@8.5.0(typescript@5.9.3))(@solana/signers@8.5.0(typescript@5.9.3))(@solana/transactions@8.5.0(typescript@5.9.3))': + dependencies: + '@solana/addresses': 8.5.0(typescript@5.9.3) + '@solana/codecs-strings': 8.5.0(typescript@5.9.3) + '@solana/keychain-core': 1.4.0(@solana/addresses@8.5.0(typescript@5.9.3))(@solana/codecs-core@8.5.0(typescript@5.9.3))(@solana/codecs-strings@8.5.0(typescript@5.9.3))(@solana/keys@8.5.0(typescript@5.9.3))(@solana/signers@8.5.0(typescript@5.9.3))(@solana/transactions@8.5.0(typescript@5.9.3)) + '@solana/keys': 8.5.0(typescript@5.9.3) + '@solana/signers': 8.5.0(typescript@5.9.3) + '@solana/transactions': 8.5.0(typescript@5.9.3) transitivePeerDependencies: - '@solana/codecs-core' @@ -2759,19 +2771,6 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/keys@6.8.0(typescript@5.9.3)': - dependencies: - '@solana/assertions': 6.8.0(typescript@5.9.3) - '@solana/codecs-core': 6.8.0(typescript@5.9.3) - '@solana/codecs-strings': 6.8.0(typescript@5.9.3) - '@solana/errors': 6.8.0(typescript@5.9.3) - '@solana/nominal-types': 6.8.0(typescript@5.9.3) - '@solana/promises': 6.8.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - '@solana/keys@7.1.1(typescript@5.9.3)': dependencies: '@solana/assertions': 7.1.1(typescript@5.9.3) @@ -2785,46 +2784,61 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/kit-plugin-instruction-plan@0.13.0(@solana/kit@6.8.0(typescript@5.9.3))': - dependencies: - '@solana/kit': 6.8.0(typescript@5.9.3) - - '@solana/kit-plugin-rpc@0.15.0(@solana/kit@6.8.0(typescript@5.9.3))': - dependencies: - '@solana/kit': 6.8.0(typescript@5.9.3) - '@solana/kit-plugin-instruction-plan': 0.13.0(@solana/kit@6.8.0(typescript@5.9.3)) - - '@solana/kit-plugin-signer@0.13.0(@solana/kit@6.8.0(typescript@5.9.3))': - dependencies: - '@solana/kit': 6.8.0(typescript@5.9.3) - - '@solana/kit@6.8.0(typescript@5.9.3)': - dependencies: - '@solana/accounts': 6.8.0(typescript@5.9.3) - '@solana/addresses': 6.8.0(typescript@5.9.3) - '@solana/codecs': 6.8.0(typescript@5.9.3) - '@solana/errors': 6.8.0(typescript@5.9.3) - '@solana/functional': 6.8.0(typescript@5.9.3) - '@solana/instruction-plans': 6.8.0(typescript@5.9.3) - '@solana/instructions': 6.8.0(typescript@5.9.3) - '@solana/keys': 6.8.0(typescript@5.9.3) - '@solana/offchain-messages': 6.8.0(typescript@5.9.3) - '@solana/plugin-core': 6.8.0(typescript@5.9.3) - '@solana/plugin-interfaces': 6.8.0(typescript@5.9.3) - '@solana/program-client-core': 6.8.0(typescript@5.9.3) - '@solana/programs': 6.8.0(typescript@5.9.3) - '@solana/rpc': 6.8.0(typescript@5.9.3) - '@solana/rpc-api': 6.8.0(typescript@5.9.3) - '@solana/rpc-parsed-types': 6.8.0(typescript@5.9.3) - '@solana/rpc-spec-types': 6.8.0(typescript@5.9.3) - '@solana/rpc-subscriptions': 6.8.0(typescript@5.9.3) - '@solana/rpc-types': 6.8.0(typescript@5.9.3) - '@solana/signers': 6.8.0(typescript@5.9.3) - '@solana/subscribable': 6.8.0(typescript@5.9.3) - '@solana/sysvars': 6.8.0(typescript@5.9.3) - '@solana/transaction-confirmation': 6.8.0(typescript@5.9.3) - '@solana/transaction-messages': 6.8.0(typescript@5.9.3) - '@solana/transactions': 6.8.0(typescript@5.9.3) + '@solana/keys@8.5.0(typescript@5.9.3)': + dependencies: + '@solana/assertions': 8.5.0(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-strings': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/nominal-types': 8.5.0(typescript@5.9.3) + '@solana/promises': 8.5.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/kit-plugin-instruction-plan@0.13.0(@solana/kit@8.5.0(typescript@5.9.3))': + dependencies: + '@solana/kit': 8.5.0(typescript@5.9.3) + + '@solana/kit-plugin-rpc@0.15.0(@solana/kit@8.5.0(typescript@5.9.3))': + dependencies: + '@solana/kit': 8.5.0(typescript@5.9.3) + '@solana/kit-plugin-instruction-plan': 0.13.0(@solana/kit@8.5.0(typescript@5.9.3)) + + '@solana/kit-plugin-signer@0.13.0(@solana/kit@8.5.0(typescript@5.9.3))': + dependencies: + '@solana/kit': 8.5.0(typescript@5.9.3) + + '@solana/kit@8.5.0(typescript@5.9.3)': + dependencies: + '@solana/accounts': 8.5.0(typescript@5.9.3) + '@solana/addresses': 8.5.0(typescript@5.9.3) + '@solana/codecs': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/functional': 8.5.0(typescript@5.9.3) + '@solana/instruction-plans': 8.5.0(typescript@5.9.3) + '@solana/instructions': 8.5.0(typescript@5.9.3) + '@solana/keys': 8.5.0(typescript@5.9.3) + '@solana/offchain-messages': 8.5.0(typescript@5.9.3) + '@solana/plugin-core': 8.5.0(typescript@5.9.3) + '@solana/plugin-interfaces': 8.5.0(typescript@5.9.3) + '@solana/program-client-core': 8.5.0(typescript@5.9.3) + '@solana/programs': 8.5.0(typescript@5.9.3) + '@solana/promises': 8.5.0(typescript@5.9.3) + '@solana/rpc': 8.5.0(typescript@5.9.3) + '@solana/rpc-api': 8.5.0(typescript@5.9.3) + '@solana/rpc-parsed-types': 8.5.0(typescript@5.9.3) + '@solana/rpc-spec-types': 8.5.0(typescript@5.9.3) + '@solana/rpc-subscriptions': 8.5.0(typescript@5.9.3) + '@solana/rpc-types': 8.5.0(typescript@5.9.3) + '@solana/signers': 8.5.0(typescript@5.9.3) + '@solana/subscribable': 8.5.0(typescript@5.9.3) + '@solana/sysvars': 8.5.0(typescript@5.9.3) + '@solana/transaction-confirmation': 8.5.0(typescript@5.9.3) + '@solana/transaction-introspection': 8.5.0(typescript@5.9.3) + '@solana/transaction-messages': 8.5.0(typescript@5.9.3) + '@solana/transactions': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: @@ -2832,17 +2846,17 @@ snapshots: - fastestsmallesttextencoderdecoder - utf-8-validate - '@solana/mpp@file:../typescript/packages/mpp(@solana/kit@6.8.0(typescript@5.9.3))(mppx@0.8.19(express@4.22.2)(typescript@5.9.3)(viem@2.57.2(typescript@5.9.3)(zod@4.4.3)))(typescript@5.9.3)': + '@solana/mpp@file:../typescript/packages/mpp(@solana/kit@8.5.0(typescript@5.9.3))(mppx@0.8.19(express@4.22.2)(typescript@5.9.3)(viem@2.57.2(typescript@5.9.3)(zod@4.6.7)))(typescript@5.9.3)': dependencies: - '@solana-program/compute-budget': 0.15.0(@solana/kit@6.8.0(typescript@5.9.3)) - '@solana-program/system': 0.12.0(@solana/kit@6.8.0(typescript@5.9.3)) - '@solana-program/token': 0.11.0(@solana/kit@6.8.0(typescript@5.9.3)) + '@solana-program/compute-budget': 0.15.0(@solana/kit@8.5.0(typescript@5.9.3)) + '@solana-program/system': 0.12.0(@solana/kit@8.5.0(typescript@5.9.3)) + '@solana-program/token': 0.11.0(@solana/kit@8.5.0(typescript@5.9.3)) '@solana/addresses': 6.10.0(typescript@5.9.3) - '@solana/kit': 6.8.0(typescript@5.9.3) + '@solana/kit': 8.5.0(typescript@5.9.3) '@solana/program-client-core': 6.10.0(typescript@5.9.3) - '@solana/subscriptions': 0.5.0(@solana/kit@6.8.0(typescript@5.9.3))(typescript@5.9.3) - mppx: 0.8.19(express@4.22.2)(typescript@5.9.3)(viem@2.57.2(typescript@5.9.3)(zod@4.4.3)) - zod: 4.4.3 + '@solana/subscriptions': 0.5.0(@solana/kit@8.5.0(typescript@5.9.3))(typescript@5.9.3) + mppx: 0.8.19(express@4.22.2)(typescript@5.9.3)(viem@2.57.2(typescript@5.9.3)(zod@4.6.7)) + zod: 4.6.7 transitivePeerDependencies: - '@solana/sysvars' - '@solana/zk-sdk' @@ -2853,11 +2867,11 @@ snapshots: optionalDependencies: typescript: 5.9.3 - '@solana/nominal-types@6.8.0(typescript@5.9.3)': + '@solana/nominal-types@7.1.1(typescript@5.9.3)': optionalDependencies: typescript: 5.9.3 - '@solana/nominal-types@7.1.1(typescript@5.9.3)': + '@solana/nominal-types@8.5.0(typescript@5.9.3)': optionalDependencies: typescript: 5.9.3 @@ -2876,21 +2890,6 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/offchain-messages@6.8.0(typescript@5.9.3)': - dependencies: - '@solana/addresses': 6.8.0(typescript@5.9.3) - '@solana/codecs-core': 6.8.0(typescript@5.9.3) - '@solana/codecs-data-structures': 6.8.0(typescript@5.9.3) - '@solana/codecs-numbers': 6.8.0(typescript@5.9.3) - '@solana/codecs-strings': 6.8.0(typescript@5.9.3) - '@solana/errors': 6.8.0(typescript@5.9.3) - '@solana/keys': 6.8.0(typescript@5.9.3) - '@solana/nominal-types': 6.8.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - '@solana/offchain-messages@7.1.1(typescript@5.9.3)': dependencies: '@solana/addresses': 7.1.1(typescript@5.9.3) @@ -2906,26 +2905,41 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/options@6.8.0(typescript@5.9.3)': + '@solana/offchain-messages@8.5.0(typescript@5.9.3)': dependencies: - '@solana/codecs-core': 6.8.0(typescript@5.9.3) - '@solana/codecs-data-structures': 6.8.0(typescript@5.9.3) - '@solana/codecs-numbers': 6.8.0(typescript@5.9.3) - '@solana/codecs-strings': 6.8.0(typescript@5.9.3) - '@solana/errors': 6.8.0(typescript@5.9.3) + '@solana/addresses': 8.5.0(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-data-structures': 8.5.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.5.0(typescript@5.9.3) + '@solana/codecs-strings': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/keys': 8.5.0(typescript@5.9.3) + '@solana/nominal-types': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/pay-kit@file:../typescript/packages/pay-kit(@solana/addresses@7.1.1(typescript@5.9.3))(@solana/codecs-core@7.1.1(typescript@5.9.3))(@solana/codecs-strings@7.1.1(typescript@5.9.3))(@solana/keys@7.1.1(typescript@5.9.3))(@solana/signers@7.1.1(typescript@5.9.3))(@solana/transactions@7.1.1(typescript@5.9.3))(express@4.22.2)(typescript@5.9.3)(viem@2.57.2(typescript@5.9.3)(zod@4.4.3))': + '@solana/options@8.5.0(typescript@5.9.3)': dependencies: - '@solana-program/compute-budget': 0.15.0(@solana/kit@6.8.0(typescript@5.9.3)) - '@solana-program/token': 0.13.0(@solana/kit@6.8.0(typescript@5.9.3)) - '@solana-program/token-2022': 0.11.0(@solana/kit@6.8.0(typescript@5.9.3)) - '@solana/keychain-memory': 1.4.0(@solana/addresses@7.1.1(typescript@5.9.3))(@solana/codecs-core@7.1.1(typescript@5.9.3))(@solana/codecs-strings@7.1.1(typescript@5.9.3))(@solana/keys@7.1.1(typescript@5.9.3))(@solana/signers@7.1.1(typescript@5.9.3))(@solana/transactions@7.1.1(typescript@5.9.3)) - '@solana/kit': 6.8.0(typescript@5.9.3) - mppx: 0.8.19(express@4.22.2)(typescript@5.9.3)(viem@2.57.2(typescript@5.9.3)(zod@4.4.3)) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-data-structures': 8.5.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.5.0(typescript@5.9.3) + '@solana/codecs-strings': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/pay-kit@file:../typescript/packages/pay-kit(@solana/addresses@8.5.0(typescript@5.9.3))(@solana/codecs-core@8.5.0(typescript@5.9.3))(@solana/codecs-strings@8.5.0(typescript@5.9.3))(@solana/keys@8.5.0(typescript@5.9.3))(@solana/signers@8.5.0(typescript@5.9.3))(@solana/transactions@8.5.0(typescript@5.9.3))(express@4.22.2)(typescript@5.9.3)(viem@2.57.2(typescript@5.9.3)(zod@4.6.7))': + dependencies: + '@solana-program/compute-budget': 0.20.0(@solana/kit@8.5.0(typescript@5.9.3)) + '@solana-program/token': 0.18.0(@solana/kit@8.5.0(typescript@5.9.3)) + '@solana-program/token-2022': 0.20.0(@solana/kit@8.5.0(typescript@5.9.3)) + '@solana/keychain-memory': 1.4.0(@solana/addresses@8.5.0(typescript@5.9.3))(@solana/codecs-core@8.5.0(typescript@5.9.3))(@solana/codecs-strings@8.5.0(typescript@5.9.3))(@solana/keys@8.5.0(typescript@5.9.3))(@solana/signers@8.5.0(typescript@5.9.3))(@solana/transactions@8.5.0(typescript@5.9.3)) + '@solana/kit': 8.5.0(typescript@5.9.3) + mppx: 0.8.19(express@4.22.2)(typescript@5.9.3)(viem@2.57.2(typescript@5.9.3)(zod@4.6.7)) transitivePeerDependencies: - '@modelcontextprotocol/sdk' - '@solana/addresses' @@ -2945,7 +2959,7 @@ snapshots: - utf-8-validate - viem - '@solana/plugin-core@6.8.0(typescript@5.9.3)': + '@solana/plugin-core@8.5.0(typescript@5.9.3)': optionalDependencies: typescript: 5.9.3 @@ -2963,20 +2977,6 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/plugin-interfaces@6.8.0(typescript@5.9.3)': - dependencies: - '@solana/addresses': 6.8.0(typescript@5.9.3) - '@solana/instruction-plans': 6.8.0(typescript@5.9.3) - '@solana/keys': 6.8.0(typescript@5.9.3) - '@solana/rpc-spec': 6.8.0(typescript@5.9.3) - '@solana/rpc-subscriptions-spec': 6.8.0(typescript@5.9.3) - '@solana/rpc-types': 6.8.0(typescript@5.9.3) - '@solana/signers': 6.8.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - '@solana/plugin-interfaces@7.1.1(typescript@5.9.3)': dependencies: '@solana/accounts': 7.1.1(typescript@5.9.3) @@ -2992,6 +2992,22 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/plugin-interfaces@8.5.0(typescript@5.9.3)': + dependencies: + '@solana/accounts': 8.5.0(typescript@5.9.3) + '@solana/addresses': 8.5.0(typescript@5.9.3) + '@solana/instruction-plans': 8.5.0(typescript@5.9.3) + '@solana/keys': 8.5.0(typescript@5.9.3) + '@solana/rpc-spec': 8.5.0(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 8.5.0(typescript@5.9.3) + '@solana/rpc-types': 8.5.0(typescript@5.9.3) + '@solana/signers': 8.5.0(typescript@5.9.3) + '@solana/transactions': 8.5.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) @@ -3008,22 +3024,6 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/program-client-core@6.8.0(typescript@5.9.3)': - dependencies: - '@solana/accounts': 6.8.0(typescript@5.9.3) - '@solana/addresses': 6.8.0(typescript@5.9.3) - '@solana/codecs-core': 6.8.0(typescript@5.9.3) - '@solana/errors': 6.8.0(typescript@5.9.3) - '@solana/instruction-plans': 6.8.0(typescript@5.9.3) - '@solana/instructions': 6.8.0(typescript@5.9.3) - '@solana/plugin-interfaces': 6.8.0(typescript@5.9.3) - '@solana/rpc-api': 6.8.0(typescript@5.9.3) - '@solana/signers': 6.8.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - '@solana/program-client-core@7.1.1(typescript@5.9.3)': dependencies: '@solana/accounts': 7.1.1(typescript@5.9.3) @@ -3040,10 +3040,26 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/programs@6.8.0(typescript@5.9.3)': + '@solana/program-client-core@8.5.0(typescript@5.9.3)': + dependencies: + '@solana/accounts': 8.5.0(typescript@5.9.3) + '@solana/addresses': 8.5.0(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/instruction-plans': 8.5.0(typescript@5.9.3) + '@solana/instructions': 8.5.0(typescript@5.9.3) + '@solana/plugin-interfaces': 8.5.0(typescript@5.9.3) + '@solana/rpc-api': 8.5.0(typescript@5.9.3) + '@solana/signers': 8.5.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/programs@8.5.0(typescript@5.9.3)': dependencies: - '@solana/addresses': 6.8.0(typescript@5.9.3) - '@solana/errors': 6.8.0(typescript@5.9.3) + '@solana/addresses': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: @@ -3053,11 +3069,11 @@ snapshots: optionalDependencies: typescript: 5.9.3 - '@solana/promises@6.8.0(typescript@5.9.3)': + '@solana/promises@7.1.1(typescript@5.9.3)': optionalDependencies: typescript: 5.9.3 - '@solana/promises@7.1.1(typescript@5.9.3)': + '@solana/promises@8.5.0(typescript@5.9.3)': optionalDependencies: typescript: 5.9.3 @@ -3079,24 +3095,6 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/rpc-api@6.8.0(typescript@5.9.3)': - dependencies: - '@solana/addresses': 6.8.0(typescript@5.9.3) - '@solana/codecs-core': 6.8.0(typescript@5.9.3) - '@solana/codecs-strings': 6.8.0(typescript@5.9.3) - '@solana/errors': 6.8.0(typescript@5.9.3) - '@solana/keys': 6.8.0(typescript@5.9.3) - '@solana/rpc-parsed-types': 6.8.0(typescript@5.9.3) - '@solana/rpc-spec': 6.8.0(typescript@5.9.3) - '@solana/rpc-transformers': 6.8.0(typescript@5.9.3) - '@solana/rpc-types': 6.8.0(typescript@5.9.3) - '@solana/transaction-messages': 6.8.0(typescript@5.9.3) - '@solana/transactions': 6.8.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - '@solana/rpc-api@7.1.1(typescript@5.9.3)': dependencies: '@solana/addresses': 7.1.1(typescript@5.9.3) @@ -3115,11 +3113,25 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/rpc-parsed-types@6.10.0(typescript@5.9.3)': + '@solana/rpc-api@8.5.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.5.0(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-strings': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/keys': 8.5.0(typescript@5.9.3) + '@solana/rpc-parsed-types': 8.5.0(typescript@5.9.3) + '@solana/rpc-spec': 8.5.0(typescript@5.9.3) + '@solana/rpc-transformers': 8.5.0(typescript@5.9.3) + '@solana/rpc-types': 8.5.0(typescript@5.9.3) + '@solana/transaction-messages': 8.5.0(typescript@5.9.3) + '@solana/transactions': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder - '@solana/rpc-parsed-types@6.8.0(typescript@5.9.3)': + '@solana/rpc-parsed-types@6.10.0(typescript@5.9.3)': optionalDependencies: typescript: 5.9.3 @@ -3127,11 +3139,11 @@ snapshots: optionalDependencies: typescript: 5.9.3 - '@solana/rpc-spec-types@6.10.0(typescript@5.9.3)': + '@solana/rpc-parsed-types@8.5.0(typescript@5.9.3)': optionalDependencies: typescript: 5.9.3 - '@solana/rpc-spec-types@6.8.0(typescript@5.9.3)': + '@solana/rpc-spec-types@6.10.0(typescript@5.9.3)': optionalDependencies: typescript: 5.9.3 @@ -3141,18 +3153,17 @@ snapshots: optionalDependencies: typescript: 5.9.3 - '@solana/rpc-spec@6.10.0(typescript@5.9.3)': + '@solana/rpc-spec-types@8.5.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) + '@solana/errors': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 - '@solana/rpc-spec@6.8.0(typescript@5.9.3)': + '@solana/rpc-spec@6.10.0(typescript@5.9.3)': dependencies: - '@solana/errors': 6.8.0(typescript@5.9.3) - '@solana/rpc-spec-types': 6.8.0(typescript@5.9.3) + '@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 @@ -3164,26 +3175,34 @@ snapshots: optionalDependencies: typescript: 5.9.3 - '@solana/rpc-subscriptions-api@6.8.0(typescript@5.9.3)': + '@solana/rpc-spec@8.5.0(typescript@5.9.3)': dependencies: - '@solana/addresses': 6.8.0(typescript@5.9.3) - '@solana/keys': 6.8.0(typescript@5.9.3) - '@solana/rpc-subscriptions-spec': 6.8.0(typescript@5.9.3) - '@solana/rpc-transformers': 6.8.0(typescript@5.9.3) - '@solana/rpc-types': 6.8.0(typescript@5.9.3) - '@solana/transaction-messages': 6.8.0(typescript@5.9.3) - '@solana/transactions': 6.8.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/rpc-spec-types': 8.5.0(typescript@5.9.3) + '@solana/subscribable': 8.5.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/rpc-subscriptions-api@8.5.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.5.0(typescript@5.9.3) + '@solana/keys': 8.5.0(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 8.5.0(typescript@5.9.3) + '@solana/rpc-transformers': 8.5.0(typescript@5.9.3) + '@solana/rpc-types': 8.5.0(typescript@5.9.3) + '@solana/transaction-messages': 8.5.0(typescript@5.9.3) + '@solana/transactions': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/rpc-subscriptions-channel-websocket@6.8.0(typescript@5.9.3)': + '@solana/rpc-subscriptions-channel-websocket@8.5.0(typescript@5.9.3)': dependencies: - '@solana/errors': 6.8.0(typescript@5.9.3) - '@solana/functional': 6.8.0(typescript@5.9.3) - '@solana/rpc-subscriptions-spec': 6.8.0(typescript@5.9.3) - '@solana/subscribable': 6.8.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/functional': 8.5.0(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 8.5.0(typescript@5.9.3) + '@solana/subscribable': 8.5.0(typescript@5.9.3) ws: 8.21.0 optionalDependencies: typescript: 5.9.3 @@ -3200,15 +3219,6 @@ snapshots: optionalDependencies: typescript: 5.9.3 - '@solana/rpc-subscriptions-spec@6.8.0(typescript@5.9.3)': - dependencies: - '@solana/errors': 6.8.0(typescript@5.9.3) - '@solana/promises': 6.8.0(typescript@5.9.3) - '@solana/rpc-spec-types': 6.8.0(typescript@5.9.3) - '@solana/subscribable': 6.8.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - '@solana/rpc-subscriptions-spec@7.1.1(typescript@5.9.3)': dependencies: '@solana/errors': 7.1.1(typescript@5.9.3) @@ -3218,19 +3228,28 @@ snapshots: optionalDependencies: typescript: 5.9.3 - '@solana/rpc-subscriptions@6.8.0(typescript@5.9.3)': - dependencies: - '@solana/errors': 6.8.0(typescript@5.9.3) - '@solana/fast-stable-stringify': 6.8.0(typescript@5.9.3) - '@solana/functional': 6.8.0(typescript@5.9.3) - '@solana/promises': 6.8.0(typescript@5.9.3) - '@solana/rpc-spec-types': 6.8.0(typescript@5.9.3) - '@solana/rpc-subscriptions-api': 6.8.0(typescript@5.9.3) - '@solana/rpc-subscriptions-channel-websocket': 6.8.0(typescript@5.9.3) - '@solana/rpc-subscriptions-spec': 6.8.0(typescript@5.9.3) - '@solana/rpc-transformers': 6.8.0(typescript@5.9.3) - '@solana/rpc-types': 6.8.0(typescript@5.9.3) - '@solana/subscribable': 6.8.0(typescript@5.9.3) + '@solana/rpc-subscriptions-spec@8.5.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/promises': 8.5.0(typescript@5.9.3) + '@solana/rpc-spec-types': 8.5.0(typescript@5.9.3) + '@solana/subscribable': 8.5.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/rpc-subscriptions@8.5.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/fast-stable-stringify': 8.5.0(typescript@5.9.3) + '@solana/functional': 8.5.0(typescript@5.9.3) + '@solana/promises': 8.5.0(typescript@5.9.3) + '@solana/rpc-spec-types': 8.5.0(typescript@5.9.3) + '@solana/rpc-subscriptions-api': 8.5.0(typescript@5.9.3) + '@solana/rpc-subscriptions-channel-websocket': 8.5.0(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 8.5.0(typescript@5.9.3) + '@solana/rpc-transformers': 8.5.0(typescript@5.9.3) + '@solana/rpc-types': 8.5.0(typescript@5.9.3) + '@solana/subscribable': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: @@ -3250,18 +3269,6 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/rpc-transformers@6.8.0(typescript@5.9.3)': - dependencies: - '@solana/errors': 6.8.0(typescript@5.9.3) - '@solana/functional': 6.8.0(typescript@5.9.3) - '@solana/nominal-types': 6.8.0(typescript@5.9.3) - '@solana/rpc-spec-types': 6.8.0(typescript@5.9.3) - '@solana/rpc-types': 6.8.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - '@solana/rpc-transformers@7.1.1(typescript@5.9.3)': dependencies: '@solana/errors': 7.1.1(typescript@5.9.3) @@ -3274,12 +3281,24 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/rpc-transport-http@6.8.0(typescript@5.9.3)': + '@solana/rpc-transformers@8.5.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/functional': 8.5.0(typescript@5.9.3) + '@solana/nominal-types': 8.5.0(typescript@5.9.3) + '@solana/rpc-spec-types': 8.5.0(typescript@5.9.3) + '@solana/rpc-types': 8.5.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/rpc-transport-http@8.5.0(typescript@5.9.3)': dependencies: - '@solana/errors': 6.8.0(typescript@5.9.3) - '@solana/rpc-spec': 6.8.0(typescript@5.9.3) - '@solana/rpc-spec-types': 6.8.0(typescript@5.9.3) - undici-types: 8.1.0 + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/rpc-spec': 8.5.0(typescript@5.9.3) + '@solana/rpc-spec-types': 8.5.0(typescript@5.9.3) + undici-types: 8.12.3 optionalDependencies: typescript: 5.9.3 @@ -3297,19 +3316,6 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/rpc-types@6.8.0(typescript@5.9.3)': - dependencies: - '@solana/addresses': 6.8.0(typescript@5.9.3) - '@solana/codecs-core': 6.8.0(typescript@5.9.3) - '@solana/codecs-numbers': 6.8.0(typescript@5.9.3) - '@solana/codecs-strings': 6.8.0(typescript@5.9.3) - '@solana/errors': 6.8.0(typescript@5.9.3) - '@solana/nominal-types': 6.8.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - '@solana/rpc-types@7.1.1(typescript@5.9.3)': dependencies: '@solana/addresses': 7.1.1(typescript@5.9.3) @@ -3324,17 +3330,31 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/rpc@6.8.0(typescript@5.9.3)': - dependencies: - '@solana/errors': 6.8.0(typescript@5.9.3) - '@solana/fast-stable-stringify': 6.8.0(typescript@5.9.3) - '@solana/functional': 6.8.0(typescript@5.9.3) - '@solana/rpc-api': 6.8.0(typescript@5.9.3) - '@solana/rpc-spec': 6.8.0(typescript@5.9.3) - '@solana/rpc-spec-types': 6.8.0(typescript@5.9.3) - '@solana/rpc-transformers': 6.8.0(typescript@5.9.3) - '@solana/rpc-transport-http': 6.8.0(typescript@5.9.3) - '@solana/rpc-types': 6.8.0(typescript@5.9.3) + '@solana/rpc-types@8.5.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.5.0(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.5.0(typescript@5.9.3) + '@solana/codecs-strings': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/fixed-points': 8.5.0(typescript@5.9.3) + '@solana/nominal-types': 8.5.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/rpc@8.5.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/fast-stable-stringify': 8.5.0(typescript@5.9.3) + '@solana/functional': 8.5.0(typescript@5.9.3) + '@solana/rpc-api': 8.5.0(typescript@5.9.3) + '@solana/rpc-spec': 8.5.0(typescript@5.9.3) + '@solana/rpc-spec-types': 8.5.0(typescript@5.9.3) + '@solana/rpc-transformers': 8.5.0(typescript@5.9.3) + '@solana/rpc-transport-http': 8.5.0(typescript@5.9.3) + '@solana/rpc-types': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: @@ -3356,22 +3376,6 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/signers@6.8.0(typescript@5.9.3)': - dependencies: - '@solana/addresses': 6.8.0(typescript@5.9.3) - '@solana/codecs-core': 6.8.0(typescript@5.9.3) - '@solana/errors': 6.8.0(typescript@5.9.3) - '@solana/instructions': 6.8.0(typescript@5.9.3) - '@solana/keys': 6.8.0(typescript@5.9.3) - '@solana/nominal-types': 6.8.0(typescript@5.9.3) - '@solana/offchain-messages': 6.8.0(typescript@5.9.3) - '@solana/transaction-messages': 6.8.0(typescript@5.9.3) - '@solana/transactions': 6.8.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - '@solana/signers@7.1.1(typescript@5.9.3)': dependencies: '@solana/addresses': 7.1.1(typescript@5.9.3) @@ -3388,6 +3392,22 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/signers@8.5.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.5.0(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/instructions': 8.5.0(typescript@5.9.3) + '@solana/keys': 8.5.0(typescript@5.9.3) + '@solana/nominal-types': 8.5.0(typescript@5.9.3) + '@solana/offchain-messages': 8.5.0(typescript@5.9.3) + '@solana/transaction-messages': 8.5.0(typescript@5.9.3) + '@solana/transactions': 8.5.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) @@ -3395,26 +3415,27 @@ snapshots: optionalDependencies: typescript: 5.9.3 - '@solana/subscribable@6.8.0(typescript@5.9.3)': + '@solana/subscribable@7.1.1(typescript@5.9.3)': dependencies: - '@solana/errors': 6.8.0(typescript@5.9.3) + '@solana/errors': 7.1.1(typescript@5.9.3) + '@solana/promises': 7.1.1(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 - '@solana/subscribable@7.1.1(typescript@5.9.3)': + '@solana/subscribable@8.5.0(typescript@5.9.3)': dependencies: - '@solana/errors': 7.1.1(typescript@5.9.3) - '@solana/promises': 7.1.1(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/promises': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 - '@solana/subscriptions@0.5.0(@solana/kit@6.8.0(typescript@5.9.3))(typescript@5.9.3)': + '@solana/subscriptions@0.5.0(@solana/kit@8.5.0(typescript@5.9.3))(typescript@5.9.3)': dependencies: - '@solana-program/token': 0.15.0(@solana/kit@6.8.0(typescript@5.9.3)) - '@solana-program/token-2022': 0.14.1(@solana/kit@6.8.0(typescript@5.9.3)) - '@solana/kit': 6.8.0(typescript@5.9.3) - '@solana/kit-plugin-rpc': 0.15.0(@solana/kit@6.8.0(typescript@5.9.3)) - '@solana/kit-plugin-signer': 0.13.0(@solana/kit@6.8.0(typescript@5.9.3)) + '@solana-program/token': 0.15.0(@solana/kit@8.5.0(typescript@5.9.3)) + '@solana-program/token-2022': 0.14.1(@solana/kit@8.5.0(typescript@5.9.3)) + '@solana/kit': 8.5.0(typescript@5.9.3) + '@solana/kit-plugin-rpc': 0.15.0(@solana/kit@8.5.0(typescript@5.9.3)) + '@solana/kit-plugin-signer': 0.13.0(@solana/kit@8.5.0(typescript@5.9.3)) '@solana/program-client-core': 7.1.1(typescript@5.9.3) transitivePeerDependencies: - '@solana/sysvars' @@ -3422,46 +3443,49 @@ snapshots: - fastestsmallesttextencoderdecoder - typescript - '@solana/surfpool-darwin-arm64@1.4.0': + '@solana/surfpool-darwin-arm64@1.5.0': optional: true - '@solana/surfpool-darwin-x64@1.4.0': + '@solana/surfpool-darwin-x64@1.5.0': optional: true - '@solana/surfpool-linux-x64-gnu@1.4.0': + '@solana/surfpool-linux-x64-gnu@1.5.0': optional: true - '@solana/surfpool@1.4.0': + '@solana/surfpool@1.5.0(@solana/kit-plugin-rpc@0.15.0(@solana/kit@8.5.0(typescript@5.9.3)))(@solana/kit-plugin-signer@0.13.0(@solana/kit@8.5.0(typescript@5.9.3)))(@solana/kit@8.5.0(typescript@5.9.3))': optionalDependencies: - '@solana/surfpool-darwin-arm64': 1.4.0 - '@solana/surfpool-darwin-x64': 1.4.0 - '@solana/surfpool-linux-x64-gnu': 1.4.0 - - '@solana/sysvars@6.8.0(typescript@5.9.3)': - dependencies: - '@solana/accounts': 6.8.0(typescript@5.9.3) - '@solana/codecs-core': 6.8.0(typescript@5.9.3) - '@solana/codecs-data-structures': 6.8.0(typescript@5.9.3) - '@solana/codecs-numbers': 6.8.0(typescript@5.9.3) - '@solana/errors': 6.8.0(typescript@5.9.3) - '@solana/rpc-types': 6.8.0(typescript@5.9.3) + '@solana/kit': 8.5.0(typescript@5.9.3) + '@solana/kit-plugin-rpc': 0.15.0(@solana/kit@8.5.0(typescript@5.9.3)) + '@solana/kit-plugin-signer': 0.13.0(@solana/kit@8.5.0(typescript@5.9.3)) + '@solana/surfpool-darwin-arm64': 1.5.0 + '@solana/surfpool-darwin-x64': 1.5.0 + '@solana/surfpool-linux-x64-gnu': 1.5.0 + + '@solana/sysvars@8.5.0(typescript@5.9.3)': + dependencies: + '@solana/accounts': 8.5.0(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-data-structures': 8.5.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/rpc-types': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/transaction-confirmation@6.8.0(typescript@5.9.3)': - dependencies: - '@solana/addresses': 6.8.0(typescript@5.9.3) - '@solana/codecs-strings': 6.8.0(typescript@5.9.3) - '@solana/errors': 6.8.0(typescript@5.9.3) - '@solana/keys': 6.8.0(typescript@5.9.3) - '@solana/promises': 6.8.0(typescript@5.9.3) - '@solana/rpc': 6.8.0(typescript@5.9.3) - '@solana/rpc-subscriptions': 6.8.0(typescript@5.9.3) - '@solana/rpc-types': 6.8.0(typescript@5.9.3) - '@solana/transaction-messages': 6.8.0(typescript@5.9.3) - '@solana/transactions': 6.8.0(typescript@5.9.3) + '@solana/transaction-confirmation@8.5.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.5.0(typescript@5.9.3) + '@solana/codecs-strings': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/keys': 8.5.0(typescript@5.9.3) + '@solana/promises': 8.5.0(typescript@5.9.3) + '@solana/rpc': 8.5.0(typescript@5.9.3) + '@solana/rpc-subscriptions': 8.5.0(typescript@5.9.3) + '@solana/rpc-types': 8.5.0(typescript@5.9.3) + '@solana/transaction-messages': 8.5.0(typescript@5.9.3) + '@solana/transactions': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: @@ -3469,6 +3493,21 @@ snapshots: - fastestsmallesttextencoderdecoder - utf-8-validate + '@solana/transaction-introspection@8.5.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.5.0(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-strings': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/instructions': 8.5.0(typescript@5.9.3) + '@solana/rpc-types': 8.5.0(typescript@5.9.3) + '@solana/transaction-messages': 8.5.0(typescript@5.9.3) + '@solana/transactions': 8.5.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) @@ -3485,22 +3524,6 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/transaction-messages@6.8.0(typescript@5.9.3)': - dependencies: - '@solana/addresses': 6.8.0(typescript@5.9.3) - '@solana/codecs-core': 6.8.0(typescript@5.9.3) - '@solana/codecs-data-structures': 6.8.0(typescript@5.9.3) - '@solana/codecs-numbers': 6.8.0(typescript@5.9.3) - '@solana/errors': 6.8.0(typescript@5.9.3) - '@solana/functional': 6.8.0(typescript@5.9.3) - '@solana/instructions': 6.8.0(typescript@5.9.3) - '@solana/nominal-types': 6.8.0(typescript@5.9.3) - '@solana/rpc-types': 6.8.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - '@solana/transaction-messages@7.1.1(typescript@5.9.3)': dependencies: '@solana/addresses': 7.1.1(typescript@5.9.3) @@ -3517,6 +3540,22 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/transaction-messages@8.5.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.5.0(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-data-structures': 8.5.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/functional': 8.5.0(typescript@5.9.3) + '@solana/instructions': 8.5.0(typescript@5.9.3) + '@solana/nominal-types': 8.5.0(typescript@5.9.3) + '@solana/rpc-types': 8.5.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) @@ -3536,25 +3575,6 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/transactions@6.8.0(typescript@5.9.3)': - dependencies: - '@solana/addresses': 6.8.0(typescript@5.9.3) - '@solana/codecs-core': 6.8.0(typescript@5.9.3) - '@solana/codecs-data-structures': 6.8.0(typescript@5.9.3) - '@solana/codecs-numbers': 6.8.0(typescript@5.9.3) - '@solana/codecs-strings': 6.8.0(typescript@5.9.3) - '@solana/errors': 6.8.0(typescript@5.9.3) - '@solana/functional': 6.8.0(typescript@5.9.3) - '@solana/instructions': 6.8.0(typescript@5.9.3) - '@solana/keys': 6.8.0(typescript@5.9.3) - '@solana/nominal-types': 6.8.0(typescript@5.9.3) - '@solana/rpc-types': 6.8.0(typescript@5.9.3) - '@solana/transaction-messages': 6.8.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - '@solana/transactions@7.1.1(typescript@5.9.3)': dependencies: '@solana/addresses': 7.1.1(typescript@5.9.3) @@ -3574,15 +3594,29 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/transactions@8.5.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.5.0(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-data-structures': 8.5.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.5.0(typescript@5.9.3) + '@solana/codecs-strings': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/functional': 8.5.0(typescript@5.9.3) + '@solana/instructions': 8.5.0(typescript@5.9.3) + '@solana/keys': 8.5.0(typescript@5.9.3) + '@solana/nominal-types': 8.5.0(typescript@5.9.3) + '@solana/rpc-types': 8.5.0(typescript@5.9.3) + '@solana/transaction-messages': 8.5.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@standard-schema/spec@1.1.0': {} '@stripe/stripe-js@9.13.0': {} - '@tybys/wasm-util@0.10.1': - dependencies: - tslib: 2.8.1 - optional: true - '@types/body-parser@1.19.6': dependencies: '@types/connect': 3.4.38 @@ -3633,56 +3667,56 @@ snapshots: '@types/http-errors': 2.0.5 '@types/node': 25.6.0 - '@vitest/expect@4.1.11': + '@vitest/expect@4.1.12': dependencies: '@standard-schema/spec': 1.1.0 '@types/chai': 5.2.3 - '@vitest/spy': 4.1.11 - '@vitest/utils': 4.1.11 + '@vitest/spy': 4.1.12 + '@vitest/utils': 4.1.12 chai: 6.2.2 tinyrainbow: 3.1.0 - '@vitest/mocker@4.1.11(vite@8.0.16(@types/node@25.6.0)(esbuild@0.27.7)(tsx@4.21.0)(yaml@2.8.3))': + '@vitest/mocker@4.1.12(vite@8.3.5(@types/node@25.6.0)(esbuild@0.28.2)(tsx@4.23.15)(yaml@2.8.3))': dependencies: - '@vitest/spy': 4.1.11 + '@vitest/spy': 4.1.12 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 8.0.16(@types/node@25.6.0)(esbuild@0.27.7)(tsx@4.21.0)(yaml@2.8.3) + vite: 8.3.5(@types/node@25.6.0)(esbuild@0.28.2)(tsx@4.23.15)(yaml@2.8.3) - '@vitest/pretty-format@4.1.11': + '@vitest/pretty-format@4.1.12': dependencies: tinyrainbow: 3.1.0 - '@vitest/runner@4.1.11': + '@vitest/runner@4.1.12': dependencies: - '@vitest/utils': 4.1.11 + '@vitest/utils': 4.1.12 pathe: 2.0.3 - '@vitest/snapshot@4.1.11': + '@vitest/snapshot@4.1.12': dependencies: - '@vitest/pretty-format': 4.1.11 - '@vitest/utils': 4.1.11 + '@vitest/pretty-format': 4.1.12 + '@vitest/utils': 4.1.12 magic-string: 0.30.21 pathe: 2.0.3 - '@vitest/spy@4.1.11': {} + '@vitest/spy@4.1.12': {} - '@vitest/utils@4.1.11': + '@vitest/utils@4.1.12': dependencies: - '@vitest/pretty-format': 4.1.11 + '@vitest/pretty-format': 4.1.12 convert-source-map: 2.0.0 tinyrainbow: 3.1.0 - abitype@1.2.3(typescript@5.9.3)(zod@4.4.3): + abitype@1.2.3(typescript@5.9.3)(zod@4.6.7): optionalDependencies: typescript: 5.9.3 - zod: 4.4.3 + zod: 4.6.7 - abitype@1.2.4(typescript@5.9.3)(zod@4.4.3): + abitype@1.2.4(typescript@5.9.3)(zod@4.6.7): optionalDependencies: typescript: 5.9.3 - zod: 4.4.3 + zod: 4.6.7 accepts@1.3.8: dependencies: @@ -3692,7 +3726,7 @@ snapshots: ajv@8.20.0: dependencies: fast-deep-equal: 3.1.3 - fast-uri: 4.1.5 + fast-uri: 4.2.3 json-schema-traverse: 1.0.0 require-from-string: 2.0.2 @@ -3700,7 +3734,7 @@ snapshots: assertion-error@2.0.1: {} - body-parser@1.20.5: + body-parser@1.20.9: dependencies: bytes: 3.1.2 content-type: 1.0.5 @@ -3733,8 +3767,6 @@ snapshots: chalk@5.6.2: {} - commander@14.0.3: {} - commander@15.0.0: {} content-disposition@0.5.4: @@ -3779,34 +3811,34 @@ snapshots: dependencies: es-errors: 1.3.0 - esbuild@0.27.7: + esbuild@0.28.2: 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/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 escape-html@1.0.3: {} @@ -3826,7 +3858,7 @@ snapshots: dependencies: accepts: 1.3.8 array-flatten: 1.1.1 - body-parser: 1.20.5 + body-parser: 1.20.9 content-disposition: 0.5.4 content-type: 1.0.5 cookie: 0.7.2 @@ -3860,11 +3892,11 @@ snapshots: fast-deep-equal@3.1.3: {} - fast-uri@4.1.5: {} + fast-uri@4.2.3: {} - fdir@6.5.0(picomatch@4.0.4): + fdir@6.5.0(picomatch@4.0.7): optionalDependencies: - picomatch: 4.0.4 + picomatch: 4.0.7 finalhandler@1.3.2: dependencies: @@ -3905,10 +3937,6 @@ snapshots: dunder-proto: 1.0.1 es-object-atoms: 1.1.2 - get-tsconfig@4.14.0: - dependencies: - resolve-pkg-maps: 1.0.0 - gopd@1.2.0: {} has-symbols@1.1.0: {} @@ -3939,54 +3967,54 @@ snapshots: json-schema-traverse@1.0.0: {} - lightningcss-android-arm64@1.32.0: + lightningcss-android-arm64@1.33.0: optional: true - lightningcss-darwin-arm64@1.32.0: + lightningcss-darwin-arm64@1.33.0: optional: true - lightningcss-darwin-x64@1.32.0: + lightningcss-darwin-x64@1.33.0: optional: true - lightningcss-freebsd-x64@1.32.0: + lightningcss-freebsd-x64@1.33.0: optional: true - lightningcss-linux-arm-gnueabihf@1.32.0: + lightningcss-linux-arm-gnueabihf@1.33.0: optional: true - lightningcss-linux-arm64-gnu@1.32.0: + lightningcss-linux-arm64-gnu@1.33.0: optional: true - lightningcss-linux-arm64-musl@1.32.0: + lightningcss-linux-arm64-musl@1.33.0: optional: true - lightningcss-linux-x64-gnu@1.32.0: + lightningcss-linux-x64-gnu@1.33.0: optional: true - lightningcss-linux-x64-musl@1.32.0: + lightningcss-linux-x64-musl@1.33.0: optional: true - lightningcss-win32-arm64-msvc@1.32.0: + lightningcss-win32-arm64-msvc@1.33.0: optional: true - lightningcss-win32-x64-msvc@1.32.0: + lightningcss-win32-x64-msvc@1.33.0: optional: true - lightningcss@1.32.0: + lightningcss@1.33.0: dependencies: detect-libc: 2.1.2 optionalDependencies: - lightningcss-android-arm64: 1.32.0 - lightningcss-darwin-arm64: 1.32.0 - lightningcss-darwin-x64: 1.32.0 - lightningcss-freebsd-x64: 1.32.0 - lightningcss-linux-arm-gnueabihf: 1.32.0 - lightningcss-linux-arm64-gnu: 1.32.0 - lightningcss-linux-arm64-musl: 1.32.0 - lightningcss-linux-x64-gnu: 1.32.0 - lightningcss-linux-x64-musl: 1.32.0 - lightningcss-win32-arm64-msvc: 1.32.0 - lightningcss-win32-x64-msvc: 1.32.0 + lightningcss-android-arm64: 1.33.0 + lightningcss-darwin-arm64: 1.33.0 + lightningcss-darwin-x64: 1.33.0 + lightningcss-freebsd-x64: 1.33.0 + lightningcss-linux-arm-gnueabihf: 1.33.0 + lightningcss-linux-arm64-gnu: 1.33.0 + lightningcss-linux-arm64-musl: 1.33.0 + lightningcss-linux-x64-gnu: 1.33.0 + lightningcss-linux-x64-musl: 1.33.0 + lightningcss-win32-arm64-msvc: 1.33.0 + lightningcss-win32-x64-msvc: 1.33.0 magic-string@0.30.21: dependencies: @@ -4008,14 +4036,14 @@ snapshots: mime@1.6.0: {} - mppx@0.8.19(express@4.22.2)(typescript@5.9.3)(viem@2.57.2(typescript@5.9.3)(zod@4.4.3)): + mppx@0.8.19(express@4.22.2)(typescript@5.9.3)(viem@2.57.2(typescript@5.9.3)(zod@4.6.7)): dependencies: '@stripe/stripe-js': 9.13.0 eventsource-parser: 3.1.1 - ox: 0.14.33(typescript@5.9.3)(zod@4.4.3) + ox: 0.14.33(typescript@5.9.3)(zod@4.6.7) structured-headers: 2.0.3 - viem: 2.57.2(typescript@5.9.3)(zod@4.4.3) - zod: 4.4.3 + viem: 2.57.2(typescript@5.9.3)(zod@4.6.7) + zod: 4.6.7 optionalDependencies: express: 4.22.2 transitivePeerDependencies: @@ -4037,7 +4065,7 @@ snapshots: dependencies: ee-first: 1.1.1 - ox@0.14.33(typescript@5.9.3)(zod@4.4.3): + ox@0.14.33(typescript@5.9.3)(zod@4.6.7): dependencies: '@adraffy/ens-normalize': 1.11.1 '@noble/ciphers': 1.3.0 @@ -4045,14 +4073,14 @@ snapshots: '@noble/hashes': 1.8.0 '@scure/bip32': 1.7.0 '@scure/bip39': 1.6.0 - abitype: 1.2.4(typescript@5.9.3)(zod@4.4.3) + abitype: 1.2.4(typescript@5.9.3)(zod@4.6.7) eventemitter3: 5.0.1 optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: - zod - ox@0.14.45(typescript@5.9.3)(zod@4.4.3): + ox@0.14.45(typescript@5.9.3)(zod@4.6.7): dependencies: '@adraffy/ens-normalize': 1.11.1 '@noble/ciphers': 1.3.0 @@ -4060,7 +4088,7 @@ snapshots: '@noble/hashes': 1.8.0 '@scure/bip32': 1.7.0 '@scure/bip39': 1.6.0 - abitype: 1.2.4(typescript@5.9.3)(zod@4.4.3) + abitype: 1.2.4(typescript@5.9.3)(zod@4.6.7) eventemitter3: 5.0.1 optionalDependencies: typescript: 5.9.3 @@ -4077,6 +4105,8 @@ snapshots: picomatch@4.0.4: {} + picomatch@4.0.7: {} + postcss@8.5.23: dependencies: nanoid: 3.3.19 @@ -4104,28 +4134,26 @@ snapshots: require-from-string@2.0.2: {} - resolve-pkg-maps@1.0.0: {} - - rolldown@1.0.3: + rolldown@1.2.15: dependencies: - '@oxc-project/types': 0.133.0 + '@oxc-project/types': 0.155.0 '@rolldown/pluginutils': 1.0.1 optionalDependencies: - '@rolldown/binding-android-arm64': 1.0.3 - '@rolldown/binding-darwin-arm64': 1.0.3 - '@rolldown/binding-darwin-x64': 1.0.3 - '@rolldown/binding-freebsd-x64': 1.0.3 - '@rolldown/binding-linux-arm-gnueabihf': 1.0.3 - '@rolldown/binding-linux-arm64-gnu': 1.0.3 - '@rolldown/binding-linux-arm64-musl': 1.0.3 - '@rolldown/binding-linux-ppc64-gnu': 1.0.3 - '@rolldown/binding-linux-s390x-gnu': 1.0.3 - '@rolldown/binding-linux-x64-gnu': 1.0.3 - '@rolldown/binding-linux-x64-musl': 1.0.3 - '@rolldown/binding-openharmony-arm64': 1.0.3 - '@rolldown/binding-wasm32-wasi': 1.0.3 - '@rolldown/binding-win32-arm64-msvc': 1.0.3 - '@rolldown/binding-win32-x64-msvc': 1.0.3 + '@rolldown/binding-android-arm-eabi': 1.2.15 + '@rolldown/binding-android-arm64': 1.2.15 + '@rolldown/binding-darwin-arm64': 1.2.15 + '@rolldown/binding-darwin-x64': 1.2.15 + '@rolldown/binding-freebsd-x64': 1.2.15 + '@rolldown/binding-linux-arm-gnueabihf': 1.2.15 + '@rolldown/binding-linux-arm64-gnu': 1.2.15 + '@rolldown/binding-linux-arm64-musl': 1.2.15 + '@rolldown/binding-linux-ppc64-gnu': 1.2.15 + '@rolldown/binding-linux-s390x-gnu': 1.2.15 + '@rolldown/binding-linux-x64-gnu': 1.2.15 + '@rolldown/binding-linux-x64-musl': 1.2.15 + '@rolldown/binding-openharmony-arm64': 1.2.15 + '@rolldown/binding-win32-arm64-msvc': 1.2.15 + '@rolldown/binding-win32-x64-msvc': 1.2.15 safe-buffer@5.2.1: {} @@ -4206,27 +4234,18 @@ snapshots: tinyexec@1.1.1: {} - tinyglobby@0.2.16: - dependencies: - fdir: 6.5.0(picomatch@4.0.4) - picomatch: 4.0.4 - tinyglobby@0.2.17: dependencies: - fdir: 6.5.0(picomatch@4.0.4) - picomatch: 4.0.4 + fdir: 6.5.0(picomatch@4.0.7) + picomatch: 4.0.7 tinyrainbow@3.1.0: {} toidentifier@1.0.1: {} - tslib@2.8.1: - optional: true - - tsx@4.21.0: + tsx@4.23.15: dependencies: - esbuild: 0.27.7 - get-tsconfig: 4.14.0 + esbuild: 0.28.2 optionalDependencies: fsevents: 2.3.3 @@ -4239,7 +4258,7 @@ snapshots: undici-types@7.19.2: {} - undici-types@8.1.0: {} + undici-types@8.12.3: {} unpipe@1.0.0: {} @@ -4247,15 +4266,15 @@ snapshots: vary@1.1.2: {} - viem@2.57.2(typescript@5.9.3)(zod@4.4.3): + viem@2.57.2(typescript@5.9.3)(zod@4.6.7): dependencies: '@noble/curves': 1.9.1 '@noble/hashes': 1.8.0 '@scure/bip32': 1.7.0 '@scure/bip39': 1.6.0 - abitype: 1.2.3(typescript@5.9.3)(zod@4.4.3) + abitype: 1.2.3(typescript@5.9.3)(zod@4.6.7) isows: 1.0.7(ws@8.21.0) - ox: 0.14.45(typescript@5.9.3)(zod@4.4.3) + ox: 0.14.45(typescript@5.9.3)(zod@4.6.7) ws: 8.21.0 optionalDependencies: typescript: 5.9.3 @@ -4264,29 +4283,29 @@ snapshots: - utf-8-validate - zod - vite@8.0.16(@types/node@25.6.0)(esbuild@0.27.7)(tsx@4.21.0)(yaml@2.8.3): + vite@8.3.5(@types/node@25.6.0)(esbuild@0.28.2)(tsx@4.23.15)(yaml@2.8.3): dependencies: - lightningcss: 1.32.0 - picomatch: 4.0.4 + lightningcss: 1.33.0 + picomatch: 4.0.7 postcss: 8.5.23 - rolldown: 1.0.3 + rolldown: 1.2.15 tinyglobby: 0.2.17 optionalDependencies: '@types/node': 25.6.0 - esbuild: 0.27.7 + esbuild: 0.28.2 fsevents: 2.3.3 - tsx: 4.21.0 + tsx: 4.23.15 yaml: 2.8.3 - vitest@4.1.11(@types/node@25.6.0)(vite@8.0.16(@types/node@25.6.0)(esbuild@0.27.7)(tsx@4.21.0)(yaml@2.8.3)): + vitest@4.1.12(@types/node@25.6.0)(vite@8.3.5(@types/node@25.6.0)(esbuild@0.28.2)(tsx@4.23.15)(yaml@2.8.3)): dependencies: - '@vitest/expect': 4.1.11 - '@vitest/mocker': 4.1.11(vite@8.0.16(@types/node@25.6.0)(esbuild@0.27.7)(tsx@4.21.0)(yaml@2.8.3)) - '@vitest/pretty-format': 4.1.11 - '@vitest/runner': 4.1.11 - '@vitest/snapshot': 4.1.11 - '@vitest/spy': 4.1.11 - '@vitest/utils': 4.1.11 + '@vitest/expect': 4.1.12 + '@vitest/mocker': 4.1.12(vite@8.3.5(@types/node@25.6.0)(esbuild@0.28.2)(tsx@4.23.15)(yaml@2.8.3)) + '@vitest/pretty-format': 4.1.12 + '@vitest/runner': 4.1.12 + '@vitest/snapshot': 4.1.12 + '@vitest/spy': 4.1.12 + '@vitest/utils': 4.1.12 es-module-lexer: 2.1.0 expect-type: 1.3.0 magic-string: 0.30.21 @@ -4296,9 +4315,9 @@ snapshots: std-env: 4.1.0 tinybench: 2.9.0 tinyexec: 1.1.1 - tinyglobby: 0.2.16 + tinyglobby: 0.2.17 tinyrainbow: 3.1.0 - vite: 8.0.16(@types/node@25.6.0)(esbuild@0.27.7)(tsx@4.21.0)(yaml@2.8.3) + vite: 8.3.5(@types/node@25.6.0)(esbuild@0.28.2)(tsx@4.23.15)(yaml@2.8.3) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 25.6.0 @@ -4314,4 +4333,4 @@ snapshots: yaml@2.8.3: {} - zod@4.4.3: {} + zod@4.6.7: {} diff --git a/harness/pnpm-workspace.yaml b/harness/pnpm-workspace.yaml index ff1f4c0b7..78f140f04 100644 --- a/harness/pnpm-workspace.yaml +++ b/harness/pnpm-workspace.yaml @@ -3,7 +3,9 @@ allowBuilds: overrides: '@toon-format/toon': '2.3.1' - fast-uri: '4.1.5' + 'body-parser@1': '1.20.9' + esbuild: '0.28.2' + fast-uri: '4.2.3' hono: '4.13.7' ip-address: '10.7.2' 'nanoid@3.3.11': '3.3.18' @@ -11,5 +13,6 @@ overrides: proxy-addr: '2.0.8' qs: '6.16.0' source-map-js: '1.2.2' - vite: '8.0.16' + vite: '8.3.5' ws: '8.21.0' + zod: '4.6.7' diff --git a/harness/requirements/x402-txv1.toml b/harness/requirements/x402-txv1.toml index e89d26fa4..3627bff41 100644 --- a/harness/requirements/x402-txv1.toml +++ b/harness/requirements/x402-txv1.toml @@ -1,20 +1,21 @@ repo = "x402-txv1" -commit = "3d723dd54706b9edab8a33dc2c4e9cad22f35745" +commit = "f7043a123097e674fca864c39c58adcb0c9c649d" files = [ "specs/schemes/exact/scheme_exact_svm.md", "specs/schemes/upto/scheme_upto_svm.md", "specs/schemes/batch-settlement/scheme_batch_settlement_svm.md", ] -# SVM transaction-version negotiation, pinned from x402-foundation/x402 -# PR 3473 (solana-foundation/x402 spec/svm-transaction-versions) until it -# merges. id = "X402TX-" + sha256(normalised text)[:10]. `required = true`: +# SVM transaction-version negotiation (x402-foundation/x402 PR 3473, merged, +# with the TransactionConfigMask wording from PR 3474), pinned at the +# solana-foundation/x402 branch feat/svm-client-transaction-v1 that carries +# it alongside the client-built version-1 implementation. id = "X402TX-" + sha256(normalised text)[:10]. `required = true`: # `pkc req-lint` fails if no case maps the id. [[requirement]] -id = "X402TX-0f874a9c63" +id = "X402TX-703c03cfb5" doc = "specs/schemes/upto/scheme_upto_svm.md" -text = "In a version-1 transaction the same caps apply to the message TransactionConfig instead: computeUnitLimit MUST be present and MUST NOT exceed 400000, loadedAccountsDataSizeLimit MUST be present, and priorityFee (total lamports) MUST satisfy priorityFee 1000000 <= 5000000 computeUnitLimit." +text = "In a version-1 transaction the same caps apply to the message config values instead (see [Transaction versions](#transaction-versions)): computeUnitLimit (bit 2) MUST be set and MUST NOT exceed 400000, loadedAccountsDataSizeLimit (bit 3) MUST be set, and priorityFee (bits 0 and 1, total lamports) MUST satisfy priorityFee 1000000 <= 5000000 computeUnitLimit, evaluated without overflow." required = true [[requirement]] @@ -48,9 +49,9 @@ text = "The client MUST intersect the advertised versions ([0] when the field is required = true [[requirement]] -id = "X402TX-644919eb3b" +id = "X402TX-f9bcc1a14a" doc = "specs/schemes/exact/scheme_exact_svm.md" -text = "It MUST set computeUnitLimit and loadedAccountsDataSizeLimit (a version-1 transaction that omits either is budgeted zero and cannot execute), it MUST NOT contain Compute Budget program instructions, and its priorityFee is a total in lamports, evaluated against a per-compute-unit cap as priorityFee 1000000 <= maxPriorityFeeMicroLamports computeUnitLimit." +text = "(The cost model still reserves 32 KiB of loaded account data for scheduling, but the transaction's own budget is 0.) A transaction that leaves bit 2 or bit 3 unset therefore cannot execute its instructions, so a client-built version-1 transaction MUST set both." required = true [[requirement]] @@ -60,9 +61,9 @@ text = "They are never advertised in extra.transactionVersions and clients MUST required = true [[requirement]] -id = "X402TX-936b492daa" +id = "X402TX-915632f040" doc = "specs/schemes/exact/scheme_exact_svm.md" -text = "A version-1 transaction that contains a Compute Budget instruction MUST be rejected." +text = "A version-1 transaction that contains a Compute Budget instruction MUST be rejected (an x402 sponsor rule; the runtime treats such instructions as no-ops)." required = true [[requirement]] @@ -102,9 +103,9 @@ text = "The sponsor MUST reject a message whose version is outside the set it ac required = true [[requirement]] -id = "X402TX-2ad7a3f326" +id = "X402TX-655bb4a79a" doc = "specs/schemes/exact/scheme_exact_svm.md" -text = "The legacy/version-0 Compute Budget price and the version-1 total priority fee MUST each be no greater than 5 lamports/CU on this path, using the normalization in §1.5 for version 1." +text = "The legacy/version-0 Compute Budget price and the version-1 total priority fee MUST each be no greater than maxPriorityFeeMicroLamports (default 5 lamports/CU) on this path, using the normalization in §1.5 for version 1." required = true [[requirement]] @@ -126,9 +127,9 @@ text = "The fee payer / sponsor MUST NOT be the authority on any observed transf required = true [[requirement]] -id = "X402TX-d188782061" +id = "X402TX-4c2fd60e66" doc = "specs/schemes/exact/scheme_exact_svm.md" -text = "A version-1 transaction MUST contain 1 to 5 instructions in this order:" +text = "For a single-payee charge, a version-1 transaction MUST contain 1 to 5 instructions in this order:" required = true [[requirement]] @@ -138,9 +139,9 @@ text = "Fee payer isolation (§2.1.1): the fee payer MUST NOT appear in any inst required = true [[requirement]] -id = "X402TX-eb681e1701" +id = "X402TX-997feeb51d" doc = "specs/schemes/exact/scheme_exact_svm.md" -text = "In a version-1 transaction the same caps apply to the message TransactionConfig instead: computeUnitLimit MUST be present and MUST NOT exceed the configured maximum, loadedAccountsDataSizeLimit MUST be present, and priorityFee (total lamports) MUST satisfy priorityFee 1000000 <= maxPriorityFeeMicroLamports computeUnitLimit." +text = "In a version-1 transaction the same caps apply to the message config values instead (§1.5): computeUnitLimit (bit 2) MUST be set and MUST NOT exceed the configured maximum, loadedAccountsDataSizeLimit (bit 3) MUST be set, and priorityFee (bits 0 and 1, total lamports) MUST satisfy priorityFee 1000000 <= capMicroLamports computeUnitLimit, where capMicroLamports is the price cap of the accepting path, evaluated without overflow as specified in §1.5." required = true [[requirement]] @@ -154,3 +155,21 @@ id = "X402TX-f9c2b66234" doc = "specs/schemes/exact/scheme_exact_svm.md" text = "Match exactly one transfer (§1.4): across top-level and inner instructions, exactly one TransferChecked MUST match the required mint, destination ATA (derived for both token programs), and amount (>= required)." required = true + +[[requirement]] +id = "X402TX-4cd70365fd" +doc = "specs/schemes/exact/scheme_exact_svm.md" +text = "As an x402 sponsor rule, a client-built version-1 transaction MUST NOT contain them, and the sponsor MUST reject one that does." +required = true + +[[requirement]] +id = "X402TX-74fb884aa9" +doc = "specs/schemes/exact/scheme_exact_svm.md" +text = "The sponsor MUST evaluate both sides of the inequality with arbitrary-precision integers (or at least 128-bit unsigned integers), so that an oversized priorityFee cannot wrap and pass the check." +required = true + +[[requirement]] +id = "X402TX-927d17b62e" +doc = "specs/schemes/exact/scheme_exact_svm.md" +text = "A client or server MUST treat a field containing any non-integer entry (a string, null, or \"legacy\") or any integer other than 0 or 1 as invalid and fail closed with unsupported_transaction_version." +required = true diff --git a/harness/requirements/x402.toml b/harness/requirements/x402.toml index c21a1e915..a3f7cdf39 100644 --- a/harness/requirements/x402.toml +++ b/harness/requirements/x402.toml @@ -1,5 +1,5 @@ repo = "x402" -commit = "03b3919b3d422d2b094ea3539e0b577558e1ae86" +commit = "f7043a123097e674fca864c39c58adcb0c9c649d" files = [ "specs/x402-specification-v2.md", "specs/schemes/exact/scheme_exact.md", @@ -113,9 +113,9 @@ text = "These are wallet-injected user protection mechanisms and MUST be allowed required = true [[requirement]] -id = "X402-a8bd75d71b" +id = "X402-05c2aacafc" doc = "specs/schemes/exact/scheme_exact_svm.md" -text = "The decompiled transaction MUST contain 3 to 7 instructions in this order:" +text = "For a single-payee charge (no extra.splits and no ATA creation), a legacy or version-0 transaction MUST contain 3 to 7 instructions in this order:" required = true [[requirement]] @@ -289,9 +289,9 @@ text = "The payload.from signature MUST be present and valid before the facilita required = true [[requirement]] -id = "X402-c1174b72d8" +id = "X402-4de59a1f27" doc = "specs/schemes/upto/scheme_upto_svm.md" -text = "The message MAY be legacy or version 0, but it MUST NOT contain Address Lookup Table lookups." +text = "The message version MUST be one advertised in extra.transactionVersions (0 when the field is absent; see [Transaction versions](#transaction-versions)), and the message MUST NOT contain Address Lookup Table lookups." required = true [[requirement]] @@ -586,6 +586,18 @@ doc = "specs/schemes/batch-settlement/scheme_batch_settlement_svm.md" text = "| authorization | BatchAuthorization | REQUIRED in server mode and absent in client mode." required = true +[[requirement]] +id = "X402-0ff4cabcb4" +doc = "specs/schemes/batch-settlement/scheme_batch_settlement_svm.md" +text = "It MUST confirm the payer has sufficient tokens for the deposit and the sponsor has sufficient SOL for the transaction fee plus the channel PDA and escrow ATA rent." +required = true + +[[requirement]] +id = "X402-014270dc81" +doc = "specs/schemes/batch-settlement/scheme_batch_settlement_svm.md" +text = "It MUST confirm the payer has sufficient tokens." +required = true + [[requirement]] id = "X402-4cedb5114b" doc = "specs/schemes/batch-settlement/scheme_batch_settlement_svm.md" @@ -659,9 +671,21 @@ text = "MUST be an integer from 900 through 2592000 (15 minutes through 30 days) required = true [[requirement]] -id = "X402-7f4ee54a73" +id = "X402-76654742e7" +doc = "specs/schemes/batch-settlement/scheme_batch_settlement_svm.md" +text = "claims[] MUST contain at least one entry and at most extra.maxClaimChannels entries, or four when the facilitator advertises no maxClaimChannels, so the instruction pairs fit in one transaction without address lookup tables." +required = true + +[[requirement]] +id = "X402-c2ca42b7a4" +doc = "specs/schemes/batch-settlement/scheme_batch_settlement_svm.md" +text = "channels[] MUST contain at least one entry and at most extra.maxSettleChannels entries, or four when the facilitator advertises no maxSettleChannels." +required = true + +[[requirement]] +id = "X402-8f57677e36" doc = "specs/schemes/batch-settlement/scheme_batch_settlement_svm.md" -text = "claims[] MUST contain between one and four entries so the instruction pairs fit in a legacy Solana transaction without address lookup tables." +text = "The server MUST copy feePayer, transactionVersions, maxClaimChannels, maxSettleChannels, and maxIdleSecs into PaymentRequirements.extra, MUST NOT author a claim or settle request with more entries than the copied capacity (four when absent), then set extra.tokenProgram from the selected asset's verified mint owner." required = true [[requirement]] diff --git a/harness/src/conformance/contract-schema.ts b/harness/src/conformance/contract-schema.ts index b98f512a4..2117eaa3a 100644 --- a/harness/src/conformance/contract-schema.ts +++ b/harness/src/conformance/contract-schema.ts @@ -129,6 +129,19 @@ export const conformanceVectorSchema = { properties: { outcome: { enum: ["accept", "reject"] }, rejectCode: rejectCodeSchema, + alsoConformant: { + type: "array", + minItems: 1, + items: { + type: "object", + required: ["outcome"], + properties: { + outcome: { enum: ["accept", "reject"] }, + rejectCode: rejectCodeSchema, + }, + }, + }, + alsoConformantReason: { type: "string", minLength: 1 }, }, }, }, diff --git a/harness/src/conformance/intents/subscription.ts b/harness/src/conformance/intents/subscription.ts index 9462d2294..6d34ab30f 100644 --- a/harness/src/conformance/intents/subscription.ts +++ b/harness/src/conformance/intents/subscription.ts @@ -90,10 +90,10 @@ async function canonical(vector: ConformanceVector): Promise { if (input.subscriptionPeriod) { const { periodUnit, periodCount } = input.subscriptionPeriod; try { - // The SDK's own client reads periodCount with Number() before mapping. + // The wire string, as the SDK's client and server pass it. const periodHours = mapSubscriptionPeriodToHours( periodUnit as "day" | "week", - Number(periodCount), + periodCount, ); return exactJson(vector.id, { periodHours }); } catch (error) { diff --git a/harness/src/conformance/intents/x402-batch-settlement.ts b/harness/src/conformance/intents/x402-batch-settlement.ts index 1a4d5bfaf..158806618 100644 --- a/harness/src/conformance/intents/x402-batch-settlement.ts +++ b/harness/src/conformance/intents/x402-batch-settlement.ts @@ -177,7 +177,29 @@ async function verify( "@x402/svm adopts a corrective 402 only inside its client channel flow, with no single-shot entry point", ); } + // The testee drives the stateless upstream facilitator: it never sees the + // resource server's store record, so a vector whose verdict rests on that + // record alone (RULINGS B1) cannot be expressed. + if (input.batchVerdictFromStore === true) { + return unsupported( + vector, + "the testee drives the stateless upstream facilitator, which never sees the resource server's store record (chargedCumulativeAmount, the accepted cumulative, a close-pending mark) this verdict rests on (RULINGS B1)", + ); + } const server = input.batchServer as Json; + // The upstream facilitator accepts legacy, version 0 and version 1 with + // no option to narrow the set ("The facilitator enforces its own accepted + // set"). + const versions = server.transactionVersions as Array<0 | 1> | undefined; + if ( + versions !== undefined && + !(new Set(versions).size === 2 && versions.includes(0) && versions.includes(1)) + ) { + return unsupported( + vector, + "the upstream batch facilitator's accepted transaction-version set is fixed (legacy, 0 and 1) with no option to narrow it (batchServer.transactionVersions other than absent or [0, 1])", + ); + } const requirements = input.batchRequirements as PaymentRequirements; const feePayer = await createKeyPairSignerFromBytes( new Uint8Array(server.feePayerSecretKey as number[]), @@ -190,7 +212,7 @@ async function verify( }; const facilitator = new x402Facilitator().register( requirements.network as Network, - new BatchFacilitator(signer, { rpcUrl: rpcUrl(input) }), + new BatchFacilitator(signer), ); let payload: PaymentPayload; try { @@ -233,12 +255,19 @@ async function build( const signer = await createKeyPairSignerFromBytes( new Uint8Array(c.secretKey as number[]), ); + // The highest version the client's signer signs, through the upstream + // client's own option, as @solana/pay-kit maps its maxTransactionVersion + // (typescript/packages/pay-kit/src/client/index.ts). + const maxVersion = c.maxTransactionVersion as 0 | 1 | undefined; const client = new x402Client().register( requirements.network as Network, new BatchClient(signer, { depositAmount: String(c.depositAmount), discoverChannels: false, rpcUrl: rpcUrl(input), + ...(maxVersion !== undefined + ? { transactionVersions: maxVersion === 0 ? [0] : [0, 1] } + : {}), }), ); try { diff --git a/harness/src/conformance/intents/x402-upto.ts b/harness/src/conformance/intents/x402-upto.ts index f30b802e2..4d691a4a1 100644 --- a/harness/src/conformance/intents/x402-upto.ts +++ b/harness/src/conformance/intents/x402-upto.ts @@ -112,6 +112,18 @@ function codeFor(reason: string, message: string): RejectCode | undefined { } if (/unsupported_transaction_version|transaction version/.test(m)) return "unsupported-version"; + // Version-1 header budget (x402-txv1 §1.5) and per-version size limit: + // `transaction v1 config rejected ()` and `above the N-byte + // limit for version V`. A ComputeBudget instruction beside the open is an + // instruction outside the open (the Rust verifier's category for upto); + // an unset or malformed header field and an oversize message are + // malformed payloads (RULINGS T4). + const v1 = /v1 config rejected \(([a-z_]+)\)/.exec(m)?.[1]; + if (v1 === "compute_budget_instruction") return "unexpected-instruction"; + if (v1 === "compute_unit_limit_too_high") return "compute-limit-over-cap"; + if (v1 === "priority_fee_too_high") return "compute-price-over-cap"; + if (v1 !== undefined) return "invalid-payload"; + if (/byte limit for version/.test(m)) return "invalid-payload"; if (/setcomputeunitprice .* exceeds/.test(m)) return "compute-price-over-cap"; if (/setcomputeunitlimit .* exceeds/.test(m)) return "compute-limit-over-cap"; if ( @@ -182,6 +194,7 @@ async function build(vector: ConformanceVector): Promise { // Permissions are the client's spending policy, not wire behaviour. const client = await createPayKitClient({ accept: ["x402"], + maxTransactionVersion: input.x402ClientMaxTransactionVersion as 0 | 1 | undefined, permissions: false, rpcUrl: rpcUrlOf(vector), signer, @@ -213,8 +226,27 @@ async function build(vector: ConformanceVector): Promise { } } +// The vendored upto facilitator accepts legacy, version 0 and version 1 with +// no option to narrow the set, so a sponsor configured with another set +// (input.x402ServerTransactionVersions other than absent or [0, 1]) cannot +// be expressed (scheme_upto_svm.md: "The facilitator enforces its own +// accepted set"). +function sponsorVersionsExpressible(versions: Array<0 | 1> | undefined): boolean { + if (versions === undefined) return true; + const set = new Set(versions); + return set.size === 2 && set.has(0) && set.has(1); +} + async function verify(vector: ConformanceVector): Promise { const input = vector.input; + if (!sponsorVersionsExpressible(input.x402ServerTransactionVersions)) { + return { + error: + "unsupported-mode: the vendored @x402/svm upto facilitator's accepted transaction-version set is fixed (legacy, 0 and 1) with no option to narrow it (input.x402ServerTransactionVersions other than absent or [0, 1])", + id: vector.id, + outcome: "unsupported-mode", + }; + } if (!input.x402PaymentHeader) throw new Error( "invalid payload: upto verify vector missing x402PaymentHeader", diff --git a/harness/src/conformance/reject.ts b/harness/src/conformance/reject.ts index f40fdcc0b..d871db7d5 100644 --- a/harness/src/conformance/reject.ts +++ b/harness/src/conformance/reject.ts @@ -37,6 +37,14 @@ const PATTERNS: Array<[RegExp, RejectCode]> = [ [/invalid_batch_settlement_svm_channel_state/, "channel-state"], [/invalid_batch_settlement_svm_refund_transaction/, "refund-transaction"], [/\bduplicate_settlement\b/, "duplicate-settlement"], + // The bare x402 reason (not `invalid_exact_svm_network_mismatch`): the + // facilitator compares `paymentPayload.accepted.network` with the + // requirements' network, so it names an accepted that differs from the + // requirements (RULINGS B3), not a transaction for another cluster. + [/\bnetwork_mismatch\b/, "accepted-mismatch"], + // The batch facilitator's /verify envelope check: paymentPayload.accepted + // differs from paymentRequirements (spec 4.5), named with core's code. + [/\binvalid_payment_requirements\b/, "accepted-mismatch"], [/\bunsupported_scheme\b/, "unsupported-scheme"], // @x402/svm batch-settlement client: refusals of a challenge's terms // (plain Errors, no reason code). @@ -87,7 +95,7 @@ const PATTERNS: Array<[RegExp, RejectCode]> = [ ], // Client refusing a challenge that violates the method spec (RULINGS C2, // C3). Checked first: these messages also contain generic words. - [/decimals is required|failed to determine token program/i, "invalid-challenge"], + [/decimals is required|failed to determine token program|tokenprogram must not be present/i, "invalid-challenge"], // @solana/pay-kit's client refusing an offer's terms (an unknown network). [/invalid_challenge_terms|unsupported solana network/i, "invalid-challenge"], // Sponsors bound the priority fee as limit x price (RULINGS S6). @@ -114,6 +122,8 @@ const PATTERNS: Array<[RegExp, RejectCode]> = [ [/network mismatch/i, "wrong-network"], // @x402/svm exact verifier reason codes. [/invalid_exact_svm_network_mismatch/i, "wrong-network"], + [/compute_price_instruction_too_high/i, "compute-price-over-cap"], + [/compute_limit_instruction_too_high/i, "compute-limit-over-cap"], [/invalid_exact_svm_payload_amount_mismatch/i, "amount-mismatch"], [ /invalid_exact_svm_payload_(mint_mismatch|recipient_mismatch|no_transfer_instruction)/i, diff --git a/harness/src/conformance/schema.ts b/harness/src/conformance/schema.ts index 35476588a..be5adb889 100644 --- a/harness/src/conformance/schema.ts +++ b/harness/src/conformance/schema.ts @@ -192,6 +192,14 @@ export type VectorExpect = { // Optional human-readable reason for reject vectors; not asserted, just // documents the divergence class. rejectReason?: string; + // Other verdicts the pinned specs allow where they leave the choice to the + // implementation (a sponsor's stricter local policy, an unordered pair of + // checks, a rule stated for another instruction). The judge passes a + // result matching the primary verdict or any of these (outcome and, for a + // reject, its code); an accepted build is still judged on its artifact. + alsoConformant?: Array<{ outcome: VectorOutcome; rejectCode?: RejectCode }>; + // Why the alternatives conform, quoting the spec. + alsoConformantReason?: string; // Normalized reject category asserted across every SDK. Pins WHY the SDK // rejected, not just that it did, so a guard that fires for the wrong // reason (e.g. a decimals-mismatch caught only by a generic @@ -564,10 +572,14 @@ export type VectorInput = { // `methodDetails.transactionVersions` (`[0]` when absent); charge verify // runners configure the server from it. signerMaxTransactionVersion?: 0 | 1; - // verify-transaction (x402): the sponsor's own accepted message versions - // (scheme_exact_svm §1.5: "The sponsor enforces its own accepted set"; - // absent means [0]). The route advertises them as - // `extra.transactionVersions` and the vector's `accepted` echoes them. + // verify-transaction (x402 exact and upto): the sponsor's own accepted + // message versions (scheme_exact_svm §1.5: "The sponsor enforces its own + // accepted set"). The spec gives that set no default, so every vector + // whose verdict depends on it states it; absent, the Rust reference + // sponsor accepts [0]. The route advertises them as + // `extra.transactionVersions` (nothing for [0]) and the vector's + // `accepted` echoes them. A testee whose SDK cannot configure the set + // reports unsupported-mode for a value it cannot express. x402ServerTransactionVersions?: Array<0 | 1>; // canonical-bytes (charge): an MPP charge request round-trip. The runner // DECODES `value` with the production SDK charge-request type (incl. @@ -665,13 +677,15 @@ export type VectorInput = { }; sessionServerFeePayerSecretKey?: number[]; // build-transaction (session): the client's `open` for `request` (the - // challenge's SessionRequest) with the channel `salt` its builder takes; - // `signerSecretKey` is the payer, `sessionSignerSecretKey` the voucher key - // it authorizes. `server` / `challenge` are for the judge only. An - // accepted build returns the open action as `sessionCredential`. + // challenge's SessionRequest) with the channel `salt` its builder takes + // and the `deposit` its caller authorizes; `signerSecretKey` is the payer, + // `sessionSignerSecretKey` the voucher key it authorizes. `server` / + // `challenge` are for the judge only. An accepted build returns the open + // action as `sessionCredential`. sessionOpenBuild?: { request: Record; salt: string; + deposit: string; server: Record; challenge: { id: string; recentBlockhash: string; recentSlot: string }; }; diff --git a/harness/src/conformance/ts-runner.ts b/harness/src/conformance/ts-runner.ts index 29c9eb26e..fe6b2d032 100644 --- a/harness/src/conformance/ts-runner.ts +++ b/harness/src/conformance/ts-runner.ts @@ -189,9 +189,6 @@ async function buildX402Vector(vector: ConformanceVector): Promise outcome: "unsupported-mode", }; } - if (input.signerMaxTransactionVersion !== undefined) { - return { error: SIGNER_VERSION_UNSUPPORTED, id: vector.id, outcome: "unsupported-mode" }; - } const signer = await createKeyPairSignerFromBytes(new Uint8Array(input.signerSecretKey)); let captured: string | undefined; const server = createServer((req, res) => { @@ -213,6 +210,7 @@ async function buildX402Vector(vector: ConformanceVector): Promise // vector judges the payment the SDK builds, so allow every payment. const client = await createPayKitClient({ accept: ["x402"], + maxTransactionVersion: input.signerMaxTransactionVersion, permissions: false, rpcUrl: rpcUrlOf(vector), signer, @@ -248,12 +246,18 @@ type X402VerifyInput = ConformanceVector["input"]; // Transaction-version knobs the TypeScript SDKs do not expose. The runner // cannot express them, so it reports unsupported-mode instead of guessing. const SIGNER_VERSION_UNSUPPORTED = - "unsupported-mode: neither @solana/mpp buildChargeTransaction nor the @solana/pay-kit x402 client takes a highest signable transaction version (input.signerMaxTransactionVersion)"; + "unsupported-mode: @solana/mpp buildChargeTransaction takes no highest signable transaction version (input.signerMaxTransactionVersion)"; const SPONSOR_VERSIONS_UNSUPPORTED = - "unsupported-mode: the vendored @x402/svm exact facilitator (x402 @03b3919b, before x402-foundation/x402 PR 3474) has no accepted transaction-version set to configure (input.x402ServerTransactionVersions other than [0])"; + "unsupported-mode: the @x402/svm exact facilitator's accepted transaction-version set is fixed at [0, 1] (legacy tolerated), with no option to narrow it (input.x402ServerTransactionVersions other than absent or [0, 1])"; function sponsorVersionsExpressible(versions: ConformanceVector["input"]["x402ServerTransactionVersions"]): boolean { - return versions === undefined || (versions.length === 1 && versions[0] === 0); + // Absent: the vector's verdict does not depend on the sponsor's own set + // (the spec gives it no default, so every vector that depends on it states + // it), and the facilitator's fixed [0, 1] serves. + if (versions === undefined) return true; + // A repeated entry names the same version (RULINGS T1): compare as sets. + const set = new Set(versions); + return set.size === 2 && set.has(0) && set.has(1); } async function verifyX402Vector(vector: ConformanceVector): Promise { diff --git a/harness/src/expectations.ts b/harness/src/expectations.ts index 706d50177..6acabbee0 100644 --- a/harness/src/expectations.ts +++ b/harness/src/expectations.ts @@ -51,6 +51,7 @@ export const INTEROP_CLAIMS: readonly string[] = [ "mpp:charge", "x402:exact", "x402:upto", + "x402:batch-settlement", "mpp:session", ].flatMap((intent) => [`${intent}:client`, `${intent}:server`]); diff --git a/harness/src/fixtures/typescript/charge-client.ts b/harness/src/fixtures/typescript/charge-client.ts index f5ecc9a42..8999ee880 100644 --- a/harness/src/fixtures/typescript/charge-client.ts +++ b/harness/src/fixtures/typescript/charge-client.ts @@ -107,6 +107,14 @@ async function payTarget( // the choice via MPP_HARNESS_PAYMENT_MODE so a single client // adapter covers both wire modes. broadcast: environment.paymentMode === "push", + // Like the Rust client fixture: refuse a challenge for another + // cluster or above the amount the scenario agreed to pay. + ...(process.env.MPP_HARNESS_NETWORK + ? { expectedNetwork: process.env.MPP_HARNESS_NETWORK } + : {}), + ...(process.env.MPP_HARNESS_AMOUNT + ? { maxAmount: BigInt(process.env.MPP_HARNESS_AMOUNT) } + : {}), signer, rpcUrl: environment.rpcUrl, ...(environment.computeUnitLimit !== undefined diff --git a/harness/src/fixtures/typescript/upto-server.ts b/harness/src/fixtures/typescript/upto-server.ts new file mode 100644 index 000000000..0619c675b --- /dev/null +++ b/harness/src/fixtures/typescript/upto-server.ts @@ -0,0 +1,141 @@ +// ts-x402 upto server adapter: a @solana/pay-kit `usage` (x402 `upto`) gate. +// +// Env in (X402_HARNESS_*, same as the Rust upto adapter +// rust/crates/harness-bins/src/bin/x402_harness_upto_server.rs), JSON out: +// prints one `ready` line with the bound port, then serves +// GET X402_HARNESS_RESOURCE_PATH authorizes up to X402_HARNESS_PRICE and +// settles X402_HARNESS_ACTUAL_AMOUNT +// GET /health +// The route is `pay.fetch(gate, handler)` on a `usage` gate: pay-kit issues +// the 402, verifies and broadcasts the client's channel `open` with the +// vendored @x402/svm upto facilitator (its open + settle + distribute +// readiness simulation included), then settles the metered amount with +// settle_and_seal and distribute. The operator (X402_HARNESS_FEE_PAYER_SECRET_KEY) +// is fee payer, rent payer, receiver authorizer and recipient. The handler +// only reports the metered amount through the SDK's `charge` meter; the +// adapter translates node:http to fetch and exposes the settlement signature +// pay-kit recorded on the scenario's settlement header. + +import http from "node:http"; +import type { AddressInfo } from "node:net"; +import { createPayKit, Signer, usage, usd } from "@solana/pay-kit"; +import { readX402ServerEnvironment } from "./exact-shared"; + +const MAINNET_PATCHED_TREASURY_OWNER = "Cs2zdfUNonRdRGsiZUQQLdTxzxVvJZmgiX2mpLYKuEqP"; + +function readRequiredEnv(name: string): string { + const value = process.env[name]; + if (!value || value.trim() === "") throw new Error(`${name} is required`); + return value; +} + +function toRequest(req: http.IncomingMessage, origin: string): Request { + const headers = new Headers(); + for (const [name, value] of Object.entries(req.headers)) { + if (value === undefined) continue; + headers.set(name, Array.isArray(value) ? value.join(", ") : value); + } + return new Request(new URL(req.url ?? "/", origin), { headers, method: req.method ?? "GET" }); +} + +async function writeResponse( + res: http.ServerResponse, + response: Response, + extraHeaders: Record, +): Promise { + const body = await response.text(); + const headers: Record = {}; + response.headers.forEach((value, name) => { + if (name !== "content-length") headers[name] = value; + }); + res.writeHead(response.status, { ...headers, ...extraHeaders }); + res.end(body); +} + +async function main(): Promise { + const env = readX402ServerEnvironment(); + const operator = await Signer.bytes( + new Uint8Array(JSON.parse(readRequiredEnv("X402_HARNESS_FEE_PAYER_SECRET_KEY")) as number[]), + ); + const actualAmount = BigInt(process.env.X402_HARNESS_ACTUAL_AMOUNT ?? "0"); + const pay = await createPayKit({ + accept: ["x402"], + network: env.network, + operator: { recipient: env.payTo, signer: operator }, + pricing: { usage: usage(usd(env.price, "USDC")) }, + rpcUrl: env.rpcUrl, + // The local validator's payment-channels build has its treasury-owner + // sentinel patched to the *mainnet* constant + // (.github/actions/build-payment-channels) while the scenario labels the + // network devnet, so name that treasury instead of devnet's. + x402: { paymentChannelsTreasuryOwner: MAINNET_PATCHED_TREASURY_OWNER }, + }); + + const route = pay.fetch("usage", (request) => { + pay.charge(request)?.charge(actualAmount); + return Response.json({ ok: true, paid: true }); + }); + + const server = http.createServer((req, res) => { + const url = new URL(req.url ?? "/", "http://127.0.0.1"); + if (url.pathname === "/health") { + res.writeHead(200, { "content-type": "application/json" }); + res.end(JSON.stringify({ ok: true })); + return; + } + if (url.pathname !== env.resourcePath) { + res.writeHead(404, { "content-type": "application/json" }); + res.end(JSON.stringify({ error: "not_found" })); + return; + } + const request = toRequest(req, `http://${req.headers.host ?? "127.0.0.1"}`); + route(request) + .then((response) => { + // pay-kit records the settlement transaction on the request's payment. + const transaction = pay.payment(request)?.transaction; + return writeResponse( + res, + response, + response.status === 200 && transaction ? { [env.settlementHeader]: transaction } : {}, + ); + }) + .catch((error: unknown) => { + console.error("ts-x402 upto server error:", error); + res.writeHead(500, { "content-type": "application/json" }); + res.end(JSON.stringify({ error: error instanceof Error ? error.message : String(error) })); + }); + }); + + await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve)); + const { port } = server.address() as AddressInfo; + + // Refuse to serve a payment the scenario did not ask for (see exact-server.ts). + const challenge = await route(new Request(`http://127.0.0.1:${port}${env.resourcePath}`)); + const offered = (await challenge.json()) as { accepts?: { amount?: string; asset?: string }[] }; + const offer = offered.accepts?.[0]; + if (offer?.asset !== env.mint || (env.amount !== undefined && offer.amount !== env.amount)) { + throw new Error( + `pay-kit prices ${env.price} USD on ${env.network} as ${offer?.amount} of ${offer?.asset}; ` + + `the scenario expects ${env.amount ?? "(any)"} of ${env.mint}`, + ); + } + + console.log( + JSON.stringify({ + type: "ready", + implementation: "typescript", + role: "server", + port, + capabilities: ["upto"], + }), + ); + + const shutdown = () => server.close(() => process.exit(0)); + process.on("SIGTERM", shutdown); + process.on("SIGINT", shutdown); +} + +main().catch((error: unknown) => { + console.error(error); + process.exit(1); +}); diff --git a/harness/test/flow-conformance.test.ts b/harness/test/flow-conformance.test.ts index 37f0e653c..259efee73 100644 --- a/harness/test/flow-conformance.test.ts +++ b/harness/test/flow-conformance.test.ts @@ -17,7 +17,7 @@ // harness/expectations/typescript.toml. import { spawn, type ChildProcess } from "node:child_process"; -import { createServer } from "node:net"; +import { createServer, type Server } from "node:net"; import { dirname, join } from "node:path"; import { fileURLToPath } from "node:url"; import { afterAll, beforeAll, describe, expect, it } from "vitest"; @@ -50,22 +50,46 @@ const flowRefs: CaseRef[] = flowCases.map((c) => ({ suite: "flow", id: c.name, c // that claims `flow` without an adapter here is a configuration error. const FLOW_ADAPTERS = { typescript: typescriptProtocolAdapter } as const; -async function getFreePort(): Promise { - return await new Promise((resolve, reject) => { +function listen(port: number): Promise { + return new Promise((resolve) => { const probe = createServer(); - probe.once("error", reject); - probe.listen(0, "127.0.0.1", () => { - const address = probe.address(); - if (address === null || typeof address === "string") { - probe.close(() => reject(new Error("could not determine a free port"))); - return; - } - const { port } = address; - probe.close(() => resolve(port)); - }); + probe.once("error", () => resolve(undefined)); + // No host: the compliance server binds the unspecified address, so probe + // the same one. + try { + probe.listen(port, () => resolve(probe)); + } catch { + // An out-of-range port throws synchronously instead of emitting "error". + resolve(undefined); + } }); } +function close(probe: Server): Promise { + return new Promise((resolve) => probe.close(() => resolve())); +} + +// The compliance server listens on `port` and on `port + 1` (the redirect +// origin, `redirect_to_port_offset` in the flow cases), so both must be free. +async function getFreePortPair(attempts = 20): Promise { + for (let i = 0; i < attempts; i++) { + const first = await listen(0); + if (!first) continue; + try { + const address = first.address(); + // 65535 has no `port + 1`; draw again rather than probe an invalid port. + if (address === null || typeof address !== "object" || address.port >= 65535) continue; + const second = await listen(address.port + 1); + if (!second) continue; + await close(second); + return address.port; + } finally { + await close(first); + } + } + throw new Error("could not find two adjacent free ports"); +} + // Mirrors flow_runner.py's wait_for_server: poll GET /free until it answers // 200 or the deadline passes. async function waitForServer(baseUrl: string, timeoutMs = 15_000): Promise { @@ -110,7 +134,7 @@ describe("mpp-protocol flow conformance (canonical flows / TypeScript runner)", }; beforeAll(async () => { - const port = await getFreePort(); + const port = await getFreePortPair(); const baseUrl = `http://127.0.0.1:${port}`; server = spawn(tsxBin, [COMPLIANCE_SERVER_PATH], { cwd: harnessRoot, diff --git a/harness/test/onchain.e2e.test.ts b/harness/test/onchain.e2e.test.ts index c6ba40928..23ccc1493 100644 --- a/harness/test/onchain.e2e.test.ts +++ b/harness/test/onchain.e2e.test.ts @@ -1,13 +1,16 @@ /** * On-chain settlement E2E — the regression net the structural harness lacks. * - * Boots a mainnet-forking surfnet (@solana/surfpool 1.4, which executes the + * Boots a mainnet-forking surfnet (@solana/surfpool 1.5, which executes the * deployed payment-channels program) and drives the real pay-kit client/server * end-to-end. A success is only returned after settlement CONFIRMS on-chain, so * this catches settlement-class regressions the byte-shape harness cannot — e.g. * the `TreasuryAccountMismatch` (0x961) that made `upto` silently 402 after * payment. (surfpool-sdk 1.2 could not run the program — "unsupported BPF * instruction" — which is a chief reason these regressions evaded local CI.) + * 1.5 is the first release that executes version-1 transactions, which the + * x402 clients build once the server advertises `transactionVersions: [0, 1]`; + * 1.6.1 fails MPP charge simulation with "Blockhash not found". * * Network-gated: surfpool forks from a mainnet datasource RPC. Set * HARNESS_ONCHAIN=1 to run; SURFPOOL_DATASOURCE_RPC_URL sets that datasource diff --git a/harness/ts-client/package-lock.json b/harness/ts-client/package-lock.json index c92bd8afb..257cf9243 100644 --- a/harness/ts-client/package-lock.json +++ b/harness/ts-client/package-lock.json @@ -11,13 +11,13 @@ "@solana-program/system": "^0.7.0", "@solana-program/token": "^0.5.0", "@solana/kit": "^2.1.0", - "tsx": "^4.19.0" + "tsx": "^4.23.15" } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz", - "integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.2.tgz", + "integrity": "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==", "cpu": [ "ppc64" ], @@ -31,9 +31,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.7.tgz", - "integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.2.tgz", + "integrity": "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==", "cpu": [ "arm" ], @@ -47,9 +47,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz", - "integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.2.tgz", + "integrity": "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==", "cpu": [ "arm64" ], @@ -63,9 +63,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.7.tgz", - "integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.2.tgz", + "integrity": "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==", "cpu": [ "x64" ], @@ -79,9 +79,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz", - "integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.2.tgz", + "integrity": "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==", "cpu": [ "arm64" ], @@ -95,9 +95,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz", - "integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.2.tgz", + "integrity": "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==", "cpu": [ "x64" ], @@ -111,9 +111,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz", - "integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.2.tgz", + "integrity": "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==", "cpu": [ "arm64" ], @@ -127,9 +127,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz", - "integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.2.tgz", + "integrity": "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==", "cpu": [ "x64" ], @@ -143,9 +143,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz", - "integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.2.tgz", + "integrity": "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==", "cpu": [ "arm" ], @@ -159,9 +159,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz", - "integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.2.tgz", + "integrity": "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==", "cpu": [ "arm64" ], @@ -175,9 +175,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz", - "integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.2.tgz", + "integrity": "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==", "cpu": [ "ia32" ], @@ -191,9 +191,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz", - "integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.2.tgz", + "integrity": "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==", "cpu": [ "loong64" ], @@ -207,9 +207,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz", - "integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.2.tgz", + "integrity": "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==", "cpu": [ "mips64el" ], @@ -223,9 +223,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz", - "integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.2.tgz", + "integrity": "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==", "cpu": [ "ppc64" ], @@ -239,9 +239,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz", - "integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.2.tgz", + "integrity": "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==", "cpu": [ "riscv64" ], @@ -255,9 +255,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz", - "integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.2.tgz", + "integrity": "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==", "cpu": [ "s390x" ], @@ -271,9 +271,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.7.tgz", - "integrity": "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.2.tgz", + "integrity": "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==", "cpu": [ "x64" ], @@ -287,9 +287,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz", - "integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.2.tgz", + "integrity": "sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==", "cpu": [ "arm64" ], @@ -303,9 +303,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz", - "integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.2.tgz", + "integrity": "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==", "cpu": [ "x64" ], @@ -319,9 +319,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz", - "integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.2.tgz", + "integrity": "sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==", "cpu": [ "arm64" ], @@ -335,9 +335,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz", - "integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.2.tgz", + "integrity": "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==", "cpu": [ "x64" ], @@ -351,9 +351,9 @@ } }, "node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz", - "integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.2.tgz", + "integrity": "sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==", "cpu": [ "arm64" ], @@ -367,9 +367,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz", - "integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.2.tgz", + "integrity": "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==", "cpu": [ "x64" ], @@ -383,9 +383,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz", - "integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.2.tgz", + "integrity": "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==", "cpu": [ "arm64" ], @@ -399,9 +399,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz", - "integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.2.tgz", + "integrity": "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==", "cpu": [ "ia32" ], @@ -415,9 +415,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz", - "integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.2.tgz", + "integrity": "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==", "cpu": [ "x64" ], @@ -1134,9 +1134,9 @@ } }, "node_modules/esbuild": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz", - "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz", + "integrity": "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==", "hasInstallScript": true, "license": "MIT", "bin": { @@ -1146,32 +1146,32 @@ "node": ">=18" }, "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/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" } }, "node_modules/fastestsmallesttextencoderdecoder": { @@ -1195,35 +1195,13 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/get-tsconfig": { - "version": "4.13.7", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.7.tgz", - "integrity": "sha512-7tN6rFgBlMgpBML5j8typ92BKFi2sFQvIdpAqLA2beia5avZDrMs0FLZiM5etShWq5irVyGcGMEA1jcDaK7A/Q==", - "license": "MIT", - "dependencies": { - "resolve-pkg-maps": "^1.0.0" - }, - "funding": { - "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" - } - }, - "node_modules/resolve-pkg-maps": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", - "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", - "license": "MIT", - "funding": { - "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" - } - }, "node_modules/tsx": { - "version": "4.21.0", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", - "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "version": "4.23.15", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.23.15.tgz", + "integrity": "sha512-Yiex1Ovn8z2xPpOWckIiysV1SSyRMY9BkLF++q0yKiDxCqRhosKfMg3janKkiLBwZ5c/YryloKwGZcrEmtwxKw==", "license": "MIT", "dependencies": { - "esbuild": "~0.27.0", - "get-tsconfig": "^4.7.5" + "esbuild": "~0.28.0" }, "bin": { "tsx": "dist/cli.mjs" diff --git a/harness/ts-client/package.json b/harness/ts-client/package.json index f625f4cd6..86a353706 100644 --- a/harness/ts-client/package.json +++ b/harness/ts-client/package.json @@ -11,7 +11,7 @@ "@solana/kit": "^2.1.0", "@solana-program/system": "^0.7.0", "@solana-program/token": "^0.5.0", - "tsx": "^4.19.0" + "tsx": "^4.23.15" }, "overrides": { "ws": "8.21.0" diff --git a/harness/vectors/FILL.sha256 b/harness/vectors/FILL.sha256 index 8ed9d1305..580e270f9 100644 --- a/harness/vectors/FILL.sha256 +++ b/harness/vectors/FILL.sha256 @@ -16,19 +16,20 @@ cbf1964d7942ddc90cb59e0b6dc136f5e0855975bdf3bac790a3b8be6f7ab4d4 annotated/batc b1883c0a8adc8b00b8948695a5e061854f7f26e54e2bc6ecae4053ae2b8e1fe0 annotated/batch-close-authorization-digest-frozen.txt 7c5fd3bf6909e3a09619d36d51ec48669d7ac12c8e9cf26f7564302ee19b2796 annotated/batch-receiver-binding-memo-frozen.txt cebe8c2e2e835e00d366a614716fc950a269a3156558576a166c109302e9a7fd annotated/batch-txv1-refund-v1-not-advertised-reject.txt -f8d3e9bebedb8a01efc88e78b6ae45cdcabea6197707d73cb59a88a96b31b96f annotated/batch-txv1-top-up-legacy-policed-as-v0-reject.txt -ece22f1b28d2be87465baf9bdf110213e77141f083ae3745dae8866199539080 annotated/batch-txv1-top-up-v0-on-v1-route.txt -b77dd4cbf99080b666aed8f724aaa055ababd4583d1af03178ab03d5b794cb6c annotated/batch-txv1-top-up-v0-over-1232-bytes-reject.txt -d604af8add177a92f454d815a11fbafe02d82f76476c19a7968d622eb684df15 annotated/batch-txv1-top-up-v1-advertised.txt -081e8ae823b8a11c43ffa53902aed6d5cc17450570787b4af3fbbef1641e884c annotated/batch-txv1-top-up-v1-compute-budget-instruction-reject.txt -ea981eedf129540b23117a2f7e9e72916e8b93da074c345231e06e342cc2df0e annotated/batch-txv1-top-up-v1-loaded-limit-below-max.txt -853a6cee8cbde406c19a663bd666d21724ce2639cf3578e642bfd0eee1c86a16 annotated/batch-txv1-top-up-v1-missing-loaded-limit-reject.txt -a7659349471ab46653e0e08233655e80038fd828fcf733b065d00b9664871b22 annotated/batch-txv1-top-up-v1-missing-unit-limit-reject.txt +b0e6a1126bc85644a2295e6f1b2ab82aa13d6cb8c54c91ca0522aea547d80716 annotated/batch-txv1-top-up-legacy-policed-as-v0-reject.txt +0dd575d558e08585ff289fcc3b2d872ab42eca456d7cea17202cd8152320bf08 annotated/batch-txv1-top-up-v0-on-v1-route.txt +4be4718bdeb05a47800d3424075ca8bcb42de848d388c949598e34fa2521a08e annotated/batch-txv1-top-up-v0-over-1232-bytes-reject.txt +98566f41f49831132ac9dbd741c756f557223ed6e2d3b5a31af1398b5a740b97 annotated/batch-txv1-top-up-v1-advertised.txt +a595e8f51887195d55422fb08d04a9f7ea1f57f9ebef7c0a04b6e4d5c68acb9e annotated/batch-txv1-top-up-v1-compute-budget-instruction-reject.txt +b4203c6e2946a7508dbf99ee6601ecb7082ae332789b7d76f688777437e83d49 annotated/batch-txv1-top-up-v1-loaded-limit-below-max.txt +2eb93762fbd1879fd6272eb2f0681ed3b1c411c9d6c0e849c54975f6c6e7c9cb annotated/batch-txv1-top-up-v1-missing-loaded-limit-reject.txt +3e870a07ca91217780627ac5d595fea6b31c7bc30f8f991fac42ec7f766baeef annotated/batch-txv1-top-up-v1-missing-unit-limit-reject.txt 78c007df83fe926d4b7b52b9b9398f6d57281cb954e730e3cba8814acb6d2f3d annotated/batch-txv1-top-up-v1-not-advertised-reject.txt -22fe677b27fe02e32faaffe2822eb07ccedc2434cabbf4a45112d7f144acc2c9 annotated/batch-txv1-top-up-v1-over-1232-bytes.txt -8ee7b11777ab5c00e0e36172afdded6f68ea984bc804aa90fa563d7d915600eb annotated/batch-txv1-top-up-v1-priority-fee-at-cap.txt -bc2ac43fc7647b88381607a5b43d708251df3360d6be99a10c6a5c6d2c731b13 annotated/batch-txv1-top-up-v1-priority-fee-over-cap-reject.txt -a2e031a6a4276a2d28779bb931e2af3b3b3f7e22f1ae2c41184581e9ed37e843 annotated/batch-txv1-top-up-v1-unit-limit-over-cap-reject.txt +915ebbe8863a40adb641c5a6ca524756609892c8eb1908a2a74a5186bf8b7f95 annotated/batch-txv1-top-up-v1-over-1232-bytes.txt +98f3a48906631a2bf8dd905f634869c163d155db08cb1c2902e69c160f59f8c2 annotated/batch-txv1-top-up-v1-priority-fee-at-cap.txt +32b43edb6d4a79588749a18a26d406dd50515341b9cafeeec49effe4dacc8920 annotated/batch-txv1-top-up-v1-priority-fee-over-cap-reject.txt +1244bd723333a8b7e2b6cc8eca416d1642efff78f2a16c4ac1bad2dec18faccc annotated/batch-txv1-top-up-v1-priority-fee-over-sponsor-cap-reject.txt +f4f0c83f3dfc903fdb5c0ce98eef3261d426cd2de589210157c11cbf7c6692c3 annotated/batch-txv1-top-up-v1-unit-limit-over-cap-reject.txt ac6856f925b534e013855d6edc22b1616924bc914052fee52ca411431d39f2b5 annotated/batch-verify-accepted-amount-mismatch-reject.txt e5711029cc266f1fc00b60d5c28e4cf08c83bc4f7ed2067933c5a2d0e66d1e95 annotated/batch-verify-accepted-network-mismatch-reject.txt 788c8f8411535d523701e8d12b01e0c2619ead9ced6abf5b5afb8e6e8f571b39 annotated/batch-verify-accepted-pay-to-mismatch-reject.txt @@ -44,6 +45,7 @@ abbc3ff848d06872dd85b62b99d6d80efe67399fdf2767ae09092d9cd748c5d7 annotated/batc 1b8fc828c376ab16109ac5f089f396976f77e9a38f8b62a4a04bde7ee97e2c4f annotated/batch-verify-open-grace-period-mismatch-reject.txt 2affb69abe6cb174185ad102a6ef60eaac09386129b8c74d0e85af08cf2663d3 annotated/batch-verify-open-missing-binding-memo-reject.txt d8cbf524c5674d105caf1bebf2c0cb8b92b6476581b59e47ec23187ff167fcee annotated/batch-verify-open-stale-slot-reject.txt +7d5274d7e63295f3fbf9e769f60dc5f06ba6c011427ecd7f3d9bba6a6142eab1 annotated/batch-verify-open-unfunded-payer-reject.txt ec422081390113b98d4e87eda9775ded5bd03c4125da97cac15e2c62a6c1967b annotated/batch-verify-refund-compute-price-over-cap-reject.txt d4ffb0b5ec8fb59abf99416aaeb7a476d76990086b918283e4be00f36c25054a annotated/batch-verify-refund-disallowed-suffix-reject.txt 5ebbb1f5b11cd934f0ef1e290d1faa447c0217813bb66ee074e84dc8bdbe828f annotated/batch-verify-refund-extra-account-reject.txt @@ -61,7 +63,7 @@ b321f5a6904588490d96ad69087fe8de268d21210564fd07575ec8fd2bbaa2b2 annotated/batc 8005ddd0c9f70bb393934ea90a4bf9b55202121f36159eae72e0d6a7fc9e49db annotated/batch-verify-top-up-accept.txt f37f7e838c37d68edb371c4452c255ee0b19484bee43fa53d876a060d2940b3e annotated/batch-verify-top-up-amount-mismatch-reject.txt 3cdadb20446e17f1ea27f62d8edf1395fa91720fc8960abed4dd38e302d29b8e annotated/batch-verify-top-up-ata-instruction-reject.txt -4a949221a79fccea2e874552fcfa58425da7ca53668df8aa166689e035007536 annotated/batch-verify-top-up-compute-budget-prefix.txt +1ff9971b5c1fc4def2f875ac6fd8ae9a5b795ffa1d6a19e7ddeec0b8c881acdf annotated/batch-verify-top-up-compute-budget-prefix.txt cff0683f94cc314246aaa144a37eb40cc328d900ab3934feeee42a6373028afb annotated/batch-verify-top-up-compute-limit-over-cap-reject.txt 070c31a1d57a3beebcd79fa34b7bc2ce5a779a87acd932f9417475f28d11b139 annotated/batch-verify-top-up-compute-price-over-cap-reject.txt 08856502c2f4beb69aecea6eb54095c38afd75ed8230bc7cda2a48c26aaacbb2 annotated/batch-verify-top-up-duplicate-limit-reject.txt @@ -72,6 +74,7 @@ cff0683f94cc314246aaa144a37eb40cc328d900ab3934feeee42a6373028afb annotated/batc 40008adb08e644ce581a8fdf588bb2ec1781fc549505fcc96b75abb0a9b0926f annotated/batch-verify-top-up-fee-payer-not-sponsor-reject.txt 9eb513712b5f3ec86dc145ca787a7fdbfc6c4e64906eb3c814ac5b9b27f41de3 annotated/batch-verify-top-up-four-lighthouse-reject.txt ad0234c28be3a00ec169ffcac7708d4de28ca4a13a65a87b2dd3833bc745bf10 annotated/batch-verify-top-up-frozen-payer-ata-reject.txt +6181c15cd01a70578b8c9cb3ad6d8fa682108269b7867926d4ab7b01df5d271e annotated/batch-verify-top-up-implicit-limit-priority-fee-over-cap-reject.txt d2db393b2e9934b812d07767930c9435b8b775273546e8e86f2cd964eb330fe1 annotated/batch-verify-top-up-legacy-message.txt 4b0fba5e3942f08bdbcb7a54cb594bc8fe22e7e9e543864b240807eccd96b66b annotated/batch-verify-top-up-memo-mismatch-reject.txt 96f7b3553cb8906f55af973a8d4302cb7d8ab435f057edbec82f867f0ecb4a1e annotated/batch-verify-top-up-missing-memo-reject.txt @@ -79,12 +82,14 @@ a21cd90f07842230198b5e91463b5a32008388785d435a4022bc4bb564a003fe annotated/batc 162f0cfcb737e749f9be55b7cc6538c79190439be6feb8987e4a5dde12ac0766 annotated/batch-verify-top-up-missing-receiver-ata-reject.txt 3e7851a34c992e6bd903faf1ea995b90f73fc236da6e0eff0574bbcb22dce615 annotated/batch-verify-top-up-oversized-memo-reject.txt 131b94e275b189c3f85bad07f05cee779aff9534b0e8a455ed708b67cd1fe751 annotated/batch-verify-top-up-price-before-limit-reject.txt +0d432e27826d0c5a834d0ea66e0ed892d9582438f50dff46f370eda17a12d541 annotated/batch-verify-top-up-priority-fee-over-cap-reject.txt b4d04378f5767b1c5d30054184cafc929af2be344d2a3afb2f2a1603c518b13a annotated/batch-verify-top-up-second-setup-instruction-reject.txt c5ad34fc7aaa0bf8a49bd8d386fee5d0cae41b2334bdbd1bd1b382e513f810f2 annotated/batch-verify-top-up-smuggled-transfer-reject.txt 42f7fdd961a9643109a4d82ea00808bed206245b614dc7fc1a27ffe807533d26 annotated/batch-verify-top-up-three-lighthouse.txt d9e47769a4cdae29c93ee813ac9fefdde1257d93a54103986018a73d15debaa5 annotated/batch-verify-top-up-token-program-not-mint-owner-reject.txt 376fd66be9d2cbe6eeb0669080dfad4e29806c2356dbfc30e18c8e4f836a3c65 annotated/batch-verify-top-up-trailing-bytes-reject.txt 0886f848e43dea172477e103edeb934c5ad499a36b95953b1ae4bfd64f48a5de annotated/batch-verify-top-up-two-memos-reject.txt +6eef6e2e6b8ef5c5244f1b7f90ecfdc1effc93f9daeca6cdaf55ad61d635993d annotated/batch-verify-top-up-unfunded-payer-reject.txt 089fe911fc1b1f8000dad6e13d91846cdd2e73afad9e4b5cff820b21a2f23bb8 annotated/batch-verify-top-up-unsupported-compute-budget-reject.txt a7a9b6b9d0364ebcc8372a1781728f71f93c1ea76cf3f20d9f48851036907f81 annotated/batch-verify-top-up-wrong-channel-reject.txt d5f619a54d0fd07ac2e14433b892efedc3a6d4d8022e21420b813d4d0f0ec14a annotated/batch-verify-unsupported-scheme-reject.txt @@ -107,6 +112,7 @@ d54be8d24dc58c6412fab0c27ef261db61b11404be26478bbd01ea0ef3955c5c annotated/batc 531387a5967803eaf457add1a9627859af1a43378f4f9d5d315f647a51703910 annotated/batch-verify-voucher-receiver-authorizer-mismatch-reject.txt d3da7795e16892e7188afad55ce5d01d70ef2795fb5ba7fad43bd187169174ba annotated/batch-verify-voucher-receiver-authorizer-missing-reject.txt 69c0911edd4dbdc7087e50b531a4c0e1767460b8bf721e83256db18053615dbe annotated/batch-verify-voucher-receiver-not-pay-to-reject.txt +ef969b69c65b5649d51ba8f7ce515c997b14159c53bcbc5f5927aa7d3ed28f42 annotated/batch-verify-voucher-receiver-quotes-a-code-reject.txt e3ebeac648f18bfb0c7201f8ab72417b191327729b22f4013ba365daf871e054 annotated/batch-verify-voucher-server-mode-config-reject.txt 8f0736a900e01c7c1b9f3f425f6be83d8b69a7a88c3d8d743df69e590b6163b7 annotated/batch-verify-voucher-signature-over-other-amount-reject.txt 3a311d024360e6478928e28120f02b5a730ae48184f98711d529f039b8fb3c51 annotated/batch-verify-voucher-stale-reject.txt @@ -130,14 +136,18 @@ c3be1f3448c26af23af513e02c7aa6934fd5598ec31c24ef8a3f0fd0b4089864 annotated/batc 96571e60b2d1beff74095c494310d311f94aa67db101e4f830f42ecb449d64bc annotated/batch-wire-payload-unknown-type-reject.txt b5329b58c7d856b43529565f1b7b4633ea5073ca6676512270da34eccc42a5b6 annotated/batch-wire-payload-voucher-frozen.txt 7216a0e2794c1127daa5f6fd2fa2ba7fa1a8acc17e14d43d48343b2441f2978e annotated/batch-wire-payment-payload-frozen.txt +fa4e50d0ff78e3d289b089ac249c1486223d0e218ef2d89b555e2ddc6b582a76 annotated/batch-wire-redemption-claim-eighteen-entries.txt a9c1c59e7ab6b6ff1241425651a5c4e18e2b6d0017214a36b01d2a78aa3f8edb annotated/batch-wire-redemption-claim-empty-reject.txt 0b0fedab1bd005ca625f2ee4c48f060bbaefba3dcfa42848da31c56755dd6028 annotated/batch-wire-redemption-claim-entry-without-config-reject.txt -6b943039e38fc8058b392191fb509fb3cec406bdb01e986397b2e21e01514e6f annotated/batch-wire-redemption-claim-five-entries-reject.txt 13e9ed7c81d2c20a0a67fe2b36c812b7a39d69b8ac7caa1eaeab967875c4161d annotated/batch-wire-redemption-claim-frozen.txt +bcf5691e235d43922d6c5a154622aa05411d619b868c3a4c257f09e4a1231602 annotated/batch-wire-redemption-claim-nineteen-entries-reject.txt d7664695b5f05a9708be29f22daf3b4321e0e5eff45c667c75a8c66bf0376c7a annotated/batch-wire-redemption-seal-frozen.txt +54430551260168a40e15c8f36fb3967e88977ff315a501714f8278da007e8ff4 annotated/batch-wire-redemption-settle-fourteen-channels-reject.txt 6678a671bbe6b6090ad87d32697be8fe7589c6af93247326d327704b1f49b503 annotated/batch-wire-redemption-settle-frozen.txt +6ca0645a88505b31bf339d44c51b461df745b4c2930e92e6f6c049e5037b7dd4 annotated/batch-wire-redemption-settle-thirteen-channels.txt e5c035fff26bc29e126695735380a1a2062495b17781a14806d495c2a1c97901 annotated/batch-wire-requirements-frozen.txt -6c7ff4ca6f85430e3220d805bf6f084cb09785dc621934e2e92784a14c518577 annotated/batch-wire-requirements-transaction-versions.txt +ea2a58fe10370a47a5bf80215080fb5ac607db8f13d29ffe03ed3561495d0699 annotated/batch-wire-requirements-redemption-capacity.txt +123dcb26d90c9ae053c1c509474e3d0c31812f91b4bd56cf6737d50ac117efdb annotated/batch-wire-requirements-transaction-versions.txt 50af62264075b82e55d608a0261fb3aee213b1ab2e1f6630172a0e997d2cea47 annotated/batch-wire-requirements-unknown-transaction-version-reject.txt 62a2c4abaf41a5c181326b93f5d4bda79877ca4803b39e6e8ee20f73376102db annotated/batch-wire-settlement-response-voucher-acceptance.txt e33e5ac35f869e8eeaadf88f449287d96c54929c0d523a89913f613679953241 annotated/canonical-bytes-48-base64url.txt @@ -484,7 +494,7 @@ acc9a03b99aa82aad211f9a7045eeb40c27ad21606b6c40126e686e5eff7d054 annotated/x402 680284da54a60b588a697c92fc9551e2f34ccce261d3c7d2cbdeddfdf8fc0d30 annotated/x402-upto-verify-client-voucher-empty-reject.txt ea69f94e8ed85c52afe6b840cc59c2db368606f74143be441a8e1cb4aefae69e annotated/x402-upto-verify-client-voucher-reject.txt 8f4d132df707ad8af2d98b18b0ae0d2aae386be972dd9a34be61313c9b927043 annotated/x402-upto-verify-compute-after-open-reject.txt -87083847140c9610db91badecc3235f8182dcbb31cad238376b1ab3f60da6374 annotated/x402-upto-verify-compute-at-caps-accept.txt +e52a6ca2aa3c9255303643af1472f895b6fcca932c8c0749fd8258f7c0fc3ba9 annotated/x402-upto-verify-compute-at-caps-accept.txt 6432ba8692105852846dda3ab230ca0b376b11f8a93e44cd24e9fd5921799b19 annotated/x402-upto-verify-compute-duplicate-limit-reject.txt 21608dcea744525e48e2907fe7db4391c9ba41add489cd7bf7271b0f254b8349 annotated/x402-upto-verify-compute-duplicate-price-reject.txt ebf22f2bf093a9c44b4ee00b404622309d53746e5509fe7adff4cf284de885f0 annotated/x402-upto-verify-compute-limit-over-cap-reject.txt @@ -513,6 +523,8 @@ faf9819f9d408b7501f5d86e57e32c6ddaa557f9cf07dc50c33f8faeb382e7b8 annotated/x402 0a36e7e94a7eebf13e5e96552436a7632a5bb640391f7d37ee1cca8257e9aad8 annotated/x402-upto-verify-fractional-expires-at-reject.txt 871d71d91dfc67e79b1ee5925f7aaba73f276be25de61cadd9e250c20bec6076 annotated/x402-upto-verify-fractional-valid-after-reject.txt e1b89f350d2146afba565aa3b729ddf14e180c4cc3ffaaa3b64603fb22eda88e annotated/x402-upto-verify-grace-period-reject.txt +2134419d8a747670bbaf164c0b033e70089de5ac7141fc3811e06df98c1c2569 annotated/x402-upto-verify-implicit-limit-at-fee-cap-accept.txt +45e9d41c3aad45749f25859cc72af8c40ab0315956df34241165acee35059a26 annotated/x402-upto-verify-implicit-limit-priority-fee-over-cap-reject.txt 3bae8185d730c713d895ad01dc0698bcd451ec3a870c9027311384d38db1d9f5 annotated/x402-upto-verify-invalid-payer-signature-reject.txt 38eaacf3194b9f95a37d692b99c63332d34e08cc7aa01e78eee8019cc6261b73 annotated/x402-upto-verify-legacy-message-accept.txt debe92e1abbc8d2507e47917d34b7d23e8f45c8a9b9e40e160915d3aeff14831 annotated/x402-upto-verify-lighthouse-accept.txt @@ -541,6 +553,7 @@ b8d1adc29384f0ca1d605cb8ca6738c1769c9bf4caae2e89da286e0beb5b6fe5 annotated/x402 690bf4307d6c7b0736a4fd97b7489879e11be02b82a71885b9e816f8089df738 annotated/x402-upto-verify-pay-to-fee-payer-accept.txt 091c85b57f469025f65a0d17c910a6cd73f775640508969380da14a6180469bd annotated/x402-upto-verify-payee-reject.txt b9bdcfe745db3b93a2fb118630bee4c171d828dac85baf6a81cd062581fe2110 annotated/x402-upto-verify-payer-token-account-reject.txt +17514a51ebe453546e264577c94fe545eb07871214da61065d7cf803b402c5cf annotated/x402-upto-verify-priority-fee-over-cap-reject.txt 452683fafe8d84b99f526ba48e5f43889967f38d7e28a299d817ba960479dc22 annotated/x402-upto-verify-recipient-bps-reject.txt 7607efcd94618b9910b025d924826cd65e79ad10d26babc5fac1eafafb59ad40 annotated/x402-upto-verify-recipient-implicit-reject.txt 3b0f56eb8d9b1b069a0a8e74cbc43a15a3ea4b5eeebc737971d0f7b503a58ecb annotated/x402-upto-verify-recipient-reject.txt @@ -566,8 +579,9 @@ ce59ed37df74e4826d9bd6c71c09cc514163da33f85f708843d7742d363d558e annotated/x402 1917d0fe6e9e52317ae2ff05ce769ceb9e2948f629530de38984a74a42d09b88 annotated/x402-upto-verify-v1-missing-limit-reject.txt 047c59de0ca609c7ecbfadf78e99af07e73f1d97581e42feb1bd5af305ed767d annotated/x402-upto-verify-v1-missing-loaded-limit-reject.txt 4e62956ea1ce652109463a90b26d4c46a52360b3f62ba207fd382d79c68a40c5 annotated/x402-upto-verify-v1-oversize-reject.txt -2eb93676066b4ac25c8205dbb2a4d2141d0b6c3202fbf220828950f9541ee5ec annotated/x402-upto-verify-v1-priority-fee-at-cap-accept.txt -8f107c62c931deb4930b5ad85fa78f14ab540dc32d91252a5db320bbf06e60de annotated/x402-upto-verify-v1-priority-fee-over-cap-reject.txt +c6c8ef7beb8ac903a0a9ea75ebae5fc36f8bc1bca7619af8ca0fce273b4ee783 annotated/x402-upto-verify-v1-priority-fee-at-cap-accept.txt +21d1fbf22e8848a9111dfe36352d5b877f6cd4a4c84f9945a79619bf92cfae04 annotated/x402-upto-verify-v1-priority-fee-over-cap-reject.txt +8fdec90d0dac0cf754335c9e62e8f8446c0a27cc5d82cc9b0853082a75d2dd3c annotated/x402-upto-verify-v1-priority-fee-over-sponsor-cap-reject.txt 415ba369d974ef5b2b26d27e44565a8eee760b993747fd64ad818ef87be2c4c3 annotated/x402-upto-verify-v1-small-loaded-limit-accept.txt 251510e562d067008004931a6e6ee408301b3566e23155b019cbc8346ff44e62 annotated/x402-upto-verify-v1-unadvertised-before-layout-reject.txt 22844edaa25c1b45723e72efd6ef3cf096fd3ada517d7d0205e73b7e02ec274f annotated/x402-upto-verify-v1-unadvertised-reject.txt @@ -581,13 +595,16 @@ c990a038b0b2ada183227986a3355217212ac3c5bded7b06c10ee8d29c8deb8a annotated/x402 32d7e93a504fbbba2a5ea7d9a7716c6980c9184f1b1e34eb47e83ce5e4e01043 annotated/x402-verify-v0-with-v1-sponsor-accept.txt 41c340af7b49ab751d9b4e7735d3ac4979141adf6b7f4aeb2c575cf5cd1241aa annotated/x402-verify-v1-accept.txt 24eb1b403b372a7ec687f6635ae104af4373a125e7920bc1295844b7c05ccbd2 annotated/x402-verify-v1-compute-budget-instruction-reject.txt -98aa629fd1ce7bde0c60f1ba21103a93aca5323c2ec19426086f14ede67c1bdc annotated/x402-verify-v1-compute-limit-at-cap-accept.txt -f5be46826129cde0e271e8f17a5e87cec1c270647de769903b664119979ed442 annotated/x402-verify-v1-compute-limit-over-cap-reject.txt +7ed5c8baf33357fab18dc82212abdc64b87b567fbed7677e16cc547bc79db8a1 annotated/x402-verify-v1-compute-limit-at-cap-accept.txt +f91fb91482ac310e3eab9ff60f3d57f26175a918d73995a3e0f5aeb409b817d0 annotated/x402-verify-v1-compute-limit-over-cap-reject.txt d00bd3620a79320e1862841e29052166535e8fd36b27b1460e33e5f89caf8415 annotated/x402-verify-v1-decimals-reject.txt 906f622ea65e8a2f5ef4144567870ca2b02c4419bebeb3e1122d67c314dd6164 annotated/x402-verify-v1-explicit-v0-sponsor-reject.txt 0461554796f1e5cb015a2fd25e6d744b6f253f6e916fb7b1d3def7b48be6e5ad annotated/x402-verify-v1-extra-signer-reject.txt f6f4c736800ac8eda78ac8c1a7a3e02fc1f8f67860c2b1f9b2ab283e0fc88bb5 annotated/x402-verify-v1-fee-payer-authority-reject.txt 8ae9ddd8b332a92b90202c43001d5b098c7a27472109bd73ba7bcb680eb75a68 annotated/x402-verify-v1-fee-payer-in-accounts-reject.txt +5e84ce47631c8c39348cfd23c65833ac3ace65ea4670d3ab4ffe28c7861a4f26 annotated/x402-verify-v1-heap-size-reject.txt +92e71b89b9168b75d7589cbab2242cd2e521e703c4a5bfdc748bda676eb7f477 annotated/x402-verify-v1-loaded-data-limit-4mib-accept.txt +c54ce1aee62029fbdca28e7cbdff14b3eb6fedf78919ec9d85e14c8ba05f86b7 annotated/x402-verify-v1-loaded-data-limit-small-accept.txt 793d2c1c67c7fd90951804a0e129ab943f8567f913cf9d9dd8278337bbfc55a8 annotated/x402-verify-v1-missing-compute-unit-limit-reject.txt 2c0337853e1397f8f1e05c73d4d1f0e558e9229d4102962f418bf07b459b8515 annotated/x402-verify-v1-missing-loaded-data-limit-reject.txt 59e56227a21cf39a8403344cb30d7b5a76215f6ea4dcf312257e7461aada2612 annotated/x402-verify-v1-not-accepted-reject.txt @@ -601,15 +618,15 @@ a21a0bf71278d43da4ebbff0d32f0e232085f47386fd9476e746a0198a2fc2d1 annotated/x402 53b6a226079b89ff63242d8d71e6baca5eb3cd2e727a702a0c9e5a4962260edb annotated/x402-verify-v1-wrong-recipient-reject.txt ee17ec2e291409954d77a23e40909764e62a3cd53730fd693a72ce0462212811 annotated/x402-wire-transaction-versions-golden.txt 6ee44f50ea0166824340503d06597ab72387f672a3f8b97965efe0a1a9e008d9 annotated/x402-wire-transaction-versions-v1-only-golden.txt -00d714eb0b579a1bc8ee6c0f017297dad3dcdec91827a30efbd8927634021937 batch-build.json +da0b8e79ef64a23bfaff865b6940e9c664b8bc7661adca70e9ffb8701b5e47a5 batch-build.json 1e0bb980d86a6dca02071160befe39f9603b73d7ddb06de06e3f32a68fb248ec batch-canonical.json 9d29189ac18e7f3219a336acb593d6a64527b9357ff60ce0be44108ed38e2598 batch-corrective.json -c8baf9606dc77393d125bba0050f4f07f79887da58ce33ed8e09a3d04f7441f9 batch-txv1.json -456f3193ec301265c7ee71571757809c802afc41a866fb4bfa8989f1203dad47 batch-verify-open.json -2c69a2d23afd0c815d5be2634154208f608c157cf1132c9675d1434a8d5d2857 batch-verify-refund.json -5a3737493aa52305b81f3305c7a097ebad45e02154dbbcd1da89e62c5869fd6e batch-verify-setup-policy.json -3428ded34c4f1cfbfe343e7e8923f4f3a396a587836729f198a7c36d32f5b1ca batch-verify-voucher.json -0c6f4fae057ce68548cc4c496ecaa36cef906709abafc3463cd3de8f2543a5b5 batch-wire.json +3720bf9619ed67d98ae8a244247d2cf9a41a3bc35eb2942e4a9973c2ad8e89e8 batch-txv1.json +b07ebc33137c3c1c6c6ae99f757e720b8e35afc964ae24547e8fc53f64b76f7c batch-verify-open.json +15bc380bb473fa8e23bbecdbc3fbc3e4183bb09675f60ee45e667ff281225ae1 batch-verify-refund.json +b0375d1f1437128c3ad5b0051eaec40536032f3b6033f1a70d2454a2665031ee batch-verify-setup-policy.json +c6a7c5ee92d522a70183ca5852f6d6ca7216d1e03a50757cd56becadcfbf085e batch-verify-voucher.json +59ee352470ffa77ff4ad40f9207daf30119716ba7bd4a085e8d3eff9e0c99a8d batch-wire.json 65a3a4793b3ef918d2b6464e0aa24e8f30de634c1a8223543960224fef443bea canonical-bytes.json d751557cf0494e0b1d0cccad86bddf0f7ec0b784fe8e21ac2bf621793e1e956c charge-build-policy.json e82e3d3a8fb515bb7b69f4a34b1126d134456522351078680f2622bc551ee8e6 charge-defaults.json @@ -618,7 +635,7 @@ a0f8c42823b78c7ba5db0a25682ab0daa4bff03985fe3d7b64a244173d6465f3 charge-rejects e564bdca0d12e602ecb8b722f63a582b0213f7be74d01fa27e50ece2cf5fee2a charge-tx-versions.json ecd8ace669ac4739473b5b393aee34d563e9ad7d4aaa206540f731c9afff5b44 charge-verify-mutations.json 88de2d5aa3a36dee4e9a4ac1521a17e2de2025c8c5b92ac89c46013c20082187 charge-verify-policy.json -a2dae7b002989b55edd1362d326176b3d348c105bcef48be4f89b3056fe6bab5 session-build.json +ae480d2e1d4147763c9ba94fdc52b05371bfeea8ae687895ea15071831439802 session-build.json eb2da9fc8fd9190525718add58674f5a75ae1fcd418d50716dcd4fe0e43ee505 session-server-close.json 1679f69290ad24ceaeb8b2d4cde3707ed9c061c46d534ae698f4e49a70a62efd session-server-open.json dabdb7f95ed32cd6c45dc40ba9c2d1e9b6946655eb5397d107862374a95a5a81 session-server-topup.json @@ -639,14 +656,14 @@ c033a9a8ebbceabbf477b542173afc78db89a3529f8d42f8467de03a2842e689 subscription-w 560897640e9668490a4869cd9877ac20bc729d5ffbd4a4f04001e5d82af80fae x402-build-policy.json ce46f0ac323f508415a6dea09315596ed4fa52e38b511e2f0cf808f485d32f2a x402-build.json 812e251b273d84998507068b1b41c9710db973f05c9c38b340bb5b009f0060fc x402-extensions.json -2c75e41fa50fdbaeff061100d455866af1bd1d5393d1a8a2277608072ac99e52 x402-tx-versions.json +3bda4223dfd2459e08d60fbf0fdca55e47bfc4fa98bd256ca6980ebc8aa20772 x402-tx-versions.json ac2555712b1f952bb8c59dbcc57dccd0f3fe2de480f0a98982e15a801229e695 x402-upto-build.json -104a4c96607919402d21a0b4ffdd15796132b70702a02e7436b6495f1d1700f4 x402-upto-open-policy.json -ac8b5c84c914b88af97e7327e9221edd8ebe99e9280680a34c4ee5b18534211c x402-upto-txv1.json +56e1326fcf81fd7bc04675ef81df0927c19ce6b6a081c8c0207a49bfc1babbe0 x402-upto-open-policy.json +ce0f857b5654557f61f18fadb2f1f5639a5b8a274b0378fe82599b0d8a21b124 x402-upto-txv1.json ed579f6183f66be54f127aaec7beb5ba19f6a22222b0dbeeb18479f901f67d43 x402-upto-verify.json 7c2c19185d91c9a2d7b8d55ef4342cbcf49dc7e2918d5daa5b0357c624ad2ab1 x402-upto-wire.json a0b94e993a0766fe74aa500254c63672ddeab94aad6ec4b1ed136bb7ccd26be8 x402-v1-build.json 20db1ed7696fcb2d445cab1839bdda4737295a99cc525068dbbb63008f210821 x402-v1-verify.json -14d20064e411a8f8b88017745420b772f48a5ab50d10f93bbe47ff39d5e468da x402-verify-mutations.json -24618f97f70d81d808110aaa75c104dd69e2828b33b6ea7e7fd0f49676230390 x402-verify-policy.json +40e281d00a66b411396a18ed3040fa60c53a72c0964144903263920c459bc727 x402-verify-mutations.json +5ba2a0b6f79301f9518b568ea41cb37aaf37a14bf13962cbed3ee3adc56db4f1 x402-verify-policy.json 65ad8e90bd56fd2bf4da7d7a1a3bad9215fc19294beb6eb4ee88b513760f05f8 x402-verify.json diff --git a/harness/vectors/annotated/batch-txv1-top-up-legacy-policed-as-v0-reject.txt b/harness/vectors/annotated/batch-txv1-top-up-legacy-policed-as-v0-reject.txt index 6a3815f00..1823365bc 100644 --- a/harness/vectors/annotated/batch-txv1-top-up-legacy-policed-as-v0-reject.txt +++ b/harness/vectors/annotated/batch-txv1-top-up-legacy-policed-as-v0-reject.txt @@ -8,6 +8,8 @@ payment header (base64 JSON) "asset": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", "extra": { "feePayer": "J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf", + "maxClaimChannels": 18, + "maxSettleChannels": 13, "memo": "invoice-42", "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", "tokenProgram": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", diff --git a/harness/vectors/annotated/batch-txv1-top-up-v0-on-v1-route.txt b/harness/vectors/annotated/batch-txv1-top-up-v0-on-v1-route.txt index 215c30f18..f3f166efa 100644 --- a/harness/vectors/annotated/batch-txv1-top-up-v0-on-v1-route.txt +++ b/harness/vectors/annotated/batch-txv1-top-up-v0-on-v1-route.txt @@ -8,6 +8,8 @@ payment header (base64 JSON) "asset": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", "extra": { "feePayer": "J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf", + "maxClaimChannels": 18, + "maxSettleChannels": 13, "memo": "invoice-42", "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", "tokenProgram": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", diff --git a/harness/vectors/annotated/batch-txv1-top-up-v0-over-1232-bytes-reject.txt b/harness/vectors/annotated/batch-txv1-top-up-v0-over-1232-bytes-reject.txt index 34ff91a5d..366086813 100644 --- a/harness/vectors/annotated/batch-txv1-top-up-v0-over-1232-bytes-reject.txt +++ b/harness/vectors/annotated/batch-txv1-top-up-v0-over-1232-bytes-reject.txt @@ -8,6 +8,8 @@ payment header (base64 JSON) "asset": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", "extra": { "feePayer": "J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf", + "maxClaimChannels": 18, + "maxSettleChannels": 13, "memo": "invoice-42", "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", "tokenProgram": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", diff --git a/harness/vectors/annotated/batch-txv1-top-up-v1-advertised.txt b/harness/vectors/annotated/batch-txv1-top-up-v1-advertised.txt index 4cfc3bcd5..579272061 100644 --- a/harness/vectors/annotated/batch-txv1-top-up-v1-advertised.txt +++ b/harness/vectors/annotated/batch-txv1-top-up-v1-advertised.txt @@ -8,6 +8,8 @@ payment header (base64 JSON) "asset": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", "extra": { "feePayer": "J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf", + "maxClaimChannels": 18, + "maxSettleChannels": 13, "memo": "invoice-42", "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", "tokenProgram": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", diff --git a/harness/vectors/annotated/batch-txv1-top-up-v1-compute-budget-instruction-reject.txt b/harness/vectors/annotated/batch-txv1-top-up-v1-compute-budget-instruction-reject.txt index 1ffbe68ca..40861fbb9 100644 --- a/harness/vectors/annotated/batch-txv1-top-up-v1-compute-budget-instruction-reject.txt +++ b/harness/vectors/annotated/batch-txv1-top-up-v1-compute-budget-instruction-reject.txt @@ -8,6 +8,8 @@ payment header (base64 JSON) "asset": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", "extra": { "feePayer": "J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf", + "maxClaimChannels": 18, + "maxSettleChannels": 13, "memo": "invoice-42", "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", "tokenProgram": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", diff --git a/harness/vectors/annotated/batch-txv1-top-up-v1-loaded-limit-below-max.txt b/harness/vectors/annotated/batch-txv1-top-up-v1-loaded-limit-below-max.txt index 98517c02c..1e39a6e2d 100644 --- a/harness/vectors/annotated/batch-txv1-top-up-v1-loaded-limit-below-max.txt +++ b/harness/vectors/annotated/batch-txv1-top-up-v1-loaded-limit-below-max.txt @@ -8,6 +8,8 @@ payment header (base64 JSON) "asset": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", "extra": { "feePayer": "J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf", + "maxClaimChannels": 18, + "maxSettleChannels": 13, "memo": "invoice-42", "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", "tokenProgram": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", diff --git a/harness/vectors/annotated/batch-txv1-top-up-v1-missing-loaded-limit-reject.txt b/harness/vectors/annotated/batch-txv1-top-up-v1-missing-loaded-limit-reject.txt index 2fcaa16da..6082e9bf5 100644 --- a/harness/vectors/annotated/batch-txv1-top-up-v1-missing-loaded-limit-reject.txt +++ b/harness/vectors/annotated/batch-txv1-top-up-v1-missing-loaded-limit-reject.txt @@ -8,6 +8,8 @@ payment header (base64 JSON) "asset": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", "extra": { "feePayer": "J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf", + "maxClaimChannels": 18, + "maxSettleChannels": 13, "memo": "invoice-42", "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", "tokenProgram": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", diff --git a/harness/vectors/annotated/batch-txv1-top-up-v1-missing-unit-limit-reject.txt b/harness/vectors/annotated/batch-txv1-top-up-v1-missing-unit-limit-reject.txt index 336d821c4..24a3b3c47 100644 --- a/harness/vectors/annotated/batch-txv1-top-up-v1-missing-unit-limit-reject.txt +++ b/harness/vectors/annotated/batch-txv1-top-up-v1-missing-unit-limit-reject.txt @@ -8,6 +8,8 @@ payment header (base64 JSON) "asset": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", "extra": { "feePayer": "J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf", + "maxClaimChannels": 18, + "maxSettleChannels": 13, "memo": "invoice-42", "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", "tokenProgram": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", diff --git a/harness/vectors/annotated/batch-txv1-top-up-v1-over-1232-bytes.txt b/harness/vectors/annotated/batch-txv1-top-up-v1-over-1232-bytes.txt index b2fc6b4e0..b1efbaa34 100644 --- a/harness/vectors/annotated/batch-txv1-top-up-v1-over-1232-bytes.txt +++ b/harness/vectors/annotated/batch-txv1-top-up-v1-over-1232-bytes.txt @@ -8,6 +8,8 @@ payment header (base64 JSON) "asset": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", "extra": { "feePayer": "J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf", + "maxClaimChannels": 18, + "maxSettleChannels": 13, "memo": "invoice-42", "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", "tokenProgram": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", diff --git a/harness/vectors/annotated/batch-txv1-top-up-v1-priority-fee-at-cap.txt b/harness/vectors/annotated/batch-txv1-top-up-v1-priority-fee-at-cap.txt index cf422c1d8..ac69e737b 100644 --- a/harness/vectors/annotated/batch-txv1-top-up-v1-priority-fee-at-cap.txt +++ b/harness/vectors/annotated/batch-txv1-top-up-v1-priority-fee-at-cap.txt @@ -8,6 +8,8 @@ payment header (base64 JSON) "asset": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", "extra": { "feePayer": "J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf", + "maxClaimChannels": 18, + "maxSettleChannels": 13, "memo": "invoice-42", "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", "tokenProgram": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", @@ -35,7 +37,7 @@ payment header (base64 JSON) }, "deposit": { "amount": "6000", - "transaction": "gQIABA8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIJ/RckOFqgx1tk+3jNYC+h2ZH96/drE8WO1wLqyDXp9hjqSmxj4pxSCr71UHsTLsX5lUd2rr6+e5JCHuppFEbSLBLpNiunJD3KvxKSvUdldArM8IOOcMbn/NGbf2SxXiMea4T+VAWZkKbqIwjcZYhVrZWKZR4UVyYj9/rTk9uwE+z4qYJbWO8tXMd0MeH5xi0Nf6UmH4u3+Idtnx6JoNkrIAVKU1qZKSEGTSTocWDaOHx8NbXdvJK7geQfqEBBBUSNBt324ddloZPZy+FGzut5rBy0he1fWzeROoz1hX7/AKk7RCyzkSFX8TqTPQE0KC0DK1/+zQGi2/G3eQYI3wAup6eh+6TrKwkJk/fS39YrieK4cgd6Y5/X10eo6Z9j1BWuQEIPAAAAAABADQMAAAAABAgGCQAFAAoAAQQDAgcGA3AXAAAAAAAAaW52b2ljZS00MgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA08/hj5yslYv9++MmG85bG/9bajC8CQQ5a0VH4w0SPJuWnmEVOWIlHtx0P5nHMYw/ZXBbZJsB2hIVi0qIe3q0I" + "transaction": "gQIABA8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIJ/RckOFqgx1tk+3jNYC+h2ZH96/drE8WO1wLqyDXp9hjqSmxj4pxSCr71UHsTLsX5lUd2rr6+e5JCHuppFEbSLBLpNiunJD3KvxKSvUdldArM8IOOcMbn/NGbf2SxXiMea4T+VAWZkKbqIwjcZYhVrZWKZR4UVyYj9/rTk9uwE+z4qYJbWO8tXMd0MeH5xi0Nf6UmH4u3+Idtnx6JoNkrIAVKU1qZKSEGTSTocWDaOHx8NbXdvJK7geQfqEBBBUSNBt324ddloZPZy+FGzut5rBy0he1fWzeROoz1hX7/AKk7RCyzkSFX8TqTPQE0KC0DK1/+zQGi2/G3eQYI3wAup6eh+6TrKwkJk/fS39YrieK4cgd6Y5/X10eo6Z9j1BWu3AUAAAAAAAAsAQAAAAAABAgGCQAFAAoAAQQDAgcGA3AXAAAAAAAAaW52b2ljZS00MgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA82oAfUP6t8tQlVyWAQKaZa/+ExOJ7uWa2fDzLUXUtLKrJXiz6qNxlytIsH8bOT9WGKv6rcb86QRerxLCEXF4D" }, "transaction": "", "type": "deposit", diff --git a/harness/vectors/annotated/batch-txv1-top-up-v1-priority-fee-over-cap-reject.txt b/harness/vectors/annotated/batch-txv1-top-up-v1-priority-fee-over-cap-reject.txt index 00e759080..24b34dc6c 100644 --- a/harness/vectors/annotated/batch-txv1-top-up-v1-priority-fee-over-cap-reject.txt +++ b/harness/vectors/annotated/batch-txv1-top-up-v1-priority-fee-over-cap-reject.txt @@ -8,6 +8,8 @@ payment header (base64 JSON) "asset": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", "extra": { "feePayer": "J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf", + "maxClaimChannels": 18, + "maxSettleChannels": 13, "memo": "invoice-42", "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", "tokenProgram": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", @@ -35,7 +37,7 @@ payment header (base64 JSON) }, "deposit": { "amount": "6000", - "transaction": "gQIABA8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIJ/RckOFqgx1tk+3jNYC+h2ZH96/drE8WO1wLqyDXp9hjqSmxj4pxSCr71UHsTLsX5lUd2rr6+e5JCHuppFEbSLBLpNiunJD3KvxKSvUdldArM8IOOcMbn/NGbf2SxXiMea4T+VAWZkKbqIwjcZYhVrZWKZR4UVyYj9/rTk9uwE+z4qYJbWO8tXMd0MeH5xi0Nf6UmH4u3+Idtnx6JoNkrIAVKU1qZKSEGTSTocWDaOHx8NbXdvJK7geQfqEBBBUSNBt324ddloZPZy+FGzut5rBy0he1fWzeROoz1hX7/AKk7RCyzkSFX8TqTPQE0KC0DK1/+zQGi2/G3eQYI3wAup6eh+6TrKwkJk/fS39YrieK4cgd6Y5/X10eo6Z9j1BWuQUIPAAAAAABADQMAAAAABAgGCQAFAAoAAQQDAgcGA3AXAAAAAAAAaW52b2ljZS00MgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACJPodhRikhY4LEBl93zGhjHE3jkh2fxgINYJyU+pniirom8dXt+006KiPGnSJN+poq0auB/BrscPHGowcKCkoD" + "transaction": "gQIABA8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIJ/RckOFqgx1tk+3jNYC+h2ZH96/drE8WO1wLqyDXp9hjqSmxj4pxSCr71UHsTLsX5lUd2rr6+e5JCHuppFEbSLBLpNiunJD3KvxKSvUdldArM8IOOcMbn/NGbf2SxXiMea4T+VAWZkKbqIwjcZYhVrZWKZR4UVyYj9/rTk9uwE+z4qYJbWO8tXMd0MeH5xi0Nf6UmH4u3+Idtnx6JoNkrIAVKU1qZKSEGTSTocWDaOHx8NbXdvJK7geQfqEBBBUSNBt324ddloZPZy+FGzut5rBy0he1fWzeROoz1hX7/AKk7RCyzkSFX8TqTPQE0KC0DK1/+zQGi2/G3eQYI3wAup6eh+6TrKwkJk/fS39YrieK4cgd6Y5/X10eo6Z9j1BWu3QUAAAAAAAAsAQAAAAAABAgGCQAFAAoAAQQDAgcGA3AXAAAAAAAAaW52b2ljZS00MgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACd1hCEv9V1EQ9cFuqef/0QJq5Wm03Xc6SDEcDNbTgZ4QiG/QVmbr0F92MJlbhhdd1Fd3vuRjQmJp3w+0kANcIP" }, "transaction": "", "type": "deposit", diff --git a/harness/vectors/annotated/batch-txv1-top-up-v1-priority-fee-over-sponsor-cap-reject.txt b/harness/vectors/annotated/batch-txv1-top-up-v1-priority-fee-over-sponsor-cap-reject.txt new file mode 100644 index 000000000..286051fab --- /dev/null +++ b/harness/vectors/annotated/batch-txv1-top-up-v1-priority-fee-over-sponsor-cap-reject.txt @@ -0,0 +1,53 @@ +# batch-txv1-top-up-v1-priority-fee-over-sponsor-cap-reject (x402-batch-settlement verify-transaction, expect reject) +# generated by pkc fill; do not edit + +payment header (base64 JSON) +{ + "accepted": { + "amount": "1000", + "asset": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "extra": { + "feePayer": "J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf", + "maxClaimChannels": 18, + "maxSettleChannels": 13, + "memo": "invoice-42", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "tokenProgram": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "transactionVersions": [ + 0, + 1 + ], + "withdrawDelay": 3600 + }, + "maxTimeoutSeconds": 300, + "network": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "payTo": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "scheme": "batch-settlement" + }, + "payload": { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "42", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "deposit": { + "amount": "6000", + "transaction": "gQIABA8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIJ/RckOFqgx1tk+3jNYC+h2ZH96/drE8WO1wLqyDXp9hjqSmxj4pxSCr71UHsTLsX5lUd2rr6+e5JCHuppFEbSLBLpNiunJD3KvxKSvUdldArM8IOOcMbn/NGbf2SxXiMea4T+VAWZkKbqIwjcZYhVrZWKZR4UVyYj9/rTk9uwE+z4qYJbWO8tXMd0MeH5xi0Nf6UmH4u3+Idtnx6JoNkrIAVKU1qZKSEGTSTocWDaOHx8NbXdvJK7geQfqEBBBUSNBt324ddloZPZy+FGzut5rBy0he1fWzeROoz1hX7/AKk7RCyzkSFX8TqTPQE0KC0DK1/+zQGi2/G3eQYI3wAup6eh+6TrKwkJk/fS39YrieK4cgd6Y5/X10eo6Z9j1BWu0QcAAAAAAABADQMAAAAABAgGCQAFAAoAAQQDAgcGA3AXAAAAAAAAaW52b2ljZS00MgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJvfC0vQK4xloC9ljQm24MGCITeWYtZ8CnrnMqf7nkg39pmvJoOZPwJntL58jAHvZS14eBH4tDT05I2lMYXNwD" + }, + "transaction": "", + "type": "deposit", + "voucher": { + "channelId": "Hjg2PDgLxYDiQWRHrJeeY9V9iNyebM9MWutoA67eivsZ", + "expiresAt": 0, + "maxClaimableAmount": "4000", + "signature": "3WYNjcmhd4sXonxQPrBqrFbsVt9JogFStoASpj4o1LTnLxi9He4b4e8tHjsuCtMCWBPktoRfzGXxHSfJ9uYgaXDR" + } + }, + "x402Version": 2 +} + diff --git a/harness/vectors/annotated/batch-txv1-top-up-v1-unit-limit-over-cap-reject.txt b/harness/vectors/annotated/batch-txv1-top-up-v1-unit-limit-over-cap-reject.txt index f44079382..9f5f80bc7 100644 --- a/harness/vectors/annotated/batch-txv1-top-up-v1-unit-limit-over-cap-reject.txt +++ b/harness/vectors/annotated/batch-txv1-top-up-v1-unit-limit-over-cap-reject.txt @@ -8,6 +8,8 @@ payment header (base64 JSON) "asset": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", "extra": { "feePayer": "J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf", + "maxClaimChannels": 18, + "maxSettleChannels": 13, "memo": "invoice-42", "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", "tokenProgram": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", diff --git a/harness/vectors/annotated/batch-verify-open-unfunded-payer-reject.txt b/harness/vectors/annotated/batch-verify-open-unfunded-payer-reject.txt new file mode 100644 index 000000000..8a86b8b5a --- /dev/null +++ b/harness/vectors/annotated/batch-verify-open-unfunded-payer-reject.txt @@ -0,0 +1,47 @@ +# batch-verify-open-unfunded-payer-reject (x402-batch-settlement verify-transaction, expect reject) +# generated by pkc fill; do not edit + +payment header (base64 JSON) +{ + "accepted": { + "amount": "1000", + "asset": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "extra": { + "feePayer": "J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf", + "memo": "invoice-42", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "tokenProgram": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "withdrawDelay": 3600 + }, + "maxTimeoutSeconds": 300, + "network": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "payTo": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "scheme": "batch-settlement" + }, + "payload": { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "42", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "deposit": { + "amount": "10000", + "transaction": "AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABX7uj8xzwiqVsetaSzL7qB9S4DGswA0XQDzg002r06bFlLS9iSIpfJ0xXK6gDKPm/qMir2e2iiHId0ZnerMlwGgAIACA39FyQ4WqDHW2T7eM1gL6HZkf3r92sTxY7XAurINen2GOpKbGPinFIKvvVQexMuxfmVR3auvr57kkIe6mkURtIsEuk2K6ckPcq/EpK9R2V0Cszwg45wxuf80Zt/ZLFeIx5rhP5UBZmQpuojCNxliFWtlYplHhRXJiP3+tOT27AT7PipgltY7y1cx3Qx4fnGLQ1/pSYfi7f4h22fHomg2SsgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFSlNamSkhBk0k6HFg2jh8fDW13bySu4HkH6hAQQVEjQan1RcZLFxRIYzJTD1K8X9Y2u4Im6H9ROPb2YoAAAAABt324ddloZPZy+FGzut5rBy0he1fWzeROoz1hX7/AKk7RCyzkSFX8TqTPQE0KC0DK1/+zQGi2/G3eQYI3wAup1pUDXtrHisrtRdSGcmj8GAQkkHKjE8XDMHKLUju6vnQjJclj04kifG7PRApFI4NgwtaE5na/xCEBI572Nvp+Fmnofuk6ysJCZP30t/WK4niuHIHemOf19dHqOmfY9QVrgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwwOAQAACQEEAwIIBQcLCgxDASoAAAAAAAAAECcAAAAAAAAQDgAAQD9TFAAAAAABAAAAq04rMx5LTzoVQrrg+VXdXTMDScdOoccKkgXsBlUJIjMQJwYACmludm9pY2UtNDIGAFF4NDAyOmJhdGNoLXNldHRsZW1lbnQ6c3ZtOnJjdmF1dGg6djE6QW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MA" + }, + "transaction": "", + "type": "deposit", + "voucher": { + "channelId": "Hjg2PDgLxYDiQWRHrJeeY9V9iNyebM9MWutoA67eivsZ", + "expiresAt": 0, + "maxClaimableAmount": "1000", + "signature": "5kSviFQ8hjmQpK8sRmgHD6FxbELADzWzf6MqCG8ubWHatG4SXYV1brk9bQJQtXe8qBtfZbPZzmCHbkt7eJmEddBB" + } + }, + "x402Version": 2 +} + diff --git a/harness/vectors/annotated/batch-verify-top-up-compute-budget-prefix.txt b/harness/vectors/annotated/batch-verify-top-up-compute-budget-prefix.txt index 0f8f4d102..2daf49013 100644 --- a/harness/vectors/annotated/batch-verify-top-up-compute-budget-prefix.txt +++ b/harness/vectors/annotated/batch-verify-top-up-compute-budget-prefix.txt @@ -31,7 +31,7 @@ payment header (base64 JSON) }, "deposit": { "amount": "6000", - "transaction": "AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABElladfJFcf0y7dkj4Ke8PIxZ2rvq+TvYxGDhA1fiQYjOLMCQ2YMgrnzlJrwUEM4dvo65sJCRiAGg9hzUlsP4OgAIABQr9FyQ4WqDHW2T7eM1gL6HZkf3r92sTxY7XAurINen2GOpKbGPinFIKvvVQexMuxfmVR3auvr57kkIe6mkURtIsEuk2K6ckPcq/EpK9R2V0Cszwg45wxuf80Zt/ZLFeIx5rhP5UBZmQpuojCNxliFWtlYplHhRXJiP3+tOT27AT7PipgltY7y1cx3Qx4fnGLQ1/pSYfi7f4h22fHomg2SsgAwZGb+UhFzL/7K26csOb57yM5bvF9xJrLEObOkAAAAAFSlNamSkhBk0k6HFg2jh8fDW13bySu4HkH6hAQQVEjQbd9uHXZaGT2cvhRs7reawctIXtX1s3kTqM9YV+/wCpO0Qss5EhV/E6kz0BNCgtAytf/s0Botvxt3kGCN8ALqenofuk6ysJCZP30t/WK4niuHIHemOf19dHqOmfY9QVrgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAUABQKAGgYABQAJA0BLTAAAAAAACQYBBAMCCAcJA3AXAAAAAAAABgAKaW52b2ljZS00MgA=" + "transaction": "AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAbMsz3/1r/vuBj7FPVQc74hT+YXULuWaa819aAiELB6b3fCD+CiqbpDkkEXzGSk/0Tx7q89zuqYNCqxSN3R4NgAIABQr9FyQ4WqDHW2T7eM1gL6HZkf3r92sTxY7XAurINen2GOpKbGPinFIKvvVQexMuxfmVR3auvr57kkIe6mkURtIsEuk2K6ckPcq/EpK9R2V0Cszwg45wxuf80Zt/ZLFeIx5rhP5UBZmQpuojCNxliFWtlYplHhRXJiP3+tOT27AT7PipgltY7y1cx3Qx4fnGLQ1/pSYfi7f4h22fHomg2SsgAwZGb+UhFzL/7K26csOb57yM5bvF9xJrLEObOkAAAAAFSlNamSkhBk0k6HFg2jh8fDW13bySu4HkH6hAQQVEjQbd9uHXZaGT2cvhRs7reawctIXtX1s3kTqM9YV+/wCpO0Qss5EhV/E6kz0BNCgtAytf/s0Botvxt3kGCN8ALqenofuk6ysJCZP30t/WK4niuHIHemOf19dHqOmfY9QVrgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAUABQKAGgYABQAJA4gTAAAAAAAACQYBBAMCCAcJA3AXAAAAAAAABgAKaW52b2ljZS00MgA=" }, "transaction": "", "type": "deposit", diff --git a/harness/vectors/annotated/batch-verify-top-up-implicit-limit-priority-fee-over-cap-reject.txt b/harness/vectors/annotated/batch-verify-top-up-implicit-limit-priority-fee-over-cap-reject.txt new file mode 100644 index 000000000..419297ff2 --- /dev/null +++ b/harness/vectors/annotated/batch-verify-top-up-implicit-limit-priority-fee-over-cap-reject.txt @@ -0,0 +1,47 @@ +# batch-verify-top-up-implicit-limit-priority-fee-over-cap-reject (x402-batch-settlement verify-transaction, expect reject) +# generated by pkc fill; do not edit + +payment header (base64 JSON) +{ + "accepted": { + "amount": "1000", + "asset": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "extra": { + "feePayer": "J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf", + "memo": "invoice-42", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "tokenProgram": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "withdrawDelay": 3600 + }, + "maxTimeoutSeconds": 300, + "network": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "payTo": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "scheme": "batch-settlement" + }, + "payload": { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "42", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "deposit": { + "amount": "6000", + "transaction": "AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgorU7XPirvNxB8h1YsYOLc5STSKljTU0asU5SiLIz52k3HdUX4omACLgYBZULeReyTCyu4BrjJqX7PhgYddAMgAIABQr9FyQ4WqDHW2T7eM1gL6HZkf3r92sTxY7XAurINen2GOpKbGPinFIKvvVQexMuxfmVR3auvr57kkIe6mkURtIsEuk2K6ckPcq/EpK9R2V0Cszwg45wxuf80Zt/ZLFeIx5rhP5UBZmQpuojCNxliFWtlYplHhRXJiP3+tOT27AT7PipgltY7y1cx3Qx4fnGLQ1/pSYfi7f4h22fHomg2SsgAwZGb+UhFzL/7K26csOb57yM5bvF9xJrLEObOkAAAAAFSlNamSkhBk0k6HFg2jh8fDW13bySu4HkH6hAQQVEjQbd9uHXZaGT2cvhRs7reawctIXtX1s3kTqM9YV+/wCpO0Qss5EhV/E6kz0BNCgtAytf/s0Botvxt3kGCN8ALqenofuk6ysJCZP30t/WK4niuHIHemOf19dHqOmfY9QVrgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwUACQOJEwAAAAAAAAkGAQQDAggHCQNwFwAAAAAAAAYACmludm9pY2UtNDIA" + }, + "transaction": "", + "type": "deposit", + "voucher": { + "channelId": "Hjg2PDgLxYDiQWRHrJeeY9V9iNyebM9MWutoA67eivsZ", + "expiresAt": 0, + "maxClaimableAmount": "4000", + "signature": "3WYNjcmhd4sXonxQPrBqrFbsVt9JogFStoASpj4o1LTnLxi9He4b4e8tHjsuCtMCWBPktoRfzGXxHSfJ9uYgaXDR" + } + }, + "x402Version": 2 +} + diff --git a/harness/vectors/annotated/batch-verify-top-up-priority-fee-over-cap-reject.txt b/harness/vectors/annotated/batch-verify-top-up-priority-fee-over-cap-reject.txt new file mode 100644 index 000000000..08e1976b3 --- /dev/null +++ b/harness/vectors/annotated/batch-verify-top-up-priority-fee-over-cap-reject.txt @@ -0,0 +1,47 @@ +# batch-verify-top-up-priority-fee-over-cap-reject (x402-batch-settlement verify-transaction, expect reject) +# generated by pkc fill; do not edit + +payment header (base64 JSON) +{ + "accepted": { + "amount": "1000", + "asset": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "extra": { + "feePayer": "J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf", + "memo": "invoice-42", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "tokenProgram": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "withdrawDelay": 3600 + }, + "maxTimeoutSeconds": 300, + "network": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "payTo": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "scheme": "batch-settlement" + }, + "payload": { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "42", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "deposit": { + "amount": "6000", + "transaction": "AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABElladfJFcf0y7dkj4Ke8PIxZ2rvq+TvYxGDhA1fiQYjOLMCQ2YMgrnzlJrwUEM4dvo65sJCRiAGg9hzUlsP4OgAIABQr9FyQ4WqDHW2T7eM1gL6HZkf3r92sTxY7XAurINen2GOpKbGPinFIKvvVQexMuxfmVR3auvr57kkIe6mkURtIsEuk2K6ckPcq/EpK9R2V0Cszwg45wxuf80Zt/ZLFeIx5rhP5UBZmQpuojCNxliFWtlYplHhRXJiP3+tOT27AT7PipgltY7y1cx3Qx4fnGLQ1/pSYfi7f4h22fHomg2SsgAwZGb+UhFzL/7K26csOb57yM5bvF9xJrLEObOkAAAAAFSlNamSkhBk0k6HFg2jh8fDW13bySu4HkH6hAQQVEjQbd9uHXZaGT2cvhRs7reawctIXtX1s3kTqM9YV+/wCpO0Qss5EhV/E6kz0BNCgtAytf/s0Botvxt3kGCN8ALqenofuk6ysJCZP30t/WK4niuHIHemOf19dHqOmfY9QVrgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAUABQKAGgYABQAJA0BLTAAAAAAACQYBBAMCCAcJA3AXAAAAAAAABgAKaW52b2ljZS00MgA=" + }, + "transaction": "", + "type": "deposit", + "voucher": { + "channelId": "Hjg2PDgLxYDiQWRHrJeeY9V9iNyebM9MWutoA67eivsZ", + "expiresAt": 0, + "maxClaimableAmount": "4000", + "signature": "3WYNjcmhd4sXonxQPrBqrFbsVt9JogFStoASpj4o1LTnLxi9He4b4e8tHjsuCtMCWBPktoRfzGXxHSfJ9uYgaXDR" + } + }, + "x402Version": 2 +} + diff --git a/harness/vectors/annotated/batch-verify-top-up-unfunded-payer-reject.txt b/harness/vectors/annotated/batch-verify-top-up-unfunded-payer-reject.txt new file mode 100644 index 000000000..a21608fd3 --- /dev/null +++ b/harness/vectors/annotated/batch-verify-top-up-unfunded-payer-reject.txt @@ -0,0 +1,47 @@ +# batch-verify-top-up-unfunded-payer-reject (x402-batch-settlement verify-transaction, expect reject) +# generated by pkc fill; do not edit + +payment header (base64 JSON) +{ + "accepted": { + "amount": "1000", + "asset": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "extra": { + "feePayer": "J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf", + "memo": "invoice-42", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "tokenProgram": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "withdrawDelay": 3600 + }, + "maxTimeoutSeconds": 300, + "network": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "payTo": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "scheme": "batch-settlement" + }, + "payload": { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "42", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "deposit": { + "amount": "6000", + "transaction": "AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJz9Ahi2a6U4iQkrx8eX+yDiVVCWrVckrjwV6cgWKcxKFcHE5Xa4nguvtAqR0eHaiFw1IctI/VP6u/lVZw5oQJgAIABAn9FyQ4WqDHW2T7eM1gL6HZkf3r92sTxY7XAurINen2GOpKbGPinFIKvvVQexMuxfmVR3auvr57kkIe6mkURtIsEuk2K6ckPcq/EpK9R2V0Cszwg45wxuf80Zt/ZLFeIx5rhP5UBZmQpuojCNxliFWtlYplHhRXJiP3+tOT27AT7PipgltY7y1cx3Qx4fnGLQ1/pSYfi7f4h22fHomg2SsgBUpTWpkpIQZNJOhxYNo4fHw1td28kruB5B+oQEEFRI0G3fbh12Whk9nL4UbO63msHLSF7V9bN5E6jPWFfv8AqTtELLORIVfxOpM9ATQoLQMrX/7NAaLb8bd5BgjfAC6np6H7pOsrCQmT99Lf1iuJ4rhyB3pjn9fXR6jpn2PUFa4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIIBgEEAwIHBgkDcBcAAAAAAAAFAAppbnZvaWNlLTQyAA==" + }, + "transaction": "", + "type": "deposit", + "voucher": { + "channelId": "Hjg2PDgLxYDiQWRHrJeeY9V9iNyebM9MWutoA67eivsZ", + "expiresAt": 0, + "maxClaimableAmount": "4000", + "signature": "3WYNjcmhd4sXonxQPrBqrFbsVt9JogFStoASpj4o1LTnLxi9He4b4e8tHjsuCtMCWBPktoRfzGXxHSfJ9uYgaXDR" + } + }, + "x402Version": 2 +} + diff --git a/harness/vectors/annotated/batch-verify-voucher-receiver-quotes-a-code-reject.txt b/harness/vectors/annotated/batch-verify-voucher-receiver-quotes-a-code-reject.txt new file mode 100644 index 000000000..7a3112fce --- /dev/null +++ b/harness/vectors/annotated/batch-verify-voucher-receiver-quotes-a-code-reject.txt @@ -0,0 +1,43 @@ +# batch-verify-voucher-receiver-quotes-a-code-reject (x402-batch-settlement verify-transaction, expect reject) +# generated by pkc fill; do not edit + +payment header (base64 JSON) +{ + "accepted": { + "amount": "1000", + "asset": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "extra": { + "feePayer": "J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf", + "memo": "invoice-42", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "tokenProgram": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "withdrawDelay": 3600 + }, + "maxTimeoutSeconds": 300, + "network": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "payTo": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "scheme": "batch-settlement" + }, + "payload": { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "invalid_batch_settlement_svm_cumulative_amount_mismatch", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "42", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "transaction": "", + "type": "voucher", + "voucher": { + "channelId": "Hjg2PDgLxYDiQWRHrJeeY9V9iNyebM9MWutoA67eivsZ", + "expiresAt": 0, + "maxClaimableAmount": "4000", + "signature": "3WYNjcmhd4sXonxQPrBqrFbsVt9JogFStoASpj4o1LTnLxi9He4b4e8tHjsuCtMCWBPktoRfzGXxHSfJ9uYgaXDR" + } + }, + "x402Version": 2 +} + diff --git a/harness/vectors/annotated/batch-wire-redemption-claim-eighteen-entries.txt b/harness/vectors/annotated/batch-wire-redemption-claim-eighteen-entries.txt new file mode 100644 index 000000000..b530fff2e --- /dev/null +++ b/harness/vectors/annotated/batch-wire-redemption-claim-eighteen-entries.txt @@ -0,0 +1,5 @@ +# batch-wire-redemption-claim-eighteen-entries (x402-batch-settlement canonical-bytes, expect accept) +# generated by pkc fill; do not edit + + canonicalJson (11745 bytes) {"claims":[{"channelConfig":{"openSlot":341000000,"payer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","payerAuthorizer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","receiver":"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY","receiverAuthorizer":"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os","salt":"100","token":"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU","withdrawDelay":3600},"channelId":"Br4wUi9TpNTB7wL9BXoCqKAaHhLVAiiiaWbxve2og5DM","voucher":{"channelId":"Br4wUi9TpNTB7wL9BXoCqKAaHhLVAiiiaWbxve2og5DM","expiresAt":0,"maxClaimableAmount":"1000","signature":"5webiD4DbhJpjGjToBLXPonCCcDp5jK6KvJaG6y9LZj8RFsuxUgfeH5FLUKfZwxCkhc2qpxn9d9noyNxpwe5vhWo"}},{"channelConfig":{"openSlot":341000000,"payer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","payerAuthorizer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","receiver":"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY","receiverAuthorizer":"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os","salt":"101","token":"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU","withdrawDelay":3600},"channelId":"96wiMpqdLQvBK2vTHw2ALnzKjoXeHPe9UHL8GPM6VBH3","voucher":{"channelId":"96wiMpqdLQvBK2vTHw2ALnzKjoXeHPe9UHL8GPM6VBH3","expiresAt":0,"maxClaimableAmount":"1000","signature":"23ed7u1sWVL67DgP2XS5S6a8QNSNDNjx46N3WrDjQcYMkdTKwJxSovjLvESREwinqaX7qFGwZiH4KhX8whvKdyrm"}},{"channelConfig":{"openSlot":341000000,"payer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","payerAuthorizer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","receiver":"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY","receiverAuthorizer":"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os","salt":"102","token":"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU","withdrawDelay":3600},"channelId":"918ujLxiyqZA2WmxznvtHsEk31nDmPr6Gs8nA73oY2yn","voucher":{"channelId":"918ujLxiyqZA2WmxznvtHsEk31nDmPr6Gs8nA73oY2yn","expiresAt":0,"maxClaimableAmount":"1000","signature":"5M1EwT6SshyUKRhv6qKfSjk7qjjsw7rqZ1q1bjfpHnfqAUm6PUdzxMVspDQX1ptvQwjdwB4xd6xdpKJ9QC8gksdJ"}},{"channelConfig":{"openSlot":341000000,"payer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","payerAuthorizer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","receiver":"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY","receiverAuthorizer":"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os","salt":"103","token":"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU","withdrawDelay":3600},"channelId":"27P2VM5swSSRGK83AqMhGNg9ZfTNVXtx74MkKevV8PpH","voucher":{"channelId":"27P2VM5swSSRGK83AqMhGNg9ZfTNVXtx74MkKevV8PpH","expiresAt":0,"maxClaimableAmount":"1000","signature":"2yyjqaHsdiBKKHvjR8vdqqHeQ36AFruuGdsazmDBMEbtPiXjbDqA3q6s9FyugebWpzMWResiLPcNfkUBX2onVdyQ"}},{"channelConfig":{"openSlot":341000000,"payer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","payerAuthorizer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","receiver":"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY","receiverAuthorizer":"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os","salt":"104","token":"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU","withdrawDelay":3600},"channelId":"BJtkqYs9cWfuyP1x9VGsdU2bmjQYTr2sDzPE1Wq6vFXs","voucher":{"channelId":"BJtkqYs9cWfuyP1x9VGsdU2bmjQYTr2sDzPE1Wq6vFXs","expiresAt":0,"maxClaimableAmount":"1000","signature":"53JvbdCtBUmDgVwdPDbvwyWXMtXaZBvXR7uUsQq8EPLYtmB8HFSadt7LdhqJ2oGwS4iCcYm1WdCBu3PTU47YDR4h"}},{"channelConfig":{"openSlot":341000000,"payer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","payerAuthorizer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","receiver":"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY","receiverAuthorizer":"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os","salt":"105","token":"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU","withdrawDelay":3600},"channelId":"4ANNVYxLfjNvjgR6kqD7W7waAfNGZQ3izAqrPuonvswN","voucher":{"channelId":"4ANNVYxLfjNvjgR6kqD7W7waAfNGZQ3izAqrPuonvswN","expiresAt":0,"maxClaimableAmount":"1000","signature":"5M3HkGtcYhugcEhwguEn3kMuk3oP1tCeL1iUKXcFjr5V2E5e2QrK48rz7eEfZK66yo44gCGEEPPCC1W3VRzkqGK9"}},{"channelConfig":{"openSlot":341000000,"payer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","payerAuthorizer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","receiver":"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY","receiverAuthorizer":"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os","salt":"106","token":"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU","withdrawDelay":3600},"channelId":"4q9jEnqAMp8hvBisuXh9HuitWBHRNKthHmdJ1bhBy7pN","voucher":{"channelId":"4q9jEnqAMp8hvBisuXh9HuitWBHRNKthHmdJ1bhBy7pN","expiresAt":0,"maxClaimableAmount":"1000","signature":"2GiPnYGRk8fjqRf4TnpiXU3xV1HyrSfyKgQ2JXJVKK3R68ahvdfU11Frcc5HM2SeSLPrHDrZdnaXL9et1hwHvQtt"}},{"channelConfig":{"openSlot":341000000,"payer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","payerAuthorizer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","receiver":"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY","receiverAuthorizer":"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os","salt":"107","token":"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU","withdrawDelay":3600},"channelId":"8F5xwzrKcgrMKLaTYGcKMZdcuDhiq7PxSGnHuWt6Md9F","voucher":{"channelId":"8F5xwzrKcgrMKLaTYGcKMZdcuDhiq7PxSGnHuWt6Md9F","expiresAt":0,"maxClaimableAmount":"1000","signature":"2NHpct6EYtPLcX7pvV9CG6aB3tWuW9kpn9JDqPkiHZYZvfZUaUCmqxWzYSnRg5ZNCTUzSsXcvnRMDyLaoKRUWje4"}},{"channelConfig":{"openSlot":341000000,"payer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","payerAuthorizer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","receiver":"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY","receiverAuthorizer":"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os","salt":"108","token":"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU","withdrawDelay":3600},"channelId":"GUNsKpc5ybB7tj7SUF8UasuByHS7Sxs3aptt5eRicATC","voucher":{"channelId":"GUNsKpc5ybB7tj7SUF8UasuByHS7Sxs3aptt5eRicATC","expiresAt":0,"maxClaimableAmount":"1000","signature":"2aF1Rda2h8ecvpj6Dg99rBXd3Z1TAKtkoq8LPnwRw4UMbTYuqhVHjUn6hrPbnuzQTQiUj4VvEwTu813eu7dyzCh3"}},{"channelConfig":{"openSlot":341000000,"payer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","payerAuthorizer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","receiver":"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY","receiverAuthorizer":"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os","salt":"109","token":"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU","withdrawDelay":3600},"channelId":"Fmw75DJk8fi8i6yjf3HA9oyxjz5QL6gs8SRXYV4hkxQ3","voucher":{"channelId":"Fmw75DJk8fi8i6yjf3HA9oyxjz5QL6gs8SRXYV4hkxQ3","expiresAt":0,"maxClaimableAmount":"1000","signature":"5LEJTzesUtMgvaY25KSUo1TAQPQeht7RBpqYRyEc1vRijHDzv2P2tCYAXKqKVU7ke8RZuMmxcpajLAXXcqWWZCqe"}},{"channelConfig":{"openSlot":341000000,"payer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","payerAuthorizer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","receiver":"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY","receiverAuthorizer":"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os","salt":"110","token":"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU","withdrawDelay":3600},"channelId":"Bpd4syvg5BSByt7xXbNVSztCpgwHsCDrzSm54pm49VjQ","voucher":{"channelId":"Bpd4syvg5BSByt7xXbNVSztCpgwHsCDrzSm54pm49VjQ","expiresAt":0,"maxClaimableAmount":"1000","signature":"5ju5RhAzvKY9v1tub5tUR5aBcBRJjioyfeoJqXSo6WEd1ywCc1nw7tPpdAdJCjc4K4s9XFZPH9P6U2FCJH8WuDC7"}},{"channelConfig":{"openSlot":341000000,"payer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","payerAuthorizer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","receiver":"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY","receiverAuthorizer":"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os","salt":"111","token":"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU","withdrawDelay":3600},"channelId":"EMJFPxSkCK8QztvKAjPniNbgevAu3Tcx8WpqDhw3zHxE","voucher":{"channelId":"EMJFPxSkCK8QztvKAjPniNbgevAu3Tcx8WpqDhw3zHxE","expiresAt":0,"maxClaimableAmount":"1000","signature":"57r7o5SRxtLsJr9wMj8wEhB74inVaJFwVAqEqAqY6qqqtFZmpWprUE3CdBBjiCZym6Zb6jjsZB4iL5uyNtSHod9U"}},{"channelConfig":{"openSlot":341000000,"payer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","payerAuthorizer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","receiver":"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY","receiverAuthorizer":"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os","salt":"112","token":"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU","withdrawDelay":3600},"channelId":"9ZZL2NSCaoQRmKqBJjtC5AyhuongALRcpiKi8oP5fZ3t","voucher":{"channelId":"9ZZL2NSCaoQRmKqBJjtC5AyhuongALRcpiKi8oP5fZ3t","expiresAt":0,"maxClaimableAmount":"1000","signature":"3Dr3f4jFaMRQr8CW52yjNwsUMYekoaRXsWd93rmtsgo5Q7kGFKsEt5bLKDdjw53LS9G2SeCvVtbJKnyFdGxgHe4H"}},{"channelConfig":{"openSlot":341000000,"payer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","payerAuthorizer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","receiver":"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY","receiverAuthorizer":"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os","salt":"113","token":"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU","withdrawDelay":3600},"channelId":"3bqqR4WnvtTMJxbChKYJHTktHyakzyUvYZbDEytT8umV","voucher":{"channelId":"3bqqR4WnvtTMJxbChKYJHTktHyakzyUvYZbDEytT8umV","expiresAt":0,"maxClaimableAmount":"1000","signature":"3GULYmEqbBEXVNVPvhUAnKG9MHon55ktkBAGCixUSLwKdoKP1CMDRtWiCyXN963LHzmBQ4V4nxUWfJGPQgYoq8qi"}},{"channelConfig":{"openSlot":341000000,"payer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","payerAuthorizer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","receiver":"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY","receiverAuthorizer":"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os","salt":"114","token":"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU","withdrawDelay":3600},"channelId":"AzABWhvJfRpZu9cPfoAGkfSgA7n6CLN7L1Tsz4kSsPtA","voucher":{"channelId":"AzABWhvJfRpZu9cPfoAGkfSgA7n6CLN7L1Tsz4kSsPtA","expiresAt":0,"maxClaimableAmount":"1000","signature":"2CW2iPoeJx3EdeEgJ68bREhKhVRfGcyrbsQ9LWWoKM4sSLSF2Gm3y7BK2CaGRy9hX58QD7Rdi1pUM9Zv6sX24vQR"}},{"channelConfig":{"openSlot":341000000,"payer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","payerAuthorizer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","receiver":"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY","receiverAuthorizer":"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os","salt":"115","token":"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU","withdrawDelay":3600},"channelId":"6GwxXVRNTRG1rMnvCs4Agy5Tw24Ag7JnPgZo5zDP6acv","voucher":{"channelId":"6GwxXVRNTRG1rMnvCs4Agy5Tw24Ag7JnPgZo5zDP6acv","expiresAt":0,"maxClaimableAmount":"1000","signature":"37HNwRRV62mnVBg1X3F7T4pumj1B74i5Tz8YzXjvwEy6oU6ccxiawySDNi8Ezz9cCTyyZHkWJ7J4beaXhC6JKYbt"}},{"channelConfig":{"openSlot":341000000,"payer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","payerAuthorizer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","receiver":"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY","receiverAuthorizer":"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os","salt":"116","token":"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU","withdrawDelay":3600},"channelId":"BhgXfPYvNtMZFhrKF3MpatXjVMM9KmppZgBugyfVWsmY","voucher":{"channelId":"BhgXfPYvNtMZFhrKF3MpatXjVMM9KmppZgBugyfVWsmY","expiresAt":0,"maxClaimableAmount":"1000","signature":"5CzWp2MfYojT83Tu19vdpY6MuTFW9g5Vpha25N8u1Rw561xADeaoRcEK6fevHbo35ybACn3iT9xXf7xqRuiKKwSw"}},{"channelConfig":{"openSlot":341000000,"payer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","payerAuthorizer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","receiver":"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY","receiverAuthorizer":"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os","salt":"117","token":"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU","withdrawDelay":3600},"channelId":"F2cTdjHc7JAfCogJzxiz2YiTsvtG4k55qvLewHRP6wvW","voucher":{"channelId":"F2cTdjHc7JAfCogJzxiz2YiTsvtG4k55qvLewHRP6wvW","expiresAt":0,"maxClaimableAmount":"1000","signature":"2KpMKJ4doNJrtVkkRmxFTrn7BUGcRX8a2F5oSX5pN2GfUUWW9XNueUdycYMLMoi9tYopn1iqnQfJ77oQzCqPsquM"}}],"type":"claim"} + base64Url (15660 chars) eyJjbGFpbXMiOlt7ImNoYW5uZWxDb25maWciOnsib3BlblNsb3QiOjM0MTAwMDAwMCwicGF5ZXIiOiJHbWFEcnBwQkM3UDVBUktWOGczZGppd1A4OXZ6MWpMSzIzVjJHQmp1QUVHQiIsInBheWVyQXV0aG9yaXplciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicmVjZWl2ZXIiOiJDWGhyRlpKTEtxanptUDNzallMY0Y0ZFRlWFdLQ3k5ZTJTWFhaMllvNk1QWSIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwic2FsdCI6IjEwMCIsInRva2VuIjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwiY2hhbm5lbElkIjoiQnI0d1VpOVRwTlRCN3dMOUJYb0NxS0FhSGhMVkFpaWlhV2J4dmUyb2c1RE0iLCJ2b3VjaGVyIjp7ImNoYW5uZWxJZCI6IkJyNHdVaTlUcE5UQjd3TDlCWG9DcUtBYUhoTFZBaWlpYVdieHZlMm9nNURNIiwiZXhwaXJlc0F0IjowLCJtYXhDbGFpbWFibGVBbW91bnQiOiIxMDAwIiwic2lnbmF0dXJlIjoiNXdlYmlENERiaEpwakdqVG9CTFhQb25DQ2NEcDVqSzZLdkphRzZ5OUxaajhSRnN1eFVnZmVINUZMVUtmWnd4Q2toYzJxcHhuOWQ5bm95Tnhwd2U1dmhXbyJ9fSx7ImNoYW5uZWxDb25maWciOnsib3BlblNsb3QiOjM0MTAwMDAwMCwicGF5ZXIiOiJHbWFEcnBwQkM3UDVBUktWOGczZGppd1A4OXZ6MWpMSzIzVjJHQmp1QUVHQiIsInBheWVyQXV0aG9yaXplciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicmVjZWl2ZXIiOiJDWGhyRlpKTEtxanptUDNzallMY0Y0ZFRlWFdLQ3k5ZTJTWFhaMllvNk1QWSIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwic2FsdCI6IjEwMSIsInRva2VuIjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwiY2hhbm5lbElkIjoiOTZ3aU1wcWRMUXZCSzJ2VEh3MkFMbnpLam9YZUhQZTlVSEw4R1BNNlZCSDMiLCJ2b3VjaGVyIjp7ImNoYW5uZWxJZCI6Ijk2d2lNcHFkTFF2QksydlRIdzJBTG56S2pvWGVIUGU5VUhMOEdQTTZWQkgzIiwiZXhwaXJlc0F0IjowLCJtYXhDbGFpbWFibGVBbW91bnQiOiIxMDAwIiwic2lnbmF0dXJlIjoiMjNlZDd1MXNXVkw2N0RnUDJYUzVTNmE4UU5TTkROang0Nk4zV3JEalFjWU1rZFRLd0p4U292akx2RVNSRXdpbnFhWDdxRkd3WmlINEtoWDh3aHZLZHlybSJ9fSx7ImNoYW5uZWxDb25maWciOnsib3BlblNsb3QiOjM0MTAwMDAwMCwicGF5ZXIiOiJHbWFEcnBwQkM3UDVBUktWOGczZGppd1A4OXZ6MWpMSzIzVjJHQmp1QUVHQiIsInBheWVyQXV0aG9yaXplciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicmVjZWl2ZXIiOiJDWGhyRlpKTEtxanptUDNzallMY0Y0ZFRlWFdLQ3k5ZTJTWFhaMllvNk1QWSIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwic2FsdCI6IjEwMiIsInRva2VuIjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwiY2hhbm5lbElkIjoiOTE4dWpMeGl5cVpBMldteHpudnRIc0VrMzFuRG1QcjZHczhuQTczb1kyeW4iLCJ2b3VjaGVyIjp7ImNoYW5uZWxJZCI6IjkxOHVqTHhpeXFaQTJXbXh6bnZ0SHNFazMxbkRtUHI2R3M4bkE3M29ZMnluIiwiZXhwaXJlc0F0IjowLCJtYXhDbGFpbWFibGVBbW91bnQiOiIxMDAwIiwic2lnbmF0dXJlIjoiNU0xRXdUNlNzaHlVS1JodjZxS2ZTams3cWpqc3c3cnFaMXExYmpmcEhuZnFBVW02UFVkenhNVnNwRFFYMXB0dlF3amR3QjR4ZDZ4ZHBLSjlRQzhna3NkSiJ9fSx7ImNoYW5uZWxDb25maWciOnsib3BlblNsb3QiOjM0MTAwMDAwMCwicGF5ZXIiOiJHbWFEcnBwQkM3UDVBUktWOGczZGppd1A4OXZ6MWpMSzIzVjJHQmp1QUVHQiIsInBheWVyQXV0aG9yaXplciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicmVjZWl2ZXIiOiJDWGhyRlpKTEtxanptUDNzallMY0Y0ZFRlWFdLQ3k5ZTJTWFhaMllvNk1QWSIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwic2FsdCI6IjEwMyIsInRva2VuIjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwiY2hhbm5lbElkIjoiMjdQMlZNNXN3U1NSR0s4M0FxTWhHTmc5WmZUTlZYdHg3NE1rS2V2VjhQcEgiLCJ2b3VjaGVyIjp7ImNoYW5uZWxJZCI6IjI3UDJWTTVzd1NTUkdLODNBcU1oR05nOVpmVE5WWHR4NzRNa0tldlY4UHBIIiwiZXhwaXJlc0F0IjowLCJtYXhDbGFpbWFibGVBbW91bnQiOiIxMDAwIiwic2lnbmF0dXJlIjoiMnl5anFhSHNkaUJLS0h2alI4dmRxcUhlUTM2QUZydXVHZHNhem1EQk1FYnRQaVhqYkRxQTNxNnM5Rnl1Z2ViV3B6TVdSZXNpTFBjTmZrVUJYMm9uVmR5USJ9fSx7ImNoYW5uZWxDb25maWciOnsib3BlblNsb3QiOjM0MTAwMDAwMCwicGF5ZXIiOiJHbWFEcnBwQkM3UDVBUktWOGczZGppd1A4OXZ6MWpMSzIzVjJHQmp1QUVHQiIsInBheWVyQXV0aG9yaXplciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicmVjZWl2ZXIiOiJDWGhyRlpKTEtxanptUDNzallMY0Y0ZFRlWFdLQ3k5ZTJTWFhaMllvNk1QWSIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwic2FsdCI6IjEwNCIsInRva2VuIjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwiY2hhbm5lbElkIjoiQkp0a3FZczljV2Z1eVAxeDlWR3NkVTJibWpRWVRyMnNEelBFMVdxNnZGWHMiLCJ2b3VjaGVyIjp7ImNoYW5uZWxJZCI6IkJKdGtxWXM5Y1dmdXlQMXg5VkdzZFUyYm1qUVlUcjJzRHpQRTFXcTZ2RlhzIiwiZXhwaXJlc0F0IjowLCJtYXhDbGFpbWFibGVBbW91bnQiOiIxMDAwIiwic2lnbmF0dXJlIjoiNTNKdmJkQ3RCVW1EZ1Z3ZFBEYnZ3eVdYTXRYYVpCdlhSN3VVc1FxOEVQTFl0bUI4SEZTYWR0N0xkaHFKMm9Hd1M0aUNjWW0xV2RDQnUzUFRVNDdZRFI0aCJ9fSx7ImNoYW5uZWxDb25maWciOnsib3BlblNsb3QiOjM0MTAwMDAwMCwicGF5ZXIiOiJHbWFEcnBwQkM3UDVBUktWOGczZGppd1A4OXZ6MWpMSzIzVjJHQmp1QUVHQiIsInBheWVyQXV0aG9yaXplciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicmVjZWl2ZXIiOiJDWGhyRlpKTEtxanptUDNzallMY0Y0ZFRlWFdLQ3k5ZTJTWFhaMllvNk1QWSIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwic2FsdCI6IjEwNSIsInRva2VuIjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwiY2hhbm5lbElkIjoiNEFOTlZZeExmak52amdSNmtxRDdXN3dhQWZOR1pRM2l6QXFyUHVvbnZzd04iLCJ2b3VjaGVyIjp7ImNoYW5uZWxJZCI6IjRBTk5WWXhMZmpOdmpnUjZrcUQ3Vzd3YUFmTkdaUTNpekFxclB1b252c3dOIiwiZXhwaXJlc0F0IjowLCJtYXhDbGFpbWFibGVBbW91bnQiOiIxMDAwIiwic2lnbmF0dXJlIjoiNU0zSGtHdGNZaHVnY0Vod2d1RW4za011azNvUDF0Q2VMMWlVS1hjRmpyNVYyRTVlMlFySzQ4cno3ZUVmWks2NnlvNDRnQ0dFRVBQQ0MxVzNWUnprcUdLOSJ9fSx7ImNoYW5uZWxDb25maWciOnsib3BlblNsb3QiOjM0MTAwMDAwMCwicGF5ZXIiOiJHbWFEcnBwQkM3UDVBUktWOGczZGppd1A4OXZ6MWpMSzIzVjJHQmp1QUVHQiIsInBheWVyQXV0aG9yaXplciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicmVjZWl2ZXIiOiJDWGhyRlpKTEtxanptUDNzallMY0Y0ZFRlWFdLQ3k5ZTJTWFhaMllvNk1QWSIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwic2FsdCI6IjEwNiIsInRva2VuIjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwiY2hhbm5lbElkIjoiNHE5akVucUFNcDhodkJpc3VYaDlIdWl0V0JIUk5LdGhIbWRKMWJoQnk3cE4iLCJ2b3VjaGVyIjp7ImNoYW5uZWxJZCI6IjRxOWpFbnFBTXA4aHZCaXN1WGg5SHVpdFdCSFJOS3RoSG1kSjFiaEJ5N3BOIiwiZXhwaXJlc0F0IjowLCJtYXhDbGFpbWFibGVBbW91bnQiOiIxMDAwIiwic2lnbmF0dXJlIjoiMkdpUG5ZR1JrOGZqcVJmNFRucGlYVTN4VjFIeXJTZnlLZ1EySlhKVktLM1I2OGFodmRmVTExRnJjYzVITTJTZVNMUHJIRHJaZG5hWEw5ZXQxaHdIdlF0dCJ9fSx7ImNoYW5uZWxDb25maWciOnsib3BlblNsb3QiOjM0MTAwMDAwMCwicGF5ZXIiOiJHbWFEcnBwQkM3UDVBUktWOGczZGppd1A4OXZ6MWpMSzIzVjJHQmp1QUVHQiIsInBheWVyQXV0aG9yaXplciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicmVjZWl2ZXIiOiJDWGhyRlpKTEtxanptUDNzallMY0Y0ZFRlWFdLQ3k5ZTJTWFhaMllvNk1QWSIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwic2FsdCI6IjEwNyIsInRva2VuIjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwiY2hhbm5lbElkIjoiOEY1eHd6cktjZ3JNS0xhVFlHY0tNWmRjdURoaXE3UHhTR25IdVd0Nk1kOUYiLCJ2b3VjaGVyIjp7ImNoYW5uZWxJZCI6IjhGNXh3enJLY2dyTUtMYVRZR2NLTVpkY3VEaGlxN1B4U0duSHVXdDZNZDlGIiwiZXhwaXJlc0F0IjowLCJtYXhDbGFpbWFibGVBbW91bnQiOiIxMDAwIiwic2lnbmF0dXJlIjoiMk5IcGN0NkVZdFBMY1g3cHZWOUNHNmFCM3RXdVc5a3BuOUpEcVBraUhaWVp2ZlpVYVVDbXF4V3pZU25SZzVaTkNUVXpTc1hjdm5STUR5TGFvS1JVV2plNCJ9fSx7ImNoYW5uZWxDb25maWciOnsib3BlblNsb3QiOjM0MTAwMDAwMCwicGF5ZXIiOiJHbWFEcnBwQkM3UDVBUktWOGczZGppd1A4OXZ6MWpMSzIzVjJHQmp1QUVHQiIsInBheWVyQXV0aG9yaXplciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicmVjZWl2ZXIiOiJDWGhyRlpKTEtxanptUDNzallMY0Y0ZFRlWFdLQ3k5ZTJTWFhaMllvNk1QWSIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwic2FsdCI6IjEwOCIsInRva2VuIjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwiY2hhbm5lbElkIjoiR1VOc0twYzV5YkI3dGo3U1VGOFVhc3VCeUhTN1N4czNhcHR0NWVSaWNBVEMiLCJ2b3VjaGVyIjp7ImNoYW5uZWxJZCI6IkdVTnNLcGM1eWJCN3RqN1NVRjhVYXN1QnlIUzdTeHMzYXB0dDVlUmljQVRDIiwiZXhwaXJlc0F0IjowLCJtYXhDbGFpbWFibGVBbW91bnQiOiIxMDAwIiwic2lnbmF0dXJlIjoiMmFGMVJkYTJoOGVjdnBqNkRnOTlyQlhkM1oxVEFLdGtvcThMUG53Unc0VU1iVFl1cWhWSGpVbjZoclBibnV6UVRRaVVqNFZ2RXdUdTgxM2V1N2R5ekNoMyJ9fSx7ImNoYW5uZWxDb25maWciOnsib3BlblNsb3QiOjM0MTAwMDAwMCwicGF5ZXIiOiJHbWFEcnBwQkM3UDVBUktWOGczZGppd1A4OXZ6MWpMSzIzVjJHQmp1QUVHQiIsInBheWVyQXV0aG9yaXplciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicmVjZWl2ZXIiOiJDWGhyRlpKTEtxanptUDNzallMY0Y0ZFRlWFdLQ3k5ZTJTWFhaMllvNk1QWSIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwic2FsdCI6IjEwOSIsInRva2VuIjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwiY2hhbm5lbElkIjoiRm13NzVESms4Zmk4aTZ5amYzSEE5b3l4ano1UUw2Z3M4U1JYWVY0aGt4UTMiLCJ2b3VjaGVyIjp7ImNoYW5uZWxJZCI6IkZtdzc1REprOGZpOGk2eWpmM0hBOW95eGp6NVFMNmdzOFNSWFlWNGhreFEzIiwiZXhwaXJlc0F0IjowLCJtYXhDbGFpbWFibGVBbW91bnQiOiIxMDAwIiwic2lnbmF0dXJlIjoiNUxFSlR6ZXNVdE1ndmFZMjVLU1VvMVRBUVBRZWh0N1JCcHFZUnlFYzF2UmlqSER6djJQMnRDWUFYS3FLVlU3a2U4Ulp1TW14Y3BhakxBWFhjcVdXWkNxZSJ9fSx7ImNoYW5uZWxDb25maWciOnsib3BlblNsb3QiOjM0MTAwMDAwMCwicGF5ZXIiOiJHbWFEcnBwQkM3UDVBUktWOGczZGppd1A4OXZ6MWpMSzIzVjJHQmp1QUVHQiIsInBheWVyQXV0aG9yaXplciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicmVjZWl2ZXIiOiJDWGhyRlpKTEtxanptUDNzallMY0Y0ZFRlWFdLQ3k5ZTJTWFhaMllvNk1QWSIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwic2FsdCI6IjExMCIsInRva2VuIjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwiY2hhbm5lbElkIjoiQnBkNHN5dmc1QlNCeXQ3eFhiTlZTenRDcGd3SHNDRHJ6U201NHBtNDlWalEiLCJ2b3VjaGVyIjp7ImNoYW5uZWxJZCI6IkJwZDRzeXZnNUJTQnl0N3hYYk5WU3p0Q3Bnd0hzQ0RyelNtNTRwbTQ5VmpRIiwiZXhwaXJlc0F0IjowLCJtYXhDbGFpbWFibGVBbW91bnQiOiIxMDAwIiwic2lnbmF0dXJlIjoiNWp1NVJoQXp2S1k5djF0dWI1dFVSNWFCY0JSSmppb3lmZW9KcVhTbzZXRWQxeXdDYzFudzd0UHBkQWRKQ2pjNEs0czlYRlpQSDlQNlUyRkNKSDhXdURDNyJ9fSx7ImNoYW5uZWxDb25maWciOnsib3BlblNsb3QiOjM0MTAwMDAwMCwicGF5ZXIiOiJHbWFEcnBwQkM3UDVBUktWOGczZGppd1A4OXZ6MWpMSzIzVjJHQmp1QUVHQiIsInBheWVyQXV0aG9yaXplciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicmVjZWl2ZXIiOiJDWGhyRlpKTEtxanptUDNzallMY0Y0ZFRlWFdLQ3k5ZTJTWFhaMllvNk1QWSIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwic2FsdCI6IjExMSIsInRva2VuIjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwiY2hhbm5lbElkIjoiRU1KRlB4U2tDSzhRenR2S0FqUG5pTmJnZXZBdTNUY3g4V3BxRGh3M3pIeEUiLCJ2b3VjaGVyIjp7ImNoYW5uZWxJZCI6IkVNSkZQeFNrQ0s4UXp0dktBalBuaU5iZ2V2QXUzVGN4OFdwcURodzN6SHhFIiwiZXhwaXJlc0F0IjowLCJtYXhDbGFpbWFibGVBbW91bnQiOiIxMDAwIiwic2lnbmF0dXJlIjoiNTdyN281U1J4dExzSnI5d01qOHdFaEI3NGluVmFKRndWQXFFcUFxWTZxcXF0RlptcFdwclVFM0NkQkJqaUNaeW02WmI2ampzWkI0aUw1dXlOdFNIb2Q5VSJ9fSx7ImNoYW5uZWxDb25maWciOnsib3BlblNsb3QiOjM0MTAwMDAwMCwicGF5ZXIiOiJHbWFEcnBwQkM3UDVBUktWOGczZGppd1A4OXZ6MWpMSzIzVjJHQmp1QUVHQiIsInBheWVyQXV0aG9yaXplciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicmVjZWl2ZXIiOiJDWGhyRlpKTEtxanptUDNzallMY0Y0ZFRlWFdLQ3k5ZTJTWFhaMllvNk1QWSIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwic2FsdCI6IjExMiIsInRva2VuIjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwiY2hhbm5lbElkIjoiOVpaTDJOU0Nhb1FSbUtxQkpqdEM1QXlodW9uZ0FMUmNwaUtpOG9QNWZaM3QiLCJ2b3VjaGVyIjp7ImNoYW5uZWxJZCI6IjlaWkwyTlNDYW9RUm1LcUJKanRDNUF5aHVvbmdBTFJjcGlLaThvUDVmWjN0IiwiZXhwaXJlc0F0IjowLCJtYXhDbGFpbWFibGVBbW91bnQiOiIxMDAwIiwic2lnbmF0dXJlIjoiM0RyM2Y0akZhTVJRcjhDVzUyeWpOd3NVTVlla29hUlhzV2Q5M3JtdHNnbzVRN2tHRktzRXQ1YkxLRGRqdzUzTFM5RzJTZUN2VnRiSktueUZkR3hnSGU0SCJ9fSx7ImNoYW5uZWxDb25maWciOnsib3BlblNsb3QiOjM0MTAwMDAwMCwicGF5ZXIiOiJHbWFEcnBwQkM3UDVBUktWOGczZGppd1A4OXZ6MWpMSzIzVjJHQmp1QUVHQiIsInBheWVyQXV0aG9yaXplciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicmVjZWl2ZXIiOiJDWGhyRlpKTEtxanptUDNzallMY0Y0ZFRlWFdLQ3k5ZTJTWFhaMllvNk1QWSIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwic2FsdCI6IjExMyIsInRva2VuIjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwiY2hhbm5lbElkIjoiM2JxcVI0V252dFRNSnhiQ2hLWUpIVGt0SHlha3p5VXZZWmJERXl0VDh1bVYiLCJ2b3VjaGVyIjp7ImNoYW5uZWxJZCI6IjNicXFSNFdudnRUTUp4YkNoS1lKSFRrdEh5YWt6eVV2WVpiREV5dFQ4dW1WIiwiZXhwaXJlc0F0IjowLCJtYXhDbGFpbWFibGVBbW91bnQiOiIxMDAwIiwic2lnbmF0dXJlIjoiM0dVTFltRXFiQkVYVk5WUHZoVUFuS0c5TUhvbjU1a3RrQkFHQ2l4VVNMd0tkb0tQMUNNRFJ0V2lDeVhOOTYzTEh6bUJRNFY0bnhVV2ZKR1BRZ1lvcThxaSJ9fSx7ImNoYW5uZWxDb25maWciOnsib3BlblNsb3QiOjM0MTAwMDAwMCwicGF5ZXIiOiJHbWFEcnBwQkM3UDVBUktWOGczZGppd1A4OXZ6MWpMSzIzVjJHQmp1QUVHQiIsInBheWVyQXV0aG9yaXplciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicmVjZWl2ZXIiOiJDWGhyRlpKTEtxanptUDNzallMY0Y0ZFRlWFdLQ3k5ZTJTWFhaMllvNk1QWSIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwic2FsdCI6IjExNCIsInRva2VuIjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwiY2hhbm5lbElkIjoiQXpBQldodkpmUnBadTljUGZvQUdrZlNnQTduNkNMTjdMMVRzejRrU3NQdEEiLCJ2b3VjaGVyIjp7ImNoYW5uZWxJZCI6IkF6QUJXaHZKZlJwWnU5Y1Bmb0FHa2ZTZ0E3bjZDTE43TDFUc3o0a1NzUHRBIiwiZXhwaXJlc0F0IjowLCJtYXhDbGFpbWFibGVBbW91bnQiOiIxMDAwIiwic2lnbmF0dXJlIjoiMkNXMmlQb2VKeDNFZGVFZ0o2OGJSRWhLaFZSZkdjeXJic1E5TFdXb0tNNHNTTFNGMkdtM3k3QksyQ2FHUnk5aFg1OFFEN1JkaTFwVU05WnY2c1gyNHZRUiJ9fSx7ImNoYW5uZWxDb25maWciOnsib3BlblNsb3QiOjM0MTAwMDAwMCwicGF5ZXIiOiJHbWFEcnBwQkM3UDVBUktWOGczZGppd1A4OXZ6MWpMSzIzVjJHQmp1QUVHQiIsInBheWVyQXV0aG9yaXplciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicmVjZWl2ZXIiOiJDWGhyRlpKTEtxanptUDNzallMY0Y0ZFRlWFdLQ3k5ZTJTWFhaMllvNk1QWSIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwic2FsdCI6IjExNSIsInRva2VuIjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwiY2hhbm5lbElkIjoiNkd3eFhWUk5UUkcxck1udkNzNEFneTVUdzI0QWc3Sm5QZ1pvNXpEUDZhY3YiLCJ2b3VjaGVyIjp7ImNoYW5uZWxJZCI6IjZHd3hYVlJOVFJHMXJNbnZDczRBZ3k1VHcyNEFnN0puUGdabzV6RFA2YWN2IiwiZXhwaXJlc0F0IjowLCJtYXhDbGFpbWFibGVBbW91bnQiOiIxMDAwIiwic2lnbmF0dXJlIjoiMzdITndSUlY2Mm1uVkJnMVgzRjdUNHB1bWoxQjc0aTVUejhZelhqdndFeTZvVTZjY3hpYXd5U0ROaThFeno5Y0NUeXlaSGtXSjdKNGJlYVhoQzZKS1lidCJ9fSx7ImNoYW5uZWxDb25maWciOnsib3BlblNsb3QiOjM0MTAwMDAwMCwicGF5ZXIiOiJHbWFEcnBwQkM3UDVBUktWOGczZGppd1A4OXZ6MWpMSzIzVjJHQmp1QUVHQiIsInBheWVyQXV0aG9yaXplciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicmVjZWl2ZXIiOiJDWGhyRlpKTEtxanptUDNzallMY0Y0ZFRlWFdLQ3k5ZTJTWFhaMllvNk1QWSIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwic2FsdCI6IjExNiIsInRva2VuIjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwiY2hhbm5lbElkIjoiQmhnWGZQWXZOdE1aRmhyS0YzTXBhdFhqVk1NOUttcHBaZ0J1Z3lmVldzbVkiLCJ2b3VjaGVyIjp7ImNoYW5uZWxJZCI6IkJoZ1hmUFl2TnRNWkZocktGM01wYXRYalZNTTlLbXBwWmdCdWd5ZlZXc21ZIiwiZXhwaXJlc0F0IjowLCJtYXhDbGFpbWFibGVBbW91bnQiOiIxMDAwIiwic2lnbmF0dXJlIjoiNUN6V3AyTWZZb2pUODNUdTE5dmRwWTZNdVRGVzlnNVZwaGEyNU44dTFSdzU2MXhBRGVhb1JjRUs2ZmV2SGJvMzV5YkFDbjNpVDl4WGY3eHFSdWlLS3dTdyJ9fSx7ImNoYW5uZWxDb25maWciOnsib3BlblNsb3QiOjM0MTAwMDAwMCwicGF5ZXIiOiJHbWFEcnBwQkM3UDVBUktWOGczZGppd1A4OXZ6MWpMSzIzVjJHQmp1QUVHQiIsInBheWVyQXV0aG9yaXplciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicmVjZWl2ZXIiOiJDWGhyRlpKTEtxanptUDNzallMY0Y0ZFRlWFdLQ3k5ZTJTWFhaMllvNk1QWSIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwic2FsdCI6IjExNyIsInRva2VuIjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwiY2hhbm5lbElkIjoiRjJjVGRqSGM3SkFmQ29nSnp4aXoyWWlUc3Z0RzRrNTVxdkxld0hSUDZ3dlciLCJ2b3VjaGVyIjp7ImNoYW5uZWxJZCI6IkYyY1RkakhjN0pBZkNvZ0p6eGl6MllpVHN2dEc0azU1cXZMZXdIUlA2d3ZXIiwiZXhwaXJlc0F0IjowLCJtYXhDbGFpbWFibGVBbW91bnQiOiIxMDAwIiwic2lnbmF0dXJlIjoiMktwTUtKNGRvTkpydFZra1JteEZUcm43QlVHY1JYOGEyRjVvU1g1cE4yR2ZVVVdXOVhOdWVVZHljWU1MTW9pOXRZb3BuMWlxblFmSjc3b1F6Q3FQc3F1TSJ9fV0sInR5cGUiOiJjbGFpbSJ9 diff --git a/harness/vectors/annotated/batch-wire-redemption-claim-five-entries-reject.txt b/harness/vectors/annotated/batch-wire-redemption-claim-five-entries-reject.txt deleted file mode 100644 index 1992bc0e1..000000000 --- a/harness/vectors/annotated/batch-wire-redemption-claim-five-entries-reject.txt +++ /dev/null @@ -1,3 +0,0 @@ -# batch-wire-redemption-claim-five-entries-reject (x402-batch-settlement canonical-bytes, expect reject) -# generated by pkc fill; do not edit - diff --git a/harness/vectors/annotated/batch-wire-redemption-claim-nineteen-entries-reject.txt b/harness/vectors/annotated/batch-wire-redemption-claim-nineteen-entries-reject.txt new file mode 100644 index 000000000..1448426b0 --- /dev/null +++ b/harness/vectors/annotated/batch-wire-redemption-claim-nineteen-entries-reject.txt @@ -0,0 +1,3 @@ +# batch-wire-redemption-claim-nineteen-entries-reject (x402-batch-settlement canonical-bytes, expect reject) +# generated by pkc fill; do not edit + diff --git a/harness/vectors/annotated/batch-wire-redemption-settle-fourteen-channels-reject.txt b/harness/vectors/annotated/batch-wire-redemption-settle-fourteen-channels-reject.txt new file mode 100644 index 000000000..cfc087526 --- /dev/null +++ b/harness/vectors/annotated/batch-wire-redemption-settle-fourteen-channels-reject.txt @@ -0,0 +1,3 @@ +# batch-wire-redemption-settle-fourteen-channels-reject (x402-batch-settlement canonical-bytes, expect reject) +# generated by pkc fill; do not edit + diff --git a/harness/vectors/annotated/batch-wire-redemption-settle-thirteen-channels.txt b/harness/vectors/annotated/batch-wire-redemption-settle-thirteen-channels.txt new file mode 100644 index 000000000..afc8eabb9 --- /dev/null +++ b/harness/vectors/annotated/batch-wire-redemption-settle-thirteen-channels.txt @@ -0,0 +1,5 @@ +# batch-wire-redemption-settle-thirteen-channels (x402-batch-settlement canonical-bytes, expect accept) +# generated by pkc fill; do not edit + + canonicalJson (5685 bytes) {"channels":[{"channelConfig":{"openSlot":341000000,"payer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","payerAuthorizer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","receiver":"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY","receiverAuthorizer":"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os","salt":"200","token":"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU","withdrawDelay":3600},"channelId":"CKksPyLk4CiewPo7a3XeSLT67sRwsnwXg79RrpSs2KPw"},{"channelConfig":{"openSlot":341000000,"payer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","payerAuthorizer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","receiver":"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY","receiverAuthorizer":"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os","salt":"201","token":"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU","withdrawDelay":3600},"channelId":"6CJAudALg2pEfuNU86wbewVmSQ1SbbqgxAbKyuyoqoZZ"},{"channelConfig":{"openSlot":341000000,"payer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","payerAuthorizer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","receiver":"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY","receiverAuthorizer":"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os","salt":"202","token":"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU","withdrawDelay":3600},"channelId":"5sPNJYZc5djn9Pt7s2fXjwzmNRCVTrStfUnymhT1wnJd"},{"channelConfig":{"openSlot":341000000,"payer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","payerAuthorizer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","receiver":"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY","receiverAuthorizer":"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os","salt":"203","token":"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU","withdrawDelay":3600},"channelId":"7wyGAu8UXQap8WhjUP7j3pTTQ371NbdT6qMUPtezsZa7"},{"channelConfig":{"openSlot":341000000,"payer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","payerAuthorizer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","receiver":"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY","receiverAuthorizer":"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os","salt":"204","token":"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU","withdrawDelay":3600},"channelId":"37j8xzib7vzqcuZ92iPQ6e4b78tn9km77Ce2Bep56fD4"},{"channelConfig":{"openSlot":341000000,"payer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","payerAuthorizer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","receiver":"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY","receiverAuthorizer":"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os","salt":"205","token":"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU","withdrawDelay":3600},"channelId":"3ECV7Q7eAtmXH9NBK4KiN8EKogkYWa4HmVrMkpbZj6rj"},{"channelConfig":{"openSlot":341000000,"payer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","payerAuthorizer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","receiver":"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY","receiverAuthorizer":"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os","salt":"206","token":"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU","withdrawDelay":3600},"channelId":"ApAcndckB7RHy3H6tRUS4vByUouCVKaevUqzGdVUuGFf"},{"channelConfig":{"openSlot":341000000,"payer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","payerAuthorizer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","receiver":"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY","receiverAuthorizer":"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os","salt":"207","token":"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU","withdrawDelay":3600},"channelId":"HGANnRDTeGCP7adfdPrshqRPpY4DruJmNW1edZVmL19A"},{"channelConfig":{"openSlot":341000000,"payer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","payerAuthorizer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","receiver":"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY","receiverAuthorizer":"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os","salt":"208","token":"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU","withdrawDelay":3600},"channelId":"Gt4MVUCG393EQ3rg4PqbNXN488sEteZHEH8T9iSfz5bz"},{"channelConfig":{"openSlot":341000000,"payer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","payerAuthorizer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","receiver":"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY","receiverAuthorizer":"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os","salt":"209","token":"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU","withdrawDelay":3600},"channelId":"Ftv6JqPjkLqkrYvLsUbKRN5ohDdC3AFS9FycPWb4bxfm"},{"channelConfig":{"openSlot":341000000,"payer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","payerAuthorizer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","receiver":"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY","receiverAuthorizer":"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os","salt":"210","token":"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU","withdrawDelay":3600},"channelId":"EoqfLABd1Pzcv1G4NnmXkxALWPeqQw7caTLr5kV7Q48g"},{"channelConfig":{"openSlot":341000000,"payer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","payerAuthorizer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","receiver":"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY","receiverAuthorizer":"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os","salt":"211","token":"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU","withdrawDelay":3600},"channelId":"E5tAKx8Xsf7U8ezYyGe1fH63k6qiFnrzgePm3d6XzPeo"},{"channelConfig":{"openSlot":341000000,"payer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","payerAuthorizer":"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB","receiver":"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY","receiverAuthorizer":"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os","salt":"212","token":"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU","withdrawDelay":3600},"channelId":"2w4mLaE3eXLKp46FZWAQvqb2iUgHBWN889BxJqa7aqaS"}],"type":"settle"} + base64Url (7580 chars) eyJjaGFubmVscyI6W3siY2hhbm5lbENvbmZpZyI6eyJvcGVuU2xvdCI6MzQxMDAwMDAwLCJwYXllciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicGF5ZXJBdXRob3JpemVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJyZWNlaXZlciI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwicmVjZWl2ZXJBdXRob3JpemVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJzYWx0IjoiMjAwIiwidG9rZW4iOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsIndpdGhkcmF3RGVsYXkiOjM2MDB9LCJjaGFubmVsSWQiOiJDS2tzUHlMazRDaWV3UG83YTNYZVNMVDY3c1J3c253WGc3OVJycFNzMktQdyJ9LHsiY2hhbm5lbENvbmZpZyI6eyJvcGVuU2xvdCI6MzQxMDAwMDAwLCJwYXllciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicGF5ZXJBdXRob3JpemVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJyZWNlaXZlciI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwicmVjZWl2ZXJBdXRob3JpemVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJzYWx0IjoiMjAxIiwidG9rZW4iOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsIndpdGhkcmF3RGVsYXkiOjM2MDB9LCJjaGFubmVsSWQiOiI2Q0pBdWRBTGcycEVmdU5VODZ3YmV3Vm1TUTFTYmJxZ3hBYkt5dXlvcW9aWiJ9LHsiY2hhbm5lbENvbmZpZyI6eyJvcGVuU2xvdCI6MzQxMDAwMDAwLCJwYXllciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicGF5ZXJBdXRob3JpemVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJyZWNlaXZlciI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwicmVjZWl2ZXJBdXRob3JpemVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJzYWx0IjoiMjAyIiwidG9rZW4iOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsIndpdGhkcmF3RGVsYXkiOjM2MDB9LCJjaGFubmVsSWQiOiI1c1BOSllaYzVkam45UHQ3czJmWGp3em1OUkNWVHJTdGZVbnltaFQxd25KZCJ9LHsiY2hhbm5lbENvbmZpZyI6eyJvcGVuU2xvdCI6MzQxMDAwMDAwLCJwYXllciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicGF5ZXJBdXRob3JpemVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJyZWNlaXZlciI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwicmVjZWl2ZXJBdXRob3JpemVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJzYWx0IjoiMjAzIiwidG9rZW4iOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsIndpdGhkcmF3RGVsYXkiOjM2MDB9LCJjaGFubmVsSWQiOiI3d3lHQXU4VVhRYXA4V2hqVVA3ajNwVFRRMzcxTmJkVDZxTVVQdGV6c1phNyJ9LHsiY2hhbm5lbENvbmZpZyI6eyJvcGVuU2xvdCI6MzQxMDAwMDAwLCJwYXllciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicGF5ZXJBdXRob3JpemVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJyZWNlaXZlciI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwicmVjZWl2ZXJBdXRob3JpemVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJzYWx0IjoiMjA0IiwidG9rZW4iOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsIndpdGhkcmF3RGVsYXkiOjM2MDB9LCJjaGFubmVsSWQiOiIzN2o4eHppYjd2enFjdVo5MmlQUTZlNGI3OHRuOWttNzdDZTJCZXA1NmZENCJ9LHsiY2hhbm5lbENvbmZpZyI6eyJvcGVuU2xvdCI6MzQxMDAwMDAwLCJwYXllciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicGF5ZXJBdXRob3JpemVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJyZWNlaXZlciI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwicmVjZWl2ZXJBdXRob3JpemVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJzYWx0IjoiMjA1IiwidG9rZW4iOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsIndpdGhkcmF3RGVsYXkiOjM2MDB9LCJjaGFubmVsSWQiOiIzRUNWN1E3ZUF0bVhIOU5CSzRLaU44RUtvZ2tZV2E0SG1Wck1rcGJaajZyaiJ9LHsiY2hhbm5lbENvbmZpZyI6eyJvcGVuU2xvdCI6MzQxMDAwMDAwLCJwYXllciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicGF5ZXJBdXRob3JpemVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJyZWNlaXZlciI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwicmVjZWl2ZXJBdXRob3JpemVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJzYWx0IjoiMjA2IiwidG9rZW4iOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsIndpdGhkcmF3RGVsYXkiOjM2MDB9LCJjaGFubmVsSWQiOiJBcEFjbmRja0I3Ukh5M0g2dFJVUzR2QnlVb3VDVkthZXZVcXpHZFZVdUdGZiJ9LHsiY2hhbm5lbENvbmZpZyI6eyJvcGVuU2xvdCI6MzQxMDAwMDAwLCJwYXllciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicGF5ZXJBdXRob3JpemVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJyZWNlaXZlciI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwicmVjZWl2ZXJBdXRob3JpemVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJzYWx0IjoiMjA3IiwidG9rZW4iOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsIndpdGhkcmF3RGVsYXkiOjM2MDB9LCJjaGFubmVsSWQiOiJIR0FOblJEVGVHQ1A3YWRmZFByc2hxUlBwWTREcnVKbU5XMWVkWlZtTDE5QSJ9LHsiY2hhbm5lbENvbmZpZyI6eyJvcGVuU2xvdCI6MzQxMDAwMDAwLCJwYXllciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicGF5ZXJBdXRob3JpemVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJyZWNlaXZlciI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwicmVjZWl2ZXJBdXRob3JpemVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJzYWx0IjoiMjA4IiwidG9rZW4iOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsIndpdGhkcmF3RGVsYXkiOjM2MDB9LCJjaGFubmVsSWQiOiJHdDRNVlVDRzM5M0VRM3JnNFBxYk5YTjQ4OHNFdGVaSEVIOFQ5aVNmejVieiJ9LHsiY2hhbm5lbENvbmZpZyI6eyJvcGVuU2xvdCI6MzQxMDAwMDAwLCJwYXllciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicGF5ZXJBdXRob3JpemVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJyZWNlaXZlciI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwicmVjZWl2ZXJBdXRob3JpemVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJzYWx0IjoiMjA5IiwidG9rZW4iOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsIndpdGhkcmF3RGVsYXkiOjM2MDB9LCJjaGFubmVsSWQiOiJGdHY2SnFQamtMcWtyWXZMc1ViS1JONW9oRGRDM0FGUzlGeWNQV2I0YnhmbSJ9LHsiY2hhbm5lbENvbmZpZyI6eyJvcGVuU2xvdCI6MzQxMDAwMDAwLCJwYXllciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicGF5ZXJBdXRob3JpemVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJyZWNlaXZlciI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwicmVjZWl2ZXJBdXRob3JpemVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJzYWx0IjoiMjEwIiwidG9rZW4iOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsIndpdGhkcmF3RGVsYXkiOjM2MDB9LCJjaGFubmVsSWQiOiJFb3FmTEFCZDFQemN2MUc0Tm5tWGt4QUxXUGVxUXc3Y2FUTHI1a1Y3UTQ4ZyJ9LHsiY2hhbm5lbENvbmZpZyI6eyJvcGVuU2xvdCI6MzQxMDAwMDAwLCJwYXllciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicGF5ZXJBdXRob3JpemVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJyZWNlaXZlciI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwicmVjZWl2ZXJBdXRob3JpemVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJzYWx0IjoiMjExIiwidG9rZW4iOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsIndpdGhkcmF3RGVsYXkiOjM2MDB9LCJjaGFubmVsSWQiOiJFNXRBS3g4WHNmN1U4ZXpZeUdlMWZINjNrNnFpRm5yemdlUG0zZDZYelBlbyJ9LHsiY2hhbm5lbENvbmZpZyI6eyJvcGVuU2xvdCI6MzQxMDAwMDAwLCJwYXllciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicGF5ZXJBdXRob3JpemVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJyZWNlaXZlciI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwicmVjZWl2ZXJBdXRob3JpemVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJzYWx0IjoiMjEyIiwidG9rZW4iOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsIndpdGhkcmF3RGVsYXkiOjM2MDB9LCJjaGFubmVsSWQiOiIydzRtTGFFM2VYTEtwNDZGWldBUXZxYjJpVWdIQldOODg5QnhKcWE3YXFhUyJ9XSwidHlwZSI6InNldHRsZSJ9 diff --git a/harness/vectors/annotated/batch-wire-requirements-redemption-capacity.txt b/harness/vectors/annotated/batch-wire-requirements-redemption-capacity.txt new file mode 100644 index 000000000..6051fc6fe --- /dev/null +++ b/harness/vectors/annotated/batch-wire-requirements-redemption-capacity.txt @@ -0,0 +1,5 @@ +# batch-wire-requirements-redemption-capacity (x402-batch-settlement canonical-bytes, expect accept) +# generated by pkc fill; do not edit + + canonicalJson (542 bytes) {"amount":"1000","asset":"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU","extra":{"feePayer":"J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf","maxClaimChannels":18,"maxSettleChannels":13,"memo":"invoice-42","receiverAuthorizer":"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os","tokenProgram":"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA","transactionVersions":[0,1],"withdrawDelay":3600},"maxTimeoutSeconds":300,"network":"solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1","payTo":"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY","scheme":"batch-settlement"} + base64Url (723 chars) eyJhbW91bnQiOiIxMDAwIiwiYXNzZXQiOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsImV4dHJhIjp7ImZlZVBheWVyIjoiSjJ4Y2NSdHVHNDNkckVTTFl6bkhoTGhRa0xUZGZlcGNLWWJpUTlCc0pWYWYiLCJtYXhDbGFpbUNoYW5uZWxzIjoxOCwibWF4U2V0dGxlQ2hhbm5lbHMiOjEzLCJtZW1vIjoiaW52b2ljZS00MiIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwidG9rZW5Qcm9ncmFtIjoiVG9rZW5rZWdRZmVaeWlOd0FKYk5iR0tQRlhDV3VCdmY5U3M2MjNWUTVEQSIsInRyYW5zYWN0aW9uVmVyc2lvbnMiOlswLDFdLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwibWF4VGltZW91dFNlY29uZHMiOjMwMCwibmV0d29yayI6InNvbGFuYTpFdFdUUkFCWmFZcTZpTWZlWUtvdVJ1MTY2VlUyeHFhMSIsInBheVRvIjoiQ1hockZaSkxLcWp6bVAzc2pZTGNGNGRUZVhXS0N5OWUyU1hYWjJZbzZNUFkiLCJzY2hlbWUiOiJiYXRjaC1zZXR0bGVtZW50In0 diff --git a/harness/vectors/annotated/batch-wire-requirements-transaction-versions.txt b/harness/vectors/annotated/batch-wire-requirements-transaction-versions.txt index 710ddb141..07ca21d36 100644 --- a/harness/vectors/annotated/batch-wire-requirements-transaction-versions.txt +++ b/harness/vectors/annotated/batch-wire-requirements-transaction-versions.txt @@ -1,5 +1,5 @@ # batch-wire-requirements-transaction-versions (x402-batch-settlement canonical-bytes, expect accept) # generated by pkc fill; do not edit - canonicalJson (497 bytes) {"amount":"1000","asset":"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU","extra":{"feePayer":"J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf","memo":"invoice-42","receiverAuthorizer":"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os","tokenProgram":"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA","transactionVersions":[0,1],"withdrawDelay":3600},"maxTimeoutSeconds":300,"network":"solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1","payTo":"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY","scheme":"batch-settlement"} - base64Url (663 chars) eyJhbW91bnQiOiIxMDAwIiwiYXNzZXQiOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsImV4dHJhIjp7ImZlZVBheWVyIjoiSjJ4Y2NSdHVHNDNkckVTTFl6bkhoTGhRa0xUZGZlcGNLWWJpUTlCc0pWYWYiLCJtZW1vIjoiaW52b2ljZS00MiIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwidG9rZW5Qcm9ncmFtIjoiVG9rZW5rZWdRZmVaeWlOd0FKYk5iR0tQRlhDV3VCdmY5U3M2MjNWUTVEQSIsInRyYW5zYWN0aW9uVmVyc2lvbnMiOlswLDFdLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwibWF4VGltZW91dFNlY29uZHMiOjMwMCwibmV0d29yayI6InNvbGFuYTpFdFdUUkFCWmFZcTZpTWZlWUtvdVJ1MTY2VlUyeHFhMSIsInBheVRvIjoiQ1hockZaSkxLcWp6bVAzc2pZTGNGNGRUZVhXS0N5OWUyU1hYWjJZbzZNUFkiLCJzY2hlbWUiOiJiYXRjaC1zZXR0bGVtZW50In0 + canonicalJson (542 bytes) {"amount":"1000","asset":"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU","extra":{"feePayer":"J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf","maxClaimChannels":18,"maxSettleChannels":13,"memo":"invoice-42","receiverAuthorizer":"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os","tokenProgram":"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA","transactionVersions":[0,1],"withdrawDelay":3600},"maxTimeoutSeconds":300,"network":"solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1","payTo":"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY","scheme":"batch-settlement"} + base64Url (723 chars) eyJhbW91bnQiOiIxMDAwIiwiYXNzZXQiOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsImV4dHJhIjp7ImZlZVBheWVyIjoiSjJ4Y2NSdHVHNDNkckVTTFl6bkhoTGhRa0xUZGZlcGNLWWJpUTlCc0pWYWYiLCJtYXhDbGFpbUNoYW5uZWxzIjoxOCwibWF4U2V0dGxlQ2hhbm5lbHMiOjEzLCJtZW1vIjoiaW52b2ljZS00MiIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwidG9rZW5Qcm9ncmFtIjoiVG9rZW5rZWdRZmVaeWlOd0FKYk5iR0tQRlhDV3VCdmY5U3M2MjNWUTVEQSIsInRyYW5zYWN0aW9uVmVyc2lvbnMiOlswLDFdLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwibWF4VGltZW91dFNlY29uZHMiOjMwMCwibmV0d29yayI6InNvbGFuYTpFdFdUUkFCWmFZcTZpTWZlWUtvdVJ1MTY2VlUyeHFhMSIsInBheVRvIjoiQ1hockZaSkxLcWp6bVAzc2pZTGNGNGRUZVhXS0N5OWUyU1hYWjJZbzZNUFkiLCJzY2hlbWUiOiJiYXRjaC1zZXR0bGVtZW50In0 diff --git a/harness/vectors/annotated/x402-upto-verify-compute-at-caps-accept.txt b/harness/vectors/annotated/x402-upto-verify-compute-at-caps-accept.txt index d93f29fd0..331d59a8d 100644 --- a/harness/vectors/annotated/x402-upto-verify-compute-at-caps-accept.txt +++ b/harness/vectors/annotated/x402-upto-verify-compute-at-caps-accept.txt @@ -28,7 +28,7 @@ payment header (base64 JSON) "maxAmount": "1000000", "nonce": "4242", "openSlot": "400000000", - "openTransaction": "AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABA8aFtZH/8/GTrEAE7HZY6o5Bhc6SqvljLoTqFsmWU38NB5L90TUISKmixWQiEbVLfJ29Dr1ZWBsib5R1GICAOgAIACg9mvn4zLHpFMzK9nQp/fbBV9cXvGgatpm2Ys5+2gQxHOupKbGPinFIKvvVQexMuxfmVR3auvr57kkIe6mkURtIsIcHVkVxDmWkYi7SL3G64epdKZq5xNIBuQz2VKR6IvR5rhP5UBZmQpuojCNxliFWtlYplHhRXJiP3+tOT27AT7Ns19x+fca37bm5o4/hk4XDuY/8OxynLcXoyuea1jnvzAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADBkZv5SEXMv/srbpyw5vnvIzlu8X3EmssQ5s6QAAAAAVKU1qZKSEGTSTocWDaOHx8NbXdvJK7geQfqEBBBUSNBqfVFxksXFEhjMlMPUrxf1ja7gibof1E49vZigAAAAAG3fbh12Whk9nL4UbO63msHLSF7V9bN5E6jPWFfv8AqTtELLORIVfxOpM9ATQoLQMrX/7NAaLb8bd5BgjfAC6nWlQNe2seKyu1F1IZyaPwYBCSQcqMTxcMwcotSO7q+dCMlyWPTiSJ8bs9ECkUjg2DC1oTmdr/EIQEjnvY2+n4WZGiigt0OBWTpNlGlXkgiSavyK2CyIObdkQ1m566mks6p6H7pOsrCQmT99Lf1iuJ4rhyB3pjn9fXR6jpn2PUFa4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQGAAUCgBoGAAYACQNAS0wAAAAAAA4OAQAACg0CAwQJBQgMCw5DAZIQAAAAAAAAQEIPAAAAAACEAwAAAITXFwAAAAABAAAAq04rMx5LTzoVQrrg+VXdXTMDScdOoccKkgXsBlUJIjMQJwcAIDVmM2M5YTFlN2IyZDRjNmU4ZjBhMWIyYzNkNGU1ZjYwAA==", + "openTransaction": "AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACywg/GXJuDjiBZQOi79RqEM0aHYTe4s1Ycno6eeZXSA+xJf/P0IPxzIyfAcQ+VLCDRO7EWar/MyTd4/IpzyQsLgAIACg9mvn4zLHpFMzK9nQp/fbBV9cXvGgatpm2Ys5+2gQxHOupKbGPinFIKvvVQexMuxfmVR3auvr57kkIe6mkURtIsIcHVkVxDmWkYi7SL3G64epdKZq5xNIBuQz2VKR6IvR5rhP5UBZmQpuojCNxliFWtlYplHhRXJiP3+tOT27AT7Ns19x+fca37bm5o4/hk4XDuY/8OxynLcXoyuea1jnvzAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADBkZv5SEXMv/srbpyw5vnvIzlu8X3EmssQ5s6QAAAAAVKU1qZKSEGTSTocWDaOHx8NbXdvJK7geQfqEBBBUSNBqfVFxksXFEhjMlMPUrxf1ja7gibof1E49vZigAAAAAG3fbh12Whk9nL4UbO63msHLSF7V9bN5E6jPWFfv8AqTtELLORIVfxOpM9ATQoLQMrX/7NAaLb8bd5BgjfAC6nWlQNe2seKyu1F1IZyaPwYBCSQcqMTxcMwcotSO7q+dCMlyWPTiSJ8bs9ECkUjg2DC1oTmdr/EIQEjnvY2+n4WZGiigt0OBWTpNlGlXkgiSavyK2CyIObdkQ1m566mks6p6H7pOsrCQmT99Lf1iuJ4rhyB3pjn9fXR6jpn2PUFa4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQGAAUCgBoGAAYACQOIEwAAAAAAAA4OAQAACg0CAwQJBQgMCw5DAZIQAAAAAAAAQEIPAAAAAACEAwAAAITXFwAAAAABAAAAq04rMx5LTzoVQrrg+VXdXTMDScdOoccKkgXsBlUJIjMQJwcAIDVmM2M5YTFlN2IyZDRjNmU4ZjBhMWIyYzNkNGU1ZjYwAA==", "transaction": "", "validAfter": 1800000000 }, diff --git a/harness/vectors/annotated/x402-upto-verify-implicit-limit-at-fee-cap-accept.txt b/harness/vectors/annotated/x402-upto-verify-implicit-limit-at-fee-cap-accept.txt new file mode 100644 index 000000000..841b54f17 --- /dev/null +++ b/harness/vectors/annotated/x402-upto-verify-implicit-limit-at-fee-cap-accept.txt @@ -0,0 +1,37 @@ +# x402-upto-verify-implicit-limit-at-fee-cap-accept (x402-upto verify-transaction, expect accept) +# generated by pkc fill; do not edit + +payment header (base64 JSON) +{ + "accepted": { + "amount": "1000000", + "asset": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "extra": { + "feePayer": "7v54NWdBtkjuAFJrLGsS2SXnuk8nKam81mZJeeYxVFi9", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "recentBlockhash": "11111111111111111111111111111111", + "recentSlot": "400000000", + "tokenProgram": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "withdrawDelay": 900 + }, + "maxTimeoutSeconds": 300, + "network": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "payTo": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "scheme": "upto" + }, + "payload": { + "authorizedSigner": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "channelId": "3GmtA7TCp1rZ5fCYmw6iG2HqBBXmLMDNGCaXgSUabBb3", + "deposit": "1000000", + "expiresAt": 1800000300, + "from": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "maxAmount": "1000000", + "nonce": "4242", + "openSlot": "400000000", + "openTransaction": "AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBx2swntLzZZ5R7tu8g5pGf7jhj2inm27ckk6KWijUzr5478CQv5wMP+p+bZReVflIARtwQujJsHqg5GogF7IHgAIACg9mvn4zLHpFMzK9nQp/fbBV9cXvGgatpm2Ys5+2gQxHOupKbGPinFIKvvVQexMuxfmVR3auvr57kkIe6mkURtIsIcHVkVxDmWkYi7SL3G64epdKZq5xNIBuQz2VKR6IvR5rhP5UBZmQpuojCNxliFWtlYplHhRXJiP3+tOT27AT7Ns19x+fca37bm5o4/hk4XDuY/8OxynLcXoyuea1jnvzAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADBkZv5SEXMv/srbpyw5vnvIzlu8X3EmssQ5s6QAAAAAVKU1qZKSEGTSTocWDaOHx8NbXdvJK7geQfqEBBBUSNBqfVFxksXFEhjMlMPUrxf1ja7gibof1E49vZigAAAAAG3fbh12Whk9nL4UbO63msHLSF7V9bN5E6jPWFfv8AqTtELLORIVfxOpM9ATQoLQMrX/7NAaLb8bd5BgjfAC6nWlQNe2seKyu1F1IZyaPwYBCSQcqMTxcMwcotSO7q+dCMlyWPTiSJ8bs9ECkUjg2DC1oTmdr/EIQEjnvY2+n4WZGiigt0OBWTpNlGlXkgiSavyK2CyIObdkQ1m566mks6p6H7pOsrCQmT99Lf1iuJ4rhyB3pjn9fXR6jpn2PUFa4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMGAAkDiBMAAAAAAAAODgEAAAoNAgMECQUIDAsOQwGSEAAAAAAAAEBCDwAAAAAAhAMAAACE1xcAAAAAAQAAAKtOKzMeS086FUK64PlV3V0zA0nHTqHHCpIF7AZVCSIzECcHACA1ZjNjOWExZTdiMmQ0YzZlOGYwYTFiMmMzZDRlNWY2MAA=", + "transaction": "", + "validAfter": 1800000000 + }, + "x402Version": 2 +} + diff --git a/harness/vectors/annotated/x402-upto-verify-implicit-limit-priority-fee-over-cap-reject.txt b/harness/vectors/annotated/x402-upto-verify-implicit-limit-priority-fee-over-cap-reject.txt new file mode 100644 index 000000000..3e6959b40 --- /dev/null +++ b/harness/vectors/annotated/x402-upto-verify-implicit-limit-priority-fee-over-cap-reject.txt @@ -0,0 +1,37 @@ +# x402-upto-verify-implicit-limit-priority-fee-over-cap-reject (x402-upto verify-transaction, expect reject) +# generated by pkc fill; do not edit + +payment header (base64 JSON) +{ + "accepted": { + "amount": "1000000", + "asset": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "extra": { + "feePayer": "7v54NWdBtkjuAFJrLGsS2SXnuk8nKam81mZJeeYxVFi9", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "recentBlockhash": "11111111111111111111111111111111", + "recentSlot": "400000000", + "tokenProgram": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "withdrawDelay": 900 + }, + "maxTimeoutSeconds": 300, + "network": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "payTo": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "scheme": "upto" + }, + "payload": { + "authorizedSigner": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "channelId": "3GmtA7TCp1rZ5fCYmw6iG2HqBBXmLMDNGCaXgSUabBb3", + "deposit": "1000000", + "expiresAt": 1800000300, + "from": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "maxAmount": "1000000", + "nonce": "4242", + "openSlot": "400000000", + "openTransaction": "AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC50+YxqTBkvXn4HvkxD/jhPKuh3P70vwYRyzGKpB+b3Q+zgfDDD8qYbyqLGP/Hb9obHuNBggUMQ0br2OeT+sAgAIACg9mvn4zLHpFMzK9nQp/fbBV9cXvGgatpm2Ys5+2gQxHOupKbGPinFIKvvVQexMuxfmVR3auvr57kkIe6mkURtIsIcHVkVxDmWkYi7SL3G64epdKZq5xNIBuQz2VKR6IvR5rhP5UBZmQpuojCNxliFWtlYplHhRXJiP3+tOT27AT7Ns19x+fca37bm5o4/hk4XDuY/8OxynLcXoyuea1jnvzAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADBkZv5SEXMv/srbpyw5vnvIzlu8X3EmssQ5s6QAAAAAVKU1qZKSEGTSTocWDaOHx8NbXdvJK7geQfqEBBBUSNBqfVFxksXFEhjMlMPUrxf1ja7gibof1E49vZigAAAAAG3fbh12Whk9nL4UbO63msHLSF7V9bN5E6jPWFfv8AqTtELLORIVfxOpM9ATQoLQMrX/7NAaLb8bd5BgjfAC6nWlQNe2seKyu1F1IZyaPwYBCSQcqMTxcMwcotSO7q+dCMlyWPTiSJ8bs9ECkUjg2DC1oTmdr/EIQEjnvY2+n4WZGiigt0OBWTpNlGlXkgiSavyK2CyIObdkQ1m566mks6p6H7pOsrCQmT99Lf1iuJ4rhyB3pjn9fXR6jpn2PUFa4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMGAAkDiRMAAAAAAAAODgEAAAoNAgMECQUIDAsOQwGSEAAAAAAAAEBCDwAAAAAAhAMAAACE1xcAAAAAAQAAAKtOKzMeS086FUK64PlV3V0zA0nHTqHHCpIF7AZVCSIzECcHACA1ZjNjOWExZTdiMmQ0YzZlOGYwYTFiMmMzZDRlNWY2MAA=", + "transaction": "", + "validAfter": 1800000000 + }, + "x402Version": 2 +} + diff --git a/harness/vectors/annotated/x402-upto-verify-priority-fee-over-cap-reject.txt b/harness/vectors/annotated/x402-upto-verify-priority-fee-over-cap-reject.txt new file mode 100644 index 000000000..83017629c --- /dev/null +++ b/harness/vectors/annotated/x402-upto-verify-priority-fee-over-cap-reject.txt @@ -0,0 +1,37 @@ +# x402-upto-verify-priority-fee-over-cap-reject (x402-upto verify-transaction, expect reject) +# generated by pkc fill; do not edit + +payment header (base64 JSON) +{ + "accepted": { + "amount": "1000000", + "asset": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "extra": { + "feePayer": "7v54NWdBtkjuAFJrLGsS2SXnuk8nKam81mZJeeYxVFi9", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "recentBlockhash": "11111111111111111111111111111111", + "recentSlot": "400000000", + "tokenProgram": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "withdrawDelay": 900 + }, + "maxTimeoutSeconds": 300, + "network": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "payTo": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "scheme": "upto" + }, + "payload": { + "authorizedSigner": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "channelId": "3GmtA7TCp1rZ5fCYmw6iG2HqBBXmLMDNGCaXgSUabBb3", + "deposit": "1000000", + "expiresAt": 1800000300, + "from": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "maxAmount": "1000000", + "nonce": "4242", + "openSlot": "400000000", + "openTransaction": "AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABA8aFtZH/8/GTrEAE7HZY6o5Bhc6SqvljLoTqFsmWU38NB5L90TUISKmixWQiEbVLfJ29Dr1ZWBsib5R1GICAOgAIACg9mvn4zLHpFMzK9nQp/fbBV9cXvGgatpm2Ys5+2gQxHOupKbGPinFIKvvVQexMuxfmVR3auvr57kkIe6mkURtIsIcHVkVxDmWkYi7SL3G64epdKZq5xNIBuQz2VKR6IvR5rhP5UBZmQpuojCNxliFWtlYplHhRXJiP3+tOT27AT7Ns19x+fca37bm5o4/hk4XDuY/8OxynLcXoyuea1jnvzAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADBkZv5SEXMv/srbpyw5vnvIzlu8X3EmssQ5s6QAAAAAVKU1qZKSEGTSTocWDaOHx8NbXdvJK7geQfqEBBBUSNBqfVFxksXFEhjMlMPUrxf1ja7gibof1E49vZigAAAAAG3fbh12Whk9nL4UbO63msHLSF7V9bN5E6jPWFfv8AqTtELLORIVfxOpM9ATQoLQMrX/7NAaLb8bd5BgjfAC6nWlQNe2seKyu1F1IZyaPwYBCSQcqMTxcMwcotSO7q+dCMlyWPTiSJ8bs9ECkUjg2DC1oTmdr/EIQEjnvY2+n4WZGiigt0OBWTpNlGlXkgiSavyK2CyIObdkQ1m566mks6p6H7pOsrCQmT99Lf1iuJ4rhyB3pjn9fXR6jpn2PUFa4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQGAAUCgBoGAAYACQNAS0wAAAAAAA4OAQAACg0CAwQJBQgMCw5DAZIQAAAAAAAAQEIPAAAAAACEAwAAAITXFwAAAAABAAAAq04rMx5LTzoVQrrg+VXdXTMDScdOoccKkgXsBlUJIjMQJwcAIDVmM2M5YTFlN2IyZDRjNmU4ZjBhMWIyYzNkNGU1ZjYwAA==", + "transaction": "", + "validAfter": 1800000000 + }, + "x402Version": 2 +} + diff --git a/harness/vectors/annotated/x402-upto-verify-v1-priority-fee-at-cap-accept.txt b/harness/vectors/annotated/x402-upto-verify-v1-priority-fee-at-cap-accept.txt index 09008c292..133c97f05 100644 --- a/harness/vectors/annotated/x402-upto-verify-v1-priority-fee-at-cap-accept.txt +++ b/harness/vectors/annotated/x402-upto-verify-v1-priority-fee-at-cap-accept.txt @@ -32,7 +32,7 @@ payment header (base64 JSON) "maxAmount": "1000000", "nonce": "4242", "openSlot": "400000000", - "openTransaction": "gQIACQ8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIOZr5+Myx6RTMyvZ0Kf32wVfXF7xoGraZtmLOftoEMRzrqSmxj4pxSCr71UHsTLsX5lUd2rr6+e5JCHuppFEbSLCHB1ZFcQ5lpGIu0i9xuuHqXSmaucTSAbkM9lSkeiL0ea4T+VAWZkKbqIwjcZYhVrZWKZR4UVyYj9/rTk9uwE+zbNfcfn3Gt+25uaOP4ZOFw7mP/Dscpy3F6MrnmtY578wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABUpTWpkpIQZNJOhxYNo4fHw1td28kruB5B+oQEEFRI0Gp9UXGSxcUSGMyUw9SvF/WNruCJuh/UTj29mKAAAAAAbd9uHXZaGT2cvhRs7reawctIXtX1s3kTqM9YV+/wCpO0Qss5EhV/E6kz0BNCgtAytf/s0Botvxt3kGCN8ALqdaVA17ax4rK7UXUhnJo/BgEJJByoxPFwzByi1I7ur50IyXJY9OJInxuz0QKRSODYMLWhOZ2v8QhASOe9jb6fhZkaKKC3Q4FZOk2UaVeSCJJq/IrYLIg5t2RDWbnrqaSzqnofuk6ysJCZP30t/WK4niuHIHemOf19dHqOmfY9QVrkBCDwAAAAAAQA0DAAAAAAQNDkMABgAgAAEAAAkMAgMECAUHCwoNAZIQAAAAAAAAQEIPAAAAAACEAwAAAITXFwAAAAABAAAAq04rMx5LTzoVQrrg+VXdXTMDScdOoccKkgXsBlUJIjMQJzVmM2M5YTFlN2IyZDRjNmU4ZjBhMWIyYzNkNGU1ZjYwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKxbFcquLlJSPVc1Icd7kGT05+gw0P3fXLN6LUfvBpmy5agI/Xx/TFTXiQBC7ayPH5duD18Hhr1cG5otj/rC4wM=", + "openTransaction": "gQIACQ8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIOZr5+Myx6RTMyvZ0Kf32wVfXF7xoGraZtmLOftoEMRzrqSmxj4pxSCr71UHsTLsX5lUd2rr6+e5JCHuppFEbSLCHB1ZFcQ5lpGIu0i9xuuHqXSmaucTSAbkM9lSkeiL0ea4T+VAWZkKbqIwjcZYhVrZWKZR4UVyYj9/rTk9uwE+zbNfcfn3Gt+25uaOP4ZOFw7mP/Dscpy3F6MrnmtY578wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABUpTWpkpIQZNJOhxYNo4fHw1td28kruB5B+oQEEFRI0Gp9UXGSxcUSGMyUw9SvF/WNruCJuh/UTj29mKAAAAAAbd9uHXZaGT2cvhRs7reawctIXtX1s3kTqM9YV+/wCpO0Qss5EhV/E6kz0BNCgtAytf/s0Botvxt3kGCN8ALqdaVA17ax4rK7UXUhnJo/BgEJJByoxPFwzByi1I7ur50IyXJY9OJInxuz0QKRSODYMLWhOZ2v8QhASOe9jb6fhZkaKKC3Q4FZOk2UaVeSCJJq/IrYLIg5t2RDWbnrqaSzqnofuk6ysJCZP30t/WK4niuHIHemOf19dHqOmfY9QVrtwFAAAAAAAALAEAAAAAAAQNDkMABgAgAAEAAAkMAgMECAUHCwoNAZIQAAAAAAAAQEIPAAAAAACEAwAAAITXFwAAAAABAAAAq04rMx5LTzoVQrrg+VXdXTMDScdOoccKkgXsBlUJIjMQJzVmM2M5YTFlN2IyZDRjNmU4ZjBhMWIyYzNkNGU1ZjYwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAObQX37o1MiA/E7tDgsr3vgzRs35MTC1rnNKHTSM7VQk8WMq9u/csHCWzG4VSwD6AjUpyvsvBI5gDisTFL+7cgo=", "transaction": "", "validAfter": 1800000000 }, diff --git a/harness/vectors/annotated/x402-upto-verify-v1-priority-fee-over-cap-reject.txt b/harness/vectors/annotated/x402-upto-verify-v1-priority-fee-over-cap-reject.txt index 0fb733e35..3d2d73efe 100644 --- a/harness/vectors/annotated/x402-upto-verify-v1-priority-fee-over-cap-reject.txt +++ b/harness/vectors/annotated/x402-upto-verify-v1-priority-fee-over-cap-reject.txt @@ -32,7 +32,7 @@ payment header (base64 JSON) "maxAmount": "1000000", "nonce": "4242", "openSlot": "400000000", - "openTransaction": "gQIACQ8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIOZr5+Myx6RTMyvZ0Kf32wVfXF7xoGraZtmLOftoEMRzrqSmxj4pxSCr71UHsTLsX5lUd2rr6+e5JCHuppFEbSLCHB1ZFcQ5lpGIu0i9xuuHqXSmaucTSAbkM9lSkeiL0ea4T+VAWZkKbqIwjcZYhVrZWKZR4UVyYj9/rTk9uwE+zbNfcfn3Gt+25uaOP4ZOFw7mP/Dscpy3F6MrnmtY578wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABUpTWpkpIQZNJOhxYNo4fHw1td28kruB5B+oQEEFRI0Gp9UXGSxcUSGMyUw9SvF/WNruCJuh/UTj29mKAAAAAAbd9uHXZaGT2cvhRs7reawctIXtX1s3kTqM9YV+/wCpO0Qss5EhV/E6kz0BNCgtAytf/s0Botvxt3kGCN8ALqdaVA17ax4rK7UXUhnJo/BgEJJByoxPFwzByi1I7ur50IyXJY9OJInxuz0QKRSODYMLWhOZ2v8QhASOe9jb6fhZkaKKC3Q4FZOk2UaVeSCJJq/IrYLIg5t2RDWbnrqaSzqnofuk6ysJCZP30t/WK4niuHIHemOf19dHqOmfY9QVrkFCDwAAAAAAQA0DAAAAAAQNDkMABgAgAAEAAAkMAgMECAUHCwoNAZIQAAAAAAAAQEIPAAAAAACEAwAAAITXFwAAAAABAAAAq04rMx5LTzoVQrrg+VXdXTMDScdOoccKkgXsBlUJIjMQJzVmM2M5YTFlN2IyZDRjNmU4ZjBhMWIyYzNkNGU1ZjYwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJ4T042JdKDph5oUbZzBcT7TB5p4YV8MPodWKFKZBNg7oVTAqK9fXSC67kPjRyWfV8E8WVIrXSDySc2FyFc0zQ0=", + "openTransaction": "gQIACQ8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIOZr5+Myx6RTMyvZ0Kf32wVfXF7xoGraZtmLOftoEMRzrqSmxj4pxSCr71UHsTLsX5lUd2rr6+e5JCHuppFEbSLCHB1ZFcQ5lpGIu0i9xuuHqXSmaucTSAbkM9lSkeiL0ea4T+VAWZkKbqIwjcZYhVrZWKZR4UVyYj9/rTk9uwE+zbNfcfn3Gt+25uaOP4ZOFw7mP/Dscpy3F6MrnmtY578wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABUpTWpkpIQZNJOhxYNo4fHw1td28kruB5B+oQEEFRI0Gp9UXGSxcUSGMyUw9SvF/WNruCJuh/UTj29mKAAAAAAbd9uHXZaGT2cvhRs7reawctIXtX1s3kTqM9YV+/wCpO0Qss5EhV/E6kz0BNCgtAytf/s0Botvxt3kGCN8ALqdaVA17ax4rK7UXUhnJo/BgEJJByoxPFwzByi1I7ur50IyXJY9OJInxuz0QKRSODYMLWhOZ2v8QhASOe9jb6fhZkaKKC3Q4FZOk2UaVeSCJJq/IrYLIg5t2RDWbnrqaSzqnofuk6ysJCZP30t/WK4niuHIHemOf19dHqOmfY9QVrt0FAAAAAAAALAEAAAAAAAQNDkMABgAgAAEAAAkMAgMECAUHCwoNAZIQAAAAAAAAQEIPAAAAAACEAwAAAITXFwAAAAABAAAAq04rMx5LTzoVQrrg+VXdXTMDScdOoccKkgXsBlUJIjMQJzVmM2M5YTFlN2IyZDRjNmU4ZjBhMWIyYzNkNGU1ZjYwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALgDvtuSIfbm2Dsu9fH7Mi1+IWvOPqg5TKAGkST93eFae5Ifyw9WGFmzByDUEP0sixxIbgB+A3In7xYTOTmFKQg=", "transaction": "", "validAfter": 1800000000 }, diff --git a/harness/vectors/annotated/x402-upto-verify-v1-priority-fee-over-sponsor-cap-reject.txt b/harness/vectors/annotated/x402-upto-verify-v1-priority-fee-over-sponsor-cap-reject.txt new file mode 100644 index 000000000..b94539d87 --- /dev/null +++ b/harness/vectors/annotated/x402-upto-verify-v1-priority-fee-over-sponsor-cap-reject.txt @@ -0,0 +1,41 @@ +# x402-upto-verify-v1-priority-fee-over-sponsor-cap-reject (x402-upto verify-transaction, expect reject) +# generated by pkc fill; do not edit + +payment header (base64 JSON) +{ + "accepted": { + "amount": "1000000", + "asset": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "extra": { + "feePayer": "7v54NWdBtkjuAFJrLGsS2SXnuk8nKam81mZJeeYxVFi9", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "recentBlockhash": "11111111111111111111111111111111", + "recentSlot": "400000000", + "tokenProgram": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "transactionVersions": [ + 0, + 1 + ], + "withdrawDelay": 900 + }, + "maxTimeoutSeconds": 300, + "network": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "payTo": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "scheme": "upto" + }, + "payload": { + "authorizedSigner": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "channelId": "3GmtA7TCp1rZ5fCYmw6iG2HqBBXmLMDNGCaXgSUabBb3", + "deposit": "1000000", + "expiresAt": 1800000300, + "from": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "maxAmount": "1000000", + "nonce": "4242", + "openSlot": "400000000", + "openTransaction": "gQIACQ8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIOZr5+Myx6RTMyvZ0Kf32wVfXF7xoGraZtmLOftoEMRzrqSmxj4pxSCr71UHsTLsX5lUd2rr6+e5JCHuppFEbSLCHB1ZFcQ5lpGIu0i9xuuHqXSmaucTSAbkM9lSkeiL0ea4T+VAWZkKbqIwjcZYhVrZWKZR4UVyYj9/rTk9uwE+zbNfcfn3Gt+25uaOP4ZOFw7mP/Dscpy3F6MrnmtY578wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABUpTWpkpIQZNJOhxYNo4fHw1td28kruB5B+oQEEFRI0Gp9UXGSxcUSGMyUw9SvF/WNruCJuh/UTj29mKAAAAAAbd9uHXZaGT2cvhRs7reawctIXtX1s3kTqM9YV+/wCpO0Qss5EhV/E6kz0BNCgtAytf/s0Botvxt3kGCN8ALqdaVA17ax4rK7UXUhnJo/BgEJJByoxPFwzByi1I7ur50IyXJY9OJInxuz0QKRSODYMLWhOZ2v8QhASOe9jb6fhZkaKKC3Q4FZOk2UaVeSCJJq/IrYLIg5t2RDWbnrqaSzqnofuk6ysJCZP30t/WK4niuHIHemOf19dHqOmfY9QVrtEHAAAAAAAAQA0DAAAAAAQNDkMABgAgAAEAAAkMAgMECAUHCwoNAZIQAAAAAAAAQEIPAAAAAACEAwAAAITXFwAAAAABAAAAq04rMx5LTzoVQrrg+VXdXTMDScdOoccKkgXsBlUJIjMQJzVmM2M5YTFlN2IyZDRjNmU4ZjBhMWIyYzNkNGU1ZjYwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHKufUr9Ma1oJHW5883mWdR3w25d48uzUPeXPwsWhMTu2PO6sN34lqYPIdZRfaspcDo+hAxne3zaIFUaAgGY9A8=", + "transaction": "", + "validAfter": 1800000000 + }, + "x402Version": 2 +} + diff --git a/harness/vectors/annotated/x402-verify-v1-compute-limit-at-cap-accept.txt b/harness/vectors/annotated/x402-verify-v1-compute-limit-at-cap-accept.txt index e2c0290fe..4561ad138 100644 --- a/harness/vectors/annotated/x402-verify-v1-compute-limit-at-cap-accept.txt +++ b/harness/vectors/annotated/x402-verify-v1-compute-limit-at-cap-accept.txt @@ -26,7 +26,7 @@ payment header (base64 JSON) transaction version 1 recent blockhash 11111111111111111111111111111111 - config computeUnitLimit 200000 priorityFee 1 lamports loadedAccountsDataSizeLimit 67108864 + config computeUnitLimit 400000 priorityFee 1 lamports loadedAccountsDataSizeLimit 67108864 signatures [0] empty J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf (server fee payer / charge recipient) [1] signed GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB (client) diff --git a/harness/vectors/annotated/x402-verify-v1-compute-limit-over-cap-reject.txt b/harness/vectors/annotated/x402-verify-v1-compute-limit-over-cap-reject.txt index c3d3a277d..c7f016eb1 100644 --- a/harness/vectors/annotated/x402-verify-v1-compute-limit-over-cap-reject.txt +++ b/harness/vectors/annotated/x402-verify-v1-compute-limit-over-cap-reject.txt @@ -26,7 +26,7 @@ payment header (base64 JSON) transaction version 1 recent blockhash 11111111111111111111111111111111 - config computeUnitLimit 200001 priorityFee 1 lamports loadedAccountsDataSizeLimit 67108864 + config computeUnitLimit 400001 priorityFee 1 lamports loadedAccountsDataSizeLimit 67108864 signatures [0] empty J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf (server fee payer / charge recipient) [1] signed GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB (client) diff --git a/harness/vectors/annotated/x402-verify-v1-heap-size-reject.txt b/harness/vectors/annotated/x402-verify-v1-heap-size-reject.txt new file mode 100644 index 000000000..2b4c03e4e --- /dev/null +++ b/harness/vectors/annotated/x402-verify-v1-heap-size-reject.txt @@ -0,0 +1,50 @@ +# x402-verify-v1-heap-size-reject (x402-exact verify-transaction, expect reject) +# generated by pkc fill; do not edit + +payment header (base64 JSON) +{ + "accepted": { + "amount": "1000", + "asset": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "extra": { + "feePayer": "J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf", + "transactionVersions": [ + 0, + 1 + ] + }, + "maxTimeoutSeconds": 300, + "network": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "payTo": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "scheme": "exact" + }, + "payload": { + "transaction": "" + }, + "x402Version": 2 +} + +transaction version 1 + recent blockhash 11111111111111111111111111111111 + config computeUnitLimit 200000 priorityFee 1 lamports loadedAccountsDataSizeLimit 67108864 + signatures + [0] empty J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf (server fee payer / charge recipient) + [1] signed GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB (client) + accounts + [0] J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf (server fee payer / charge recipient) [signer, writable, fee payer] + [1] GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB (client) [signer] + [2] PjeTAeWHZHjrBForCEJvMVmRJpW5dngPaRzCp8w1MM4 (ATA(x402 payTo, mint, SPL Token)) [writable] + [3] 8EiF91LJfbatqHRY3k2jp8dwrFY3yDQeEovpMDZnpJiP (ATA(client, mint, SPL Token)) [writable] + [4] MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr (Memo) [readonly] + [5] TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA (SPL Token) [readonly] + [6] 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU (mint) [readonly] + instructions + #0 SPL Token TransferChecked + amount 1000 + decimals 6 + source 8EiF91LJfbatqHRY3k2jp8dwrFY3yDQeEovpMDZnpJiP (ATA(client, mint, SPL Token)) + mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU (mint) + destination PjeTAeWHZHjrBForCEJvMVmRJpW5dngPaRzCp8w1MM4 (ATA(x402 payTo, mint, SPL Token)) + authority GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB (client) + #1 Memo + text "x402verifyv1heap0000000000000000" diff --git a/harness/vectors/annotated/x402-verify-v1-loaded-data-limit-4mib-accept.txt b/harness/vectors/annotated/x402-verify-v1-loaded-data-limit-4mib-accept.txt new file mode 100644 index 000000000..fc2eb8947 --- /dev/null +++ b/harness/vectors/annotated/x402-verify-v1-loaded-data-limit-4mib-accept.txt @@ -0,0 +1,50 @@ +# x402-verify-v1-loaded-data-limit-4mib-accept (x402-exact verify-transaction, expect accept) +# generated by pkc fill; do not edit + +payment header (base64 JSON) +{ + "accepted": { + "amount": "1000", + "asset": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "extra": { + "feePayer": "J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf", + "transactionVersions": [ + 0, + 1 + ] + }, + "maxTimeoutSeconds": 300, + "network": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "payTo": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "scheme": "exact" + }, + "payload": { + "transaction": "" + }, + "x402Version": 2 +} + +transaction version 1 + recent blockhash 11111111111111111111111111111111 + config computeUnitLimit 200000 priorityFee 1 lamports loadedAccountsDataSizeLimit 4194304 + signatures + [0] empty J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf (server fee payer / charge recipient) + [1] signed GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB (client) + accounts + [0] J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf (server fee payer / charge recipient) [signer, writable, fee payer] + [1] GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB (client) [signer] + [2] PjeTAeWHZHjrBForCEJvMVmRJpW5dngPaRzCp8w1MM4 (ATA(x402 payTo, mint, SPL Token)) [writable] + [3] 8EiF91LJfbatqHRY3k2jp8dwrFY3yDQeEovpMDZnpJiP (ATA(client, mint, SPL Token)) [writable] + [4] MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr (Memo) [readonly] + [5] TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA (SPL Token) [readonly] + [6] 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU (mint) [readonly] + instructions + #0 SPL Token TransferChecked + amount 1000 + decimals 6 + source 8EiF91LJfbatqHRY3k2jp8dwrFY3yDQeEovpMDZnpJiP (ATA(client, mint, SPL Token)) + mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU (mint) + destination PjeTAeWHZHjrBForCEJvMVmRJpW5dngPaRzCp8w1MM4 (ATA(x402 payTo, mint, SPL Token)) + authority GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB (client) + #1 Memo + text "x402verifyv1load0000000000000000" diff --git a/harness/vectors/annotated/x402-verify-v1-loaded-data-limit-small-accept.txt b/harness/vectors/annotated/x402-verify-v1-loaded-data-limit-small-accept.txt new file mode 100644 index 000000000..3d0828192 --- /dev/null +++ b/harness/vectors/annotated/x402-verify-v1-loaded-data-limit-small-accept.txt @@ -0,0 +1,50 @@ +# x402-verify-v1-loaded-data-limit-small-accept (x402-exact verify-transaction, expect accept) +# generated by pkc fill; do not edit + +payment header (base64 JSON) +{ + "accepted": { + "amount": "1000", + "asset": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "extra": { + "feePayer": "J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf", + "transactionVersions": [ + 0, + 1 + ] + }, + "maxTimeoutSeconds": 300, + "network": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "payTo": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "scheme": "exact" + }, + "payload": { + "transaction": "" + }, + "x402Version": 2 +} + +transaction version 1 + recent blockhash 11111111111111111111111111111111 + config computeUnitLimit 200000 priorityFee 1 lamports loadedAccountsDataSizeLimit 32768 + signatures + [0] empty J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf (server fee payer / charge recipient) + [1] signed GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB (client) + accounts + [0] J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf (server fee payer / charge recipient) [signer, writable, fee payer] + [1] GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB (client) [signer] + [2] PjeTAeWHZHjrBForCEJvMVmRJpW5dngPaRzCp8w1MM4 (ATA(x402 payTo, mint, SPL Token)) [writable] + [3] 8EiF91LJfbatqHRY3k2jp8dwrFY3yDQeEovpMDZnpJiP (ATA(client, mint, SPL Token)) [writable] + [4] MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr (Memo) [readonly] + [5] TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA (SPL Token) [readonly] + [6] 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU (mint) [readonly] + instructions + #0 SPL Token TransferChecked + amount 1000 + decimals 6 + source 8EiF91LJfbatqHRY3k2jp8dwrFY3yDQeEovpMDZnpJiP (ATA(client, mint, SPL Token)) + mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU (mint) + destination PjeTAeWHZHjrBForCEJvMVmRJpW5dngPaRzCp8w1MM4 (ATA(x402 payTo, mint, SPL Token)) + authority GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB (client) + #1 Memo + text "x402verifyv1load0000000000000000" diff --git a/harness/vectors/batch-build.json b/harness/vectors/batch-build.json index 0588fd5a7..a59ef5476 100644 --- a/harness/vectors/batch-build.json +++ b/harness/vectors/batch-build.json @@ -894,6 +894,8 @@ "asset": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", "extra": { "feePayer": "J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf", + "maxClaimChannels": 18, + "maxSettleChannels": 13, "memo": "invoice-42", "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", "tokenProgram": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", diff --git a/harness/vectors/batch-txv1.json b/harness/vectors/batch-txv1.json index 427a9354a..e75738fb7 100644 --- a/harness/vectors/batch-txv1.json +++ b/harness/vectors/batch-txv1.json @@ -12,6 +12,8 @@ "asset": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", "extra": { "feePayer": "J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf", + "maxClaimChannels": 18, + "maxSettleChannels": 13, "memo": "invoice-42", "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", "tokenProgram": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", @@ -148,7 +150,7 @@ "recentBlockhash": "11111111111111111111111111111111", "slot": 341000100 }, - "x402PaymentHeader": "eyJhY2NlcHRlZCI6eyJhbW91bnQiOiIxMDAwIiwiYXNzZXQiOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsImV4dHJhIjp7ImZlZVBheWVyIjoiSjJ4Y2NSdHVHNDNkckVTTFl6bkhoTGhRa0xUZGZlcGNLWWJpUTlCc0pWYWYiLCJtZW1vIjoiaW52b2ljZS00MiIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwidG9rZW5Qcm9ncmFtIjoiVG9rZW5rZWdRZmVaeWlOd0FKYk5iR0tQRlhDV3VCdmY5U3M2MjNWUTVEQSIsInRyYW5zYWN0aW9uVmVyc2lvbnMiOlswLDFdLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwibWF4VGltZW91dFNlY29uZHMiOjMwMCwibmV0d29yayI6InNvbGFuYTpFdFdUUkFCWmFZcTZpTWZlWUtvdVJ1MTY2VlUyeHFhMSIsInBheVRvIjoiQ1hockZaSkxLcWp6bVAzc2pZTGNGNGRUZVhXS0N5OWUyU1hYWjJZbzZNUFkiLCJzY2hlbWUiOiJiYXRjaC1zZXR0bGVtZW50In0sInBheWxvYWQiOnsiY2hhbm5lbENvbmZpZyI6eyJvcGVuU2xvdCI6MzQxMDAwMDAwLCJwYXllciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicGF5ZXJBdXRob3JpemVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJyZWNlaXZlciI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwicmVjZWl2ZXJBdXRob3JpemVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJzYWx0IjoiNDIiLCJ0b2tlbiI6IjR6TU1DOXNydDVSaTVYMTRHQWdYaGFIaWkzR25QQUVFUllQSmdaSkRuY0RVIiwid2l0aGRyYXdEZWxheSI6MzYwMH0sImRlcG9zaXQiOnsiYW1vdW50IjoiNjAwMCIsInRyYW5zYWN0aW9uIjoiZ1FJQUJBOEFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBSUovUmNrT0ZxZ3gxdGsrM2pOWUMraDJaSDk2L2RyRThXTzF3THF5RFhwOWhqcVNteGo0cHhTQ3I3MVVIc1RMc1g1bFVkMnJyNitlNUpDSHVwcEZFYlNMQkxwTml1bkpEM0t2eEtTdlVkbGRBck04SU9PY01ibi9OR2JmMlN4WGlNZWE0VCtWQVdaa0ticUl3amNaWWhWclpXS1pSNFVWeVlqOS9yVGs5dXdFK3o0cVlKYldPOHRYTWQwTWVINXhpME5mNlVtSDR1MytJZHRueDZKb05rcklBVktVMXFaS1NFR1RTVG9jV0RhT0h4OE5iWGR2Sks3Z2VRZnFFQkJCVVNOQnQzMjRkZGxvWlBaeStGR3p1dDVyQnkwaGUxZld6ZVJPb3oxaFg3L0FLazdSQ3l6a1NGWDhUcVRQUUUwS0MwREsxLyt6UUdpMi9HM2VRWUkzd0F1cDZlaCs2VHJLd2tKay9mUzM5WXJpZUs0Y2dkNlk1L1gxMGVvNlo5ajFCV3V5QUFBQUFBQUFBQkFEUU1BQUFBQUJBZ0dDUUFGQUFvQUFRUURBZ2NHQTNBWEFBQUFBQUFBYVc1MmIybGpaUzAwTWdBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFEVlA4QmxYSGNRckxXamlNdk9FN1NJZE1pZ2ZHOGg0SGhBZzNnUDA5dTFYejBYU0Z6UDE5MFg5MHdiQVl5VkQ0RGhXUFpTc1lFdHN0dHd2ZTdqemFRTyJ9LCJ0eXBlIjoiZGVwb3NpdCIsInZvdWNoZXIiOnsiY2hhbm5lbElkIjoiSGpnMlBEZ0x4WURpUVdSSHJKZWVZOVY5aU55ZWJNOU1XdXRvQTY3ZWl2c1oiLCJleHBpcmVzQXQiOjAsIm1heENsYWltYWJsZUFtb3VudCI6IjQwMDAiLCJzaWduYXR1cmUiOiIzV1lOamNtaGQ0c1hvbnhRUHJCcXJGYnNWdDlKb2dGU3RvQVNwajRvMUxUbkx4aTlIZTRiNGU4dEhqc3VDdE1DV0JQa3RvUmZ6R1h4SFNmSjl1WWdhWERSIn19LCJ4NDAyVmVyc2lvbiI6Mn0=" + "x402PaymentHeader": "eyJhY2NlcHRlZCI6eyJhbW91bnQiOiIxMDAwIiwiYXNzZXQiOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsImV4dHJhIjp7ImZlZVBheWVyIjoiSjJ4Y2NSdHVHNDNkckVTTFl6bkhoTGhRa0xUZGZlcGNLWWJpUTlCc0pWYWYiLCJtYXhDbGFpbUNoYW5uZWxzIjoxOCwibWF4U2V0dGxlQ2hhbm5lbHMiOjEzLCJtZW1vIjoiaW52b2ljZS00MiIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwidG9rZW5Qcm9ncmFtIjoiVG9rZW5rZWdRZmVaeWlOd0FKYk5iR0tQRlhDV3VCdmY5U3M2MjNWUTVEQSIsInRyYW5zYWN0aW9uVmVyc2lvbnMiOlswLDFdLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwibWF4VGltZW91dFNlY29uZHMiOjMwMCwibmV0d29yayI6InNvbGFuYTpFdFdUUkFCWmFZcTZpTWZlWUtvdVJ1MTY2VlUyeHFhMSIsInBheVRvIjoiQ1hockZaSkxLcWp6bVAzc2pZTGNGNGRUZVhXS0N5OWUyU1hYWjJZbzZNUFkiLCJzY2hlbWUiOiJiYXRjaC1zZXR0bGVtZW50In0sInBheWxvYWQiOnsiY2hhbm5lbENvbmZpZyI6eyJvcGVuU2xvdCI6MzQxMDAwMDAwLCJwYXllciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicGF5ZXJBdXRob3JpemVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJyZWNlaXZlciI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwicmVjZWl2ZXJBdXRob3JpemVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJzYWx0IjoiNDIiLCJ0b2tlbiI6IjR6TU1DOXNydDVSaTVYMTRHQWdYaGFIaWkzR25QQUVFUllQSmdaSkRuY0RVIiwid2l0aGRyYXdEZWxheSI6MzYwMH0sImRlcG9zaXQiOnsiYW1vdW50IjoiNjAwMCIsInRyYW5zYWN0aW9uIjoiZ1FJQUJBOEFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBSUovUmNrT0ZxZ3gxdGsrM2pOWUMraDJaSDk2L2RyRThXTzF3THF5RFhwOWhqcVNteGo0cHhTQ3I3MVVIc1RMc1g1bFVkMnJyNitlNUpDSHVwcEZFYlNMQkxwTml1bkpEM0t2eEtTdlVkbGRBck04SU9PY01ibi9OR2JmMlN4WGlNZWE0VCtWQVdaa0ticUl3amNaWWhWclpXS1pSNFVWeVlqOS9yVGs5dXdFK3o0cVlKYldPOHRYTWQwTWVINXhpME5mNlVtSDR1MytJZHRueDZKb05rcklBVktVMXFaS1NFR1RTVG9jV0RhT0h4OE5iWGR2Sks3Z2VRZnFFQkJCVVNOQnQzMjRkZGxvWlBaeStGR3p1dDVyQnkwaGUxZld6ZVJPb3oxaFg3L0FLazdSQ3l6a1NGWDhUcVRQUUUwS0MwREsxLyt6UUdpMi9HM2VRWUkzd0F1cDZlaCs2VHJLd2tKay9mUzM5WXJpZUs0Y2dkNlk1L1gxMGVvNlo5ajFCV3V5QUFBQUFBQUFBQkFEUU1BQUFBQUJBZ0dDUUFGQUFvQUFRUURBZ2NHQTNBWEFBQUFBQUFBYVc1MmIybGpaUzAwTWdBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFEVlA4QmxYSGNRckxXamlNdk9FN1NJZE1pZ2ZHOGg0SGhBZzNnUDA5dTFYejBYU0Z6UDE5MFg5MHdiQVl5VkQ0RGhXUFpTc1lFdHN0dHd2ZTdqemFRTyJ9LCJ0eXBlIjoiZGVwb3NpdCIsInZvdWNoZXIiOnsiY2hhbm5lbElkIjoiSGpnMlBEZ0x4WURpUVdSSHJKZWVZOVY5aU55ZWJNOU1XdXRvQTY3ZWl2c1oiLCJleHBpcmVzQXQiOjAsIm1heENsYWltYWJsZUFtb3VudCI6IjQwMDAiLCJzaWduYXR1cmUiOiIzV1lOamNtaGQ0c1hvbnhRUHJCcXJGYnNWdDlKb2dGU3RvQVNwajRvMUxUbkx4aTlIZTRiNGU4dEhqc3VDdE1DV0JQa3RvUmZ6R1h4SFNmSjl1WWdhWERSIn19LCJ4NDAyVmVyc2lvbiI6Mn0=" }, "intent": "x402-batch-settlement", "mode": "verify-transaction", @@ -156,19 +158,19 @@ "requirements": [ "X402TX-4de59a1f27", "X402TX-d444d01b9e", - "X402TX-644919eb3b" + "X402TX-f9bcc1a14a" ], "role": "server", "spec": { "doc": "x402-txv1/specs/schemes/batch-settlement/scheme_batch_settlement_svm.md", - "quote": "A version-1 transaction carries its compute budget in the message `TransactionConfig`.", + "quote": "A version-1 transaction carries its compute budget in the message's `TransactionConfigMask` and the config values that follow it", "section": "Transaction versions" }, "tier": "offline" }, { "bugType": "auth-bypass", - "description": "The same version-1 top_up on a route that accepts only version 0 (no transactionVersions advertised).", + "description": "The same version-1 top_up to a facilitator configured to accept only version 0 (batchServer.transactionVersions [0]).", "expect": { "outcome": "reject", "rejectCode": "unsupported-version" @@ -265,6 +267,9 @@ "payTo": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", "price": "0.001", "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "transactionVersions": [ + 0 + ], "withdrawDelay": 3600 }, "batchServerChannel": { @@ -338,6 +343,8 @@ "asset": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", "extra": { "feePayer": "J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf", + "maxClaimChannels": 18, + "maxSettleChannels": 13, "memo": "invoice-42", "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", "tokenProgram": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", @@ -474,7 +481,7 @@ "recentBlockhash": "11111111111111111111111111111111", "slot": 341000100 }, - "x402PaymentHeader": "eyJhY2NlcHRlZCI6eyJhbW91bnQiOiIxMDAwIiwiYXNzZXQiOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsImV4dHJhIjp7ImZlZVBheWVyIjoiSjJ4Y2NSdHVHNDNkckVTTFl6bkhoTGhRa0xUZGZlcGNLWWJpUTlCc0pWYWYiLCJtZW1vIjoiaW52b2ljZS00MiIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwidG9rZW5Qcm9ncmFtIjoiVG9rZW5rZWdRZmVaeWlOd0FKYk5iR0tQRlhDV3VCdmY5U3M2MjNWUTVEQSIsInRyYW5zYWN0aW9uVmVyc2lvbnMiOlswLDFdLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwibWF4VGltZW91dFNlY29uZHMiOjMwMCwibmV0d29yayI6InNvbGFuYTpFdFdUUkFCWmFZcTZpTWZlWUtvdVJ1MTY2VlUyeHFhMSIsInBheVRvIjoiQ1hockZaSkxLcWp6bVAzc2pZTGNGNGRUZVhXS0N5OWUyU1hYWjJZbzZNUFkiLCJzY2hlbWUiOiJiYXRjaC1zZXR0bGVtZW50In0sInBheWxvYWQiOnsiY2hhbm5lbENvbmZpZyI6eyJvcGVuU2xvdCI6MzQxMDAwMDAwLCJwYXllciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicGF5ZXJBdXRob3JpemVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJyZWNlaXZlciI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwicmVjZWl2ZXJBdXRob3JpemVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJzYWx0IjoiNDIiLCJ0b2tlbiI6IjR6TU1DOXNydDVSaTVYMTRHQWdYaGFIaWkzR25QQUVFUllQSmdaSkRuY0RVIiwid2l0aGRyYXdEZWxheSI6MzYwMH0sImRlcG9zaXQiOnsiYW1vdW50IjoiNjAwMCIsInRyYW5zYWN0aW9uIjoiQWdBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFCSno5QWhpMmE2VTRpUWtyeDhlWCt5RGlWVkNXclZja3Jqd1Y2Y2dXS2N4S0ZjSEU1WGE0bmd1dnRBcVIwZUhhaUZ3MUljdEkvVlA2dS9sVlp3NW9RSmdBSUFCQW45RnlRNFdxREhXMlQ3ZU0xZ0w2SFprZjNyOTJzVHhZN1hBdXJJTmVuMkdPcEtiR1BpbkZJS3Z2VlFleE11eGZtVlIzYXV2cjU3a2tJZTZta1VSdElzRXVrMks2Y2tQY3EvRXBLOVIyVjBDc3p3ZzQ1d3h1ZjgwWnQvWkxGZUl4NXJoUDVVQlptUXB1b2pDTnhsaUZXdGxZcGxIaFJYSmlQMyt0T1QyN0FUN1BpcGdsdFk3eTFjeDNReDRmbkdMUTEvcFNZZmk3ZjRoMjJmSG9tZzJTc2dCVXBUV3BrcElRWk5KT2h4WU5vNGZIdzF0ZDI4a3J1QjVCK29RRUVGUkkwRzNmYmgxMldoazluTDRVYk82M21zSExTRjdWOWJONUU2alBXRmZ2OEFxVHRFTExPUklWZnhPcE05QVRRb0xRTXJYLzdOQWFMYjhiZDVCZ2pmQUM2bnA2SDdwT3NyQ1FtVDk5TGYxaXVKNHJoeUIzcGpuOWZYUjZqcG4yUFVGYTRBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBSUlCZ0VFQXdJSEJna0RjQmNBQUFBQUFBQUZBQXBwYm5admFXTmxMVFF5QUE9PSJ9LCJ0eXBlIjoiZGVwb3NpdCIsInZvdWNoZXIiOnsiY2hhbm5lbElkIjoiSGpnMlBEZ0x4WURpUVdSSHJKZWVZOVY5aU55ZWJNOU1XdXRvQTY3ZWl2c1oiLCJleHBpcmVzQXQiOjAsIm1heENsYWltYWJsZUFtb3VudCI6IjQwMDAiLCJzaWduYXR1cmUiOiIzV1lOamNtaGQ0c1hvbnhRUHJCcXJGYnNWdDlKb2dGU3RvQVNwajRvMUxUbkx4aTlIZTRiNGU4dEhqc3VDdE1DV0JQa3RvUmZ6R1h4SFNmSjl1WWdhWERSIn19LCJ4NDAyVmVyc2lvbiI6Mn0=" + "x402PaymentHeader": "eyJhY2NlcHRlZCI6eyJhbW91bnQiOiIxMDAwIiwiYXNzZXQiOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsImV4dHJhIjp7ImZlZVBheWVyIjoiSjJ4Y2NSdHVHNDNkckVTTFl6bkhoTGhRa0xUZGZlcGNLWWJpUTlCc0pWYWYiLCJtYXhDbGFpbUNoYW5uZWxzIjoxOCwibWF4U2V0dGxlQ2hhbm5lbHMiOjEzLCJtZW1vIjoiaW52b2ljZS00MiIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwidG9rZW5Qcm9ncmFtIjoiVG9rZW5rZWdRZmVaeWlOd0FKYk5iR0tQRlhDV3VCdmY5U3M2MjNWUTVEQSIsInRyYW5zYWN0aW9uVmVyc2lvbnMiOlswLDFdLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwibWF4VGltZW91dFNlY29uZHMiOjMwMCwibmV0d29yayI6InNvbGFuYTpFdFdUUkFCWmFZcTZpTWZlWUtvdVJ1MTY2VlUyeHFhMSIsInBheVRvIjoiQ1hockZaSkxLcWp6bVAzc2pZTGNGNGRUZVhXS0N5OWUyU1hYWjJZbzZNUFkiLCJzY2hlbWUiOiJiYXRjaC1zZXR0bGVtZW50In0sInBheWxvYWQiOnsiY2hhbm5lbENvbmZpZyI6eyJvcGVuU2xvdCI6MzQxMDAwMDAwLCJwYXllciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicGF5ZXJBdXRob3JpemVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJyZWNlaXZlciI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwicmVjZWl2ZXJBdXRob3JpemVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJzYWx0IjoiNDIiLCJ0b2tlbiI6IjR6TU1DOXNydDVSaTVYMTRHQWdYaGFIaWkzR25QQUVFUllQSmdaSkRuY0RVIiwid2l0aGRyYXdEZWxheSI6MzYwMH0sImRlcG9zaXQiOnsiYW1vdW50IjoiNjAwMCIsInRyYW5zYWN0aW9uIjoiQWdBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFCSno5QWhpMmE2VTRpUWtyeDhlWCt5RGlWVkNXclZja3Jqd1Y2Y2dXS2N4S0ZjSEU1WGE0bmd1dnRBcVIwZUhhaUZ3MUljdEkvVlA2dS9sVlp3NW9RSmdBSUFCQW45RnlRNFdxREhXMlQ3ZU0xZ0w2SFprZjNyOTJzVHhZN1hBdXJJTmVuMkdPcEtiR1BpbkZJS3Z2VlFleE11eGZtVlIzYXV2cjU3a2tJZTZta1VSdElzRXVrMks2Y2tQY3EvRXBLOVIyVjBDc3p3ZzQ1d3h1ZjgwWnQvWkxGZUl4NXJoUDVVQlptUXB1b2pDTnhsaUZXdGxZcGxIaFJYSmlQMyt0T1QyN0FUN1BpcGdsdFk3eTFjeDNReDRmbkdMUTEvcFNZZmk3ZjRoMjJmSG9tZzJTc2dCVXBUV3BrcElRWk5KT2h4WU5vNGZIdzF0ZDI4a3J1QjVCK29RRUVGUkkwRzNmYmgxMldoazluTDRVYk82M21zSExTRjdWOWJONUU2alBXRmZ2OEFxVHRFTExPUklWZnhPcE05QVRRb0xRTXJYLzdOQWFMYjhiZDVCZ2pmQUM2bnA2SDdwT3NyQ1FtVDk5TGYxaXVKNHJoeUIzcGpuOWZYUjZqcG4yUFVGYTRBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBSUlCZ0VFQXdJSEJna0RjQmNBQUFBQUFBQUZBQXBwYm5admFXTmxMVFF5QUE9PSJ9LCJ0eXBlIjoiZGVwb3NpdCIsInZvdWNoZXIiOnsiY2hhbm5lbElkIjoiSGpnMlBEZ0x4WURpUVdSSHJKZWVZOVY5aU55ZWJNOU1XdXRvQTY3ZWl2c1oiLCJleHBpcmVzQXQiOjAsIm1heENsYWltYWJsZUFtb3VudCI6IjQwMDAiLCJzaWduYXR1cmUiOiIzV1lOamNtaGQ0c1hvbnhRUHJCcXJGYnNWdDlKb2dGU3RvQVNwajRvMUxUbkx4aTlIZTRiNGU4dEhqc3VDdE1DV0JQa3RvUmZ6R1h4SFNmSjl1WWdhWERSIn19LCJ4NDAyVmVyc2lvbiI6Mn0=" }, "intent": "x402-batch-settlement", "mode": "verify-transaction", @@ -504,6 +511,8 @@ "asset": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", "extra": { "feePayer": "J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf", + "maxClaimChannels": 18, + "maxSettleChannels": 13, "memo": "invoice-42", "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", "tokenProgram": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", @@ -640,18 +649,18 @@ "recentBlockhash": "11111111111111111111111111111111", "slot": 341000100 }, - "x402PaymentHeader": "eyJhY2NlcHRlZCI6eyJhbW91bnQiOiIxMDAwIiwiYXNzZXQiOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsImV4dHJhIjp7ImZlZVBheWVyIjoiSjJ4Y2NSdHVHNDNkckVTTFl6bkhoTGhRa0xUZGZlcGNLWWJpUTlCc0pWYWYiLCJtZW1vIjoiaW52b2ljZS00MiIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwidG9rZW5Qcm9ncmFtIjoiVG9rZW5rZWdRZmVaeWlOd0FKYk5iR0tQRlhDV3VCdmY5U3M2MjNWUTVEQSIsInRyYW5zYWN0aW9uVmVyc2lvbnMiOlswLDFdLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwibWF4VGltZW91dFNlY29uZHMiOjMwMCwibmV0d29yayI6InNvbGFuYTpFdFdUUkFCWmFZcTZpTWZlWUtvdVJ1MTY2VlUyeHFhMSIsInBheVRvIjoiQ1hockZaSkxLcWp6bVAzc2pZTGNGNGRUZVhXS0N5OWUyU1hYWjJZbzZNUFkiLCJzY2hlbWUiOiJiYXRjaC1zZXR0bGVtZW50In0sInBheWxvYWQiOnsiY2hhbm5lbENvbmZpZyI6eyJvcGVuU2xvdCI6MzQxMDAwMDAwLCJwYXllciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicGF5ZXJBdXRob3JpemVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJyZWNlaXZlciI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwicmVjZWl2ZXJBdXRob3JpemVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJzYWx0IjoiNDIiLCJ0b2tlbiI6IjR6TU1DOXNydDVSaTVYMTRHQWdYaGFIaWkzR25QQUVFUllQSmdaSkRuY0RVIiwid2l0aGRyYXdEZWxheSI6MzYwMH0sImRlcG9zaXQiOnsiYW1vdW50IjoiNjAwMCIsInRyYW5zYWN0aW9uIjoiZ1FJQUJROEFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBTUsvUmNrT0ZxZ3gxdGsrM2pOWUMraDJaSDk2L2RyRThXTzF3THF5RFhwOWhqcVNteGo0cHhTQ3I3MVVIc1RMc1g1bFVkMnJyNitlNUpDSHVwcEZFYlNMQkxwTml1bkpEM0t2eEtTdlVkbGRBck04SU9PY01ibi9OR2JmMlN4WGlNZWE0VCtWQVdaa0ticUl3amNaWWhWclpXS1pSNFVWeVlqOS9yVGs5dXdFK3o0cVlKYldPOHRYTWQwTWVINXhpME5mNlVtSDR1MytJZHRueDZKb05rcklBTUdSbS9sSVJjeS8reXR1bkxEbStlOGpPVzd4ZmNTYXl4RG16cEFBQUFBQlVwVFdwa3BJUVpOSk9oeFlObzRmSHcxdGQyOGtydUI1QitvUUVFRlJJMEczZmJoMTJXaGs5bkw0VWJPNjNtc0hMU0Y3VjliTjVFNmpQV0ZmdjhBcVR0RUxMT1JJVmZ4T3BNOUFUUW9MUU1yWC83TkFhTGI4YmQ1QmdqZkFDNm5wNkg3cE9zckNRbVQ5OUxmMWl1SjRyaHlCM3BqbjlmWFI2anBuMlBVRmE3SUFBQUFBQUFBQUVBTkF3QUFBQUFFQlFBRkFBa0dDUUFHQUFvQUFrQU5Bd0FCQkFNQ0NBY0RjQmNBQUFBQUFBQnBiblp2YVdObExUUXlBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBSnBNQ3BDK3htK1lzOEJ1eThQVkhqbmdyOXczanp5SmtGOXhXdDlBTW1oUk9VMnB6KzBoMEo4VWNBL2hlUndHM0xqd1A2cjFEbkNoQ2c5ZXVkU0E2QVU9In0sInR5cGUiOiJkZXBvc2l0Iiwidm91Y2hlciI6eyJjaGFubmVsSWQiOiJIamcyUERnTHhZRGlRV1JIckplZVk5VjlpTnllYk05TVd1dG9BNjdlaXZzWiIsImV4cGlyZXNBdCI6MCwibWF4Q2xhaW1hYmxlQW1vdW50IjoiNDAwMCIsInNpZ25hdHVyZSI6IjNXWU5qY21oZDRzWG9ueFFQckJxckZic1Z0OUpvZ0ZTdG9BU3BqNG8xTFRuTHhpOUhlNGI0ZTh0SGpzdUN0TUNXQlBrdG9SZnpHWHhIU2ZKOXVZZ2FYRFIifX0sIng0MDJWZXJzaW9uIjoyfQ==" + "x402PaymentHeader": "eyJhY2NlcHRlZCI6eyJhbW91bnQiOiIxMDAwIiwiYXNzZXQiOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsImV4dHJhIjp7ImZlZVBheWVyIjoiSjJ4Y2NSdHVHNDNkckVTTFl6bkhoTGhRa0xUZGZlcGNLWWJpUTlCc0pWYWYiLCJtYXhDbGFpbUNoYW5uZWxzIjoxOCwibWF4U2V0dGxlQ2hhbm5lbHMiOjEzLCJtZW1vIjoiaW52b2ljZS00MiIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwidG9rZW5Qcm9ncmFtIjoiVG9rZW5rZWdRZmVaeWlOd0FKYk5iR0tQRlhDV3VCdmY5U3M2MjNWUTVEQSIsInRyYW5zYWN0aW9uVmVyc2lvbnMiOlswLDFdLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwibWF4VGltZW91dFNlY29uZHMiOjMwMCwibmV0d29yayI6InNvbGFuYTpFdFdUUkFCWmFZcTZpTWZlWUtvdVJ1MTY2VlUyeHFhMSIsInBheVRvIjoiQ1hockZaSkxLcWp6bVAzc2pZTGNGNGRUZVhXS0N5OWUyU1hYWjJZbzZNUFkiLCJzY2hlbWUiOiJiYXRjaC1zZXR0bGVtZW50In0sInBheWxvYWQiOnsiY2hhbm5lbENvbmZpZyI6eyJvcGVuU2xvdCI6MzQxMDAwMDAwLCJwYXllciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicGF5ZXJBdXRob3JpemVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJyZWNlaXZlciI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwicmVjZWl2ZXJBdXRob3JpemVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJzYWx0IjoiNDIiLCJ0b2tlbiI6IjR6TU1DOXNydDVSaTVYMTRHQWdYaGFIaWkzR25QQUVFUllQSmdaSkRuY0RVIiwid2l0aGRyYXdEZWxheSI6MzYwMH0sImRlcG9zaXQiOnsiYW1vdW50IjoiNjAwMCIsInRyYW5zYWN0aW9uIjoiZ1FJQUJROEFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBTUsvUmNrT0ZxZ3gxdGsrM2pOWUMraDJaSDk2L2RyRThXTzF3THF5RFhwOWhqcVNteGo0cHhTQ3I3MVVIc1RMc1g1bFVkMnJyNitlNUpDSHVwcEZFYlNMQkxwTml1bkpEM0t2eEtTdlVkbGRBck04SU9PY01ibi9OR2JmMlN4WGlNZWE0VCtWQVdaa0ticUl3amNaWWhWclpXS1pSNFVWeVlqOS9yVGs5dXdFK3o0cVlKYldPOHRYTWQwTWVINXhpME5mNlVtSDR1MytJZHRueDZKb05rcklBTUdSbS9sSVJjeS8reXR1bkxEbStlOGpPVzd4ZmNTYXl4RG16cEFBQUFBQlVwVFdwa3BJUVpOSk9oeFlObzRmSHcxdGQyOGtydUI1QitvUUVFRlJJMEczZmJoMTJXaGs5bkw0VWJPNjNtc0hMU0Y3VjliTjVFNmpQV0ZmdjhBcVR0RUxMT1JJVmZ4T3BNOUFUUW9MUU1yWC83TkFhTGI4YmQ1QmdqZkFDNm5wNkg3cE9zckNRbVQ5OUxmMWl1SjRyaHlCM3BqbjlmWFI2anBuMlBVRmE3SUFBQUFBQUFBQUVBTkF3QUFBQUFFQlFBRkFBa0dDUUFHQUFvQUFrQU5Bd0FCQkFNQ0NBY0RjQmNBQUFBQUFBQnBiblp2YVdObExUUXlBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBSnBNQ3BDK3htK1lzOEJ1eThQVkhqbmdyOXczanp5SmtGOXhXdDlBTW1oUk9VMnB6KzBoMEo4VWNBL2hlUndHM0xqd1A2cjFEbkNoQ2c5ZXVkU0E2QVU9In0sInR5cGUiOiJkZXBvc2l0Iiwidm91Y2hlciI6eyJjaGFubmVsSWQiOiJIamcyUERnTHhZRGlRV1JIckplZVk5VjlpTnllYk05TVd1dG9BNjdlaXZzWiIsImV4cGlyZXNBdCI6MCwibWF4Q2xhaW1hYmxlQW1vdW50IjoiNDAwMCIsInNpZ25hdHVyZSI6IjNXWU5qY21oZDRzWG9ueFFQckJxckZic1Z0OUpvZ0ZTdG9BU3BqNG8xTFRuTHhpOUhlNGI0ZTh0SGpzdUN0TUNXQlBrdG9SZnpHWHhIU2ZKOXVZZ2FYRFIifX0sIng0MDJWZXJzaW9uIjoyfQ==" }, "intent": "x402-batch-settlement", "mode": "verify-transaction", "provenance": "generated", "requirements": [ - "X402TX-936b492daa" + "X402TX-915632f040" ], "role": "server", "spec": { "doc": "x402-txv1/specs/schemes/batch-settlement/scheme_batch_settlement_svm.md", - "quote": "A version-1 transaction that contains a Compute Budget instruction MUST be rejected.", + "quote": "A version-1 transaction that contains a Compute Budget instruction MUST be rejected (an x402 sponsor rule; the runtime treats such instructions as no-ops).", "section": "Top-level instruction layout" }, "tier": "offline" @@ -670,6 +679,8 @@ "asset": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", "extra": { "feePayer": "J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf", + "maxClaimChannels": 18, + "maxSettleChannels": 13, "memo": "invoice-42", "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", "tokenProgram": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", @@ -806,19 +817,19 @@ "recentBlockhash": "11111111111111111111111111111111", "slot": 341000100 }, - "x402PaymentHeader": "eyJhY2NlcHRlZCI6eyJhbW91bnQiOiIxMDAwIiwiYXNzZXQiOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsImV4dHJhIjp7ImZlZVBheWVyIjoiSjJ4Y2NSdHVHNDNkckVTTFl6bkhoTGhRa0xUZGZlcGNLWWJpUTlCc0pWYWYiLCJtZW1vIjoiaW52b2ljZS00MiIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwidG9rZW5Qcm9ncmFtIjoiVG9rZW5rZWdRZmVaeWlOd0FKYk5iR0tQRlhDV3VCdmY5U3M2MjNWUTVEQSIsInRyYW5zYWN0aW9uVmVyc2lvbnMiOlswLDFdLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwibWF4VGltZW91dFNlY29uZHMiOjMwMCwibmV0d29yayI6InNvbGFuYTpFdFdUUkFCWmFZcTZpTWZlWUtvdVJ1MTY2VlUyeHFhMSIsInBheVRvIjoiQ1hockZaSkxLcWp6bVAzc2pZTGNGNGRUZVhXS0N5OWUyU1hYWjJZbzZNUFkiLCJzY2hlbWUiOiJiYXRjaC1zZXR0bGVtZW50In0sInBheWxvYWQiOnsiY2hhbm5lbENvbmZpZyI6eyJvcGVuU2xvdCI6MzQxMDAwMDAwLCJwYXllciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicGF5ZXJBdXRob3JpemVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJyZWNlaXZlciI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwicmVjZWl2ZXJBdXRob3JpemVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJzYWx0IjoiNDIiLCJ0b2tlbiI6IjR6TU1DOXNydDVSaTVYMTRHQWdYaGFIaWkzR25QQUVFUllQSmdaSkRuY0RVIiwid2l0aGRyYXdEZWxheSI6MzYwMH0sImRlcG9zaXQiOnsiYW1vdW50IjoiNjAwMCIsInRyYW5zYWN0aW9uIjoiZ1FJQUJBZ0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBSUovUmNrT0ZxZ3gxdGsrM2pOWUMraDJaSDk2L2RyRThXTzF3THF5RFhwOWhqcVNteGo0cHhTQ3I3MVVIc1RMc1g1bFVkMnJyNitlNUpDSHVwcEZFYlNMQkxwTml1bkpEM0t2eEtTdlVkbGRBck04SU9PY01ibi9OR2JmMlN4WGlNZWE0VCtWQVdaa0ticUl3amNaWWhWclpXS1pSNFVWeVlqOS9yVGs5dXdFK3o0cVlKYldPOHRYTWQwTWVINXhpME5mNlVtSDR1MytJZHRueDZKb05rcklBVktVMXFaS1NFR1RTVG9jV0RhT0h4OE5iWGR2Sks3Z2VRZnFFQkJCVVNOQnQzMjRkZGxvWlBaeStGR3p1dDVyQnkwaGUxZld6ZVJPb3oxaFg3L0FLazdSQ3l6a1NGWDhUcVRQUUUwS0MwREsxLyt6UUdpMi9HM2VRWUkzd0F1cDZlaCs2VHJLd2tKay9mUzM5WXJpZUs0Y2dkNlk1L1gxMGVvNlo5ajFCV3VBQUFBQkFnR0NRQUZBQW9BQVFRREFnY0dBM0FYQUFBQUFBQUFhVzUyYjJsalpTMDBNZ0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUJCbmEwd2tOaGtCSWNGZFRkSEg5M3Fyc0ROUnBhdnVIZnVrTW16alFFRWlNOEJxcmllQis2L3cyR29LZUhwSGFTd1pUdjJzVFNONlB6Zm5rOGJWMllCIn0sInR5cGUiOiJkZXBvc2l0Iiwidm91Y2hlciI6eyJjaGFubmVsSWQiOiJIamcyUERnTHhZRGlRV1JIckplZVk5VjlpTnllYk05TVd1dG9BNjdlaXZzWiIsImV4cGlyZXNBdCI6MCwibWF4Q2xhaW1hYmxlQW1vdW50IjoiNDAwMCIsInNpZ25hdHVyZSI6IjNXWU5qY21oZDRzWG9ueFFQckJxckZic1Z0OUpvZ0ZTdG9BU3BqNG8xTFRuTHhpOUhlNGI0ZTh0SGpzdUN0TUNXQlBrdG9SZnpHWHhIU2ZKOXVZZ2FYRFIifX0sIng0MDJWZXJzaW9uIjoyfQ==" + "x402PaymentHeader": "eyJhY2NlcHRlZCI6eyJhbW91bnQiOiIxMDAwIiwiYXNzZXQiOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsImV4dHJhIjp7ImZlZVBheWVyIjoiSjJ4Y2NSdHVHNDNkckVTTFl6bkhoTGhRa0xUZGZlcGNLWWJpUTlCc0pWYWYiLCJtYXhDbGFpbUNoYW5uZWxzIjoxOCwibWF4U2V0dGxlQ2hhbm5lbHMiOjEzLCJtZW1vIjoiaW52b2ljZS00MiIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwidG9rZW5Qcm9ncmFtIjoiVG9rZW5rZWdRZmVaeWlOd0FKYk5iR0tQRlhDV3VCdmY5U3M2MjNWUTVEQSIsInRyYW5zYWN0aW9uVmVyc2lvbnMiOlswLDFdLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwibWF4VGltZW91dFNlY29uZHMiOjMwMCwibmV0d29yayI6InNvbGFuYTpFdFdUUkFCWmFZcTZpTWZlWUtvdVJ1MTY2VlUyeHFhMSIsInBheVRvIjoiQ1hockZaSkxLcWp6bVAzc2pZTGNGNGRUZVhXS0N5OWUyU1hYWjJZbzZNUFkiLCJzY2hlbWUiOiJiYXRjaC1zZXR0bGVtZW50In0sInBheWxvYWQiOnsiY2hhbm5lbENvbmZpZyI6eyJvcGVuU2xvdCI6MzQxMDAwMDAwLCJwYXllciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicGF5ZXJBdXRob3JpemVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJyZWNlaXZlciI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwicmVjZWl2ZXJBdXRob3JpemVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJzYWx0IjoiNDIiLCJ0b2tlbiI6IjR6TU1DOXNydDVSaTVYMTRHQWdYaGFIaWkzR25QQUVFUllQSmdaSkRuY0RVIiwid2l0aGRyYXdEZWxheSI6MzYwMH0sImRlcG9zaXQiOnsiYW1vdW50IjoiNjAwMCIsInRyYW5zYWN0aW9uIjoiZ1FJQUJBZ0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBSUovUmNrT0ZxZ3gxdGsrM2pOWUMraDJaSDk2L2RyRThXTzF3THF5RFhwOWhqcVNteGo0cHhTQ3I3MVVIc1RMc1g1bFVkMnJyNitlNUpDSHVwcEZFYlNMQkxwTml1bkpEM0t2eEtTdlVkbGRBck04SU9PY01ibi9OR2JmMlN4WGlNZWE0VCtWQVdaa0ticUl3amNaWWhWclpXS1pSNFVWeVlqOS9yVGs5dXdFK3o0cVlKYldPOHRYTWQwTWVINXhpME5mNlVtSDR1MytJZHRueDZKb05rcklBVktVMXFaS1NFR1RTVG9jV0RhT0h4OE5iWGR2Sks3Z2VRZnFFQkJCVVNOQnQzMjRkZGxvWlBaeStGR3p1dDVyQnkwaGUxZld6ZVJPb3oxaFg3L0FLazdSQ3l6a1NGWDhUcVRQUUUwS0MwREsxLyt6UUdpMi9HM2VRWUkzd0F1cDZlaCs2VHJLd2tKay9mUzM5WXJpZUs0Y2dkNlk1L1gxMGVvNlo5ajFCV3VBQUFBQkFnR0NRQUZBQW9BQVFRREFnY0dBM0FYQUFBQUFBQUFhVzUyYjJsalpTMDBNZ0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUJCbmEwd2tOaGtCSWNGZFRkSEg5M3Fyc0ROUnBhdnVIZnVrTW16alFFRWlNOEJxcmllQis2L3cyR29LZUhwSGFTd1pUdjJzVFNONlB6Zm5rOGJWMllCIn0sInR5cGUiOiJkZXBvc2l0Iiwidm91Y2hlciI6eyJjaGFubmVsSWQiOiJIamcyUERnTHhZRGlRV1JIckplZVk5VjlpTnllYk05TVd1dG9BNjdlaXZzWiIsImV4cGlyZXNBdCI6MCwibWF4Q2xhaW1hYmxlQW1vdW50IjoiNDAwMCIsInNpZ25hdHVyZSI6IjNXWU5qY21oZDRzWG9ueFFQckJxckZic1Z0OUpvZ0ZTdG9BU3BqNG8xTFRuTHhpOUhlNGI0ZTh0SGpzdUN0TUNXQlBrdG9SZnpHWHhIU2ZKOXVZZ2FYRFIifX0sIng0MDJWZXJzaW9uIjoyfQ==" }, "intent": "x402-batch-settlement", "mode": "verify-transaction", "provenance": "generated", "requirements": [ - "X402TX-0f874a9c63", - "X402TX-644919eb3b" + "X402TX-703c03cfb5", + "X402TX-f9bcc1a14a" ], "role": "server", "spec": { "doc": "x402-txv1/specs/schemes/batch-settlement/scheme_batch_settlement_svm.md", - "quote": "`computeUnitLimit` MUST be present and MUST NOT exceed `400000`", + "quote": "`computeUnitLimit` (bit 2) MUST be set and MUST NOT exceed `400000`", "section": "Top-level instruction layout" }, "tier": "offline" @@ -837,6 +848,8 @@ "asset": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", "extra": { "feePayer": "J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf", + "maxClaimChannels": 18, + "maxSettleChannels": 13, "memo": "invoice-42", "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", "tokenProgram": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", @@ -973,19 +986,19 @@ "recentBlockhash": "11111111111111111111111111111111", "slot": 341000100 }, - "x402PaymentHeader": "eyJhY2NlcHRlZCI6eyJhbW91bnQiOiIxMDAwIiwiYXNzZXQiOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsImV4dHJhIjp7ImZlZVBheWVyIjoiSjJ4Y2NSdHVHNDNkckVTTFl6bkhoTGhRa0xUZGZlcGNLWWJpUTlCc0pWYWYiLCJtZW1vIjoiaW52b2ljZS00MiIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwidG9rZW5Qcm9ncmFtIjoiVG9rZW5rZWdRZmVaeWlOd0FKYk5iR0tQRlhDV3VCdmY5U3M2MjNWUTVEQSIsInRyYW5zYWN0aW9uVmVyc2lvbnMiOlswLDFdLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwibWF4VGltZW91dFNlY29uZHMiOjMwMCwibmV0d29yayI6InNvbGFuYTpFdFdUUkFCWmFZcTZpTWZlWUtvdVJ1MTY2VlUyeHFhMSIsInBheVRvIjoiQ1hockZaSkxLcWp6bVAzc2pZTGNGNGRUZVhXS0N5OWUyU1hYWjJZbzZNUFkiLCJzY2hlbWUiOiJiYXRjaC1zZXR0bGVtZW50In0sInBheWxvYWQiOnsiY2hhbm5lbENvbmZpZyI6eyJvcGVuU2xvdCI6MzQxMDAwMDAwLCJwYXllciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicGF5ZXJBdXRob3JpemVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJyZWNlaXZlciI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwicmVjZWl2ZXJBdXRob3JpemVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJzYWx0IjoiNDIiLCJ0b2tlbiI6IjR6TU1DOXNydDVSaTVYMTRHQWdYaGFIaWkzR25QQUVFUllQSmdaSkRuY0RVIiwid2l0aGRyYXdEZWxheSI6MzYwMH0sImRlcG9zaXQiOnsiYW1vdW50IjoiNjAwMCIsInRyYW5zYWN0aW9uIjoiZ1FJQUJBUUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBSUovUmNrT0ZxZ3gxdGsrM2pOWUMraDJaSDk2L2RyRThXTzF3THF5RFhwOWhqcVNteGo0cHhTQ3I3MVVIc1RMc1g1bFVkMnJyNitlNUpDSHVwcEZFYlNMQkxwTml1bkpEM0t2eEtTdlVkbGRBck04SU9PY01ibi9OR2JmMlN4WGlNZWE0VCtWQVdaa0ticUl3amNaWWhWclpXS1pSNFVWeVlqOS9yVGs5dXdFK3o0cVlKYldPOHRYTWQwTWVINXhpME5mNlVtSDR1MytJZHRueDZKb05rcklBVktVMXFaS1NFR1RTVG9jV0RhT0h4OE5iWGR2Sks3Z2VRZnFFQkJCVVNOQnQzMjRkZGxvWlBaeStGR3p1dDVyQnkwaGUxZld6ZVJPb3oxaFg3L0FLazdSQ3l6a1NGWDhUcVRQUUUwS0MwREsxLyt6UUdpMi9HM2VRWUkzd0F1cDZlaCs2VHJLd2tKay9mUzM5WXJpZUs0Y2dkNlk1L1gxMGVvNlo5ajFCV3VRQTBEQUFnR0NRQUZBQW9BQVFRREFnY0dBM0FYQUFBQUFBQUFhVzUyYjJsalpTMDBNZ0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUJsMnZiR0xidmFGOVVFVHlvQ0ZsQ3BmZFJvWjMxRmQxOGNZOGlrYitCLzZzRnpBeHhyc241Zzl1THVOZkJsWmNOQnlFMTRsSzFPMkI4cGdnTC9QR3dPIn0sInR5cGUiOiJkZXBvc2l0Iiwidm91Y2hlciI6eyJjaGFubmVsSWQiOiJIamcyUERnTHhZRGlRV1JIckplZVk5VjlpTnllYk05TVd1dG9BNjdlaXZzWiIsImV4cGlyZXNBdCI6MCwibWF4Q2xhaW1hYmxlQW1vdW50IjoiNDAwMCIsInNpZ25hdHVyZSI6IjNXWU5qY21oZDRzWG9ueFFQckJxckZic1Z0OUpvZ0ZTdG9BU3BqNG8xTFRuTHhpOUhlNGI0ZTh0SGpzdUN0TUNXQlBrdG9SZnpHWHhIU2ZKOXVZZ2FYRFIifX0sIng0MDJWZXJzaW9uIjoyfQ==" + "x402PaymentHeader": "eyJhY2NlcHRlZCI6eyJhbW91bnQiOiIxMDAwIiwiYXNzZXQiOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsImV4dHJhIjp7ImZlZVBheWVyIjoiSjJ4Y2NSdHVHNDNkckVTTFl6bkhoTGhRa0xUZGZlcGNLWWJpUTlCc0pWYWYiLCJtYXhDbGFpbUNoYW5uZWxzIjoxOCwibWF4U2V0dGxlQ2hhbm5lbHMiOjEzLCJtZW1vIjoiaW52b2ljZS00MiIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwidG9rZW5Qcm9ncmFtIjoiVG9rZW5rZWdRZmVaeWlOd0FKYk5iR0tQRlhDV3VCdmY5U3M2MjNWUTVEQSIsInRyYW5zYWN0aW9uVmVyc2lvbnMiOlswLDFdLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwibWF4VGltZW91dFNlY29uZHMiOjMwMCwibmV0d29yayI6InNvbGFuYTpFdFdUUkFCWmFZcTZpTWZlWUtvdVJ1MTY2VlUyeHFhMSIsInBheVRvIjoiQ1hockZaSkxLcWp6bVAzc2pZTGNGNGRUZVhXS0N5OWUyU1hYWjJZbzZNUFkiLCJzY2hlbWUiOiJiYXRjaC1zZXR0bGVtZW50In0sInBheWxvYWQiOnsiY2hhbm5lbENvbmZpZyI6eyJvcGVuU2xvdCI6MzQxMDAwMDAwLCJwYXllciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicGF5ZXJBdXRob3JpemVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJyZWNlaXZlciI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwicmVjZWl2ZXJBdXRob3JpemVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJzYWx0IjoiNDIiLCJ0b2tlbiI6IjR6TU1DOXNydDVSaTVYMTRHQWdYaGFIaWkzR25QQUVFUllQSmdaSkRuY0RVIiwid2l0aGRyYXdEZWxheSI6MzYwMH0sImRlcG9zaXQiOnsiYW1vdW50IjoiNjAwMCIsInRyYW5zYWN0aW9uIjoiZ1FJQUJBUUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBSUovUmNrT0ZxZ3gxdGsrM2pOWUMraDJaSDk2L2RyRThXTzF3THF5RFhwOWhqcVNteGo0cHhTQ3I3MVVIc1RMc1g1bFVkMnJyNitlNUpDSHVwcEZFYlNMQkxwTml1bkpEM0t2eEtTdlVkbGRBck04SU9PY01ibi9OR2JmMlN4WGlNZWE0VCtWQVdaa0ticUl3amNaWWhWclpXS1pSNFVWeVlqOS9yVGs5dXdFK3o0cVlKYldPOHRYTWQwTWVINXhpME5mNlVtSDR1MytJZHRueDZKb05rcklBVktVMXFaS1NFR1RTVG9jV0RhT0h4OE5iWGR2Sks3Z2VRZnFFQkJCVVNOQnQzMjRkZGxvWlBaeStGR3p1dDVyQnkwaGUxZld6ZVJPb3oxaFg3L0FLazdSQ3l6a1NGWDhUcVRQUUUwS0MwREsxLyt6UUdpMi9HM2VRWUkzd0F1cDZlaCs2VHJLd2tKay9mUzM5WXJpZUs0Y2dkNlk1L1gxMGVvNlo5ajFCV3VRQTBEQUFnR0NRQUZBQW9BQVFRREFnY0dBM0FYQUFBQUFBQUFhVzUyYjJsalpTMDBNZ0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUJsMnZiR0xidmFGOVVFVHlvQ0ZsQ3BmZFJvWjMxRmQxOGNZOGlrYitCLzZzRnpBeHhyc241Zzl1THVOZkJsWmNOQnlFMTRsSzFPMkI4cGdnTC9QR3dPIn0sInR5cGUiOiJkZXBvc2l0Iiwidm91Y2hlciI6eyJjaGFubmVsSWQiOiJIamcyUERnTHhZRGlRV1JIckplZVk5VjlpTnllYk05TVd1dG9BNjdlaXZzWiIsImV4cGlyZXNBdCI6MCwibWF4Q2xhaW1hYmxlQW1vdW50IjoiNDAwMCIsInNpZ25hdHVyZSI6IjNXWU5qY21oZDRzWG9ueFFQckJxckZic1Z0OUpvZ0ZTdG9BU3BqNG8xTFRuTHhpOUhlNGI0ZTh0SGpzdUN0TUNXQlBrdG9SZnpHWHhIU2ZKOXVZZ2FYRFIifX0sIng0MDJWZXJzaW9uIjoyfQ==" }, "intent": "x402-batch-settlement", "mode": "verify-transaction", "provenance": "generated", "requirements": [ - "X402TX-0f874a9c63", - "X402TX-644919eb3b" + "X402TX-703c03cfb5", + "X402TX-f9bcc1a14a" ], "role": "server", "spec": { "doc": "x402-txv1/specs/schemes/batch-settlement/scheme_batch_settlement_svm.md", - "quote": "`loadedAccountsDataSizeLimit` MUST be present", + "quote": "`loadedAccountsDataSizeLimit` (bit 3) MUST be set", "section": "Top-level instruction layout" }, "tier": "offline" @@ -1003,6 +1016,8 @@ "asset": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", "extra": { "feePayer": "J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf", + "maxClaimChannels": 18, + "maxSettleChannels": 13, "memo": "invoice-42", "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", "tokenProgram": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", @@ -1139,19 +1154,19 @@ "recentBlockhash": "11111111111111111111111111111111", "slot": 341000100 }, - "x402PaymentHeader": "eyJhY2NlcHRlZCI6eyJhbW91bnQiOiIxMDAwIiwiYXNzZXQiOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsImV4dHJhIjp7ImZlZVBheWVyIjoiSjJ4Y2NSdHVHNDNkckVTTFl6bkhoTGhRa0xUZGZlcGNLWWJpUTlCc0pWYWYiLCJtZW1vIjoiaW52b2ljZS00MiIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwidG9rZW5Qcm9ncmFtIjoiVG9rZW5rZWdRZmVaeWlOd0FKYk5iR0tQRlhDV3VCdmY5U3M2MjNWUTVEQSIsInRyYW5zYWN0aW9uVmVyc2lvbnMiOlswLDFdLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwibWF4VGltZW91dFNlY29uZHMiOjMwMCwibmV0d29yayI6InNvbGFuYTpFdFdUUkFCWmFZcTZpTWZlWUtvdVJ1MTY2VlUyeHFhMSIsInBheVRvIjoiQ1hockZaSkxLcWp6bVAzc2pZTGNGNGRUZVhXS0N5OWUyU1hYWjJZbzZNUFkiLCJzY2hlbWUiOiJiYXRjaC1zZXR0bGVtZW50In0sInBheWxvYWQiOnsiY2hhbm5lbENvbmZpZyI6eyJvcGVuU2xvdCI6MzQxMDAwMDAwLCJwYXllciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicGF5ZXJBdXRob3JpemVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJyZWNlaXZlciI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwicmVjZWl2ZXJBdXRob3JpemVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJzYWx0IjoiNDIiLCJ0b2tlbiI6IjR6TU1DOXNydDVSaTVYMTRHQWdYaGFIaWkzR25QQUVFUllQSmdaSkRuY0RVIiwid2l0aGRyYXdEZWxheSI6MzYwMH0sImRlcG9zaXQiOnsiYW1vdW50IjoiNjAwMCIsInRyYW5zYWN0aW9uIjoiZ1FJQUJBOEFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBSUovUmNrT0ZxZ3gxdGsrM2pOWUMraDJaSDk2L2RyRThXTzF3THF5RFhwOWhqcVNteGo0cHhTQ3I3MVVIc1RMc1g1bFVkMnJyNitlNUpDSHVwcEZFYlNMQkxwTml1bkpEM0t2eEtTdlVkbGRBck04SU9PY01ibi9OR2JmMlN4WGlNZWE0VCtWQVdaa0ticUl3amNaWWhWclpXS1pSNFVWeVlqOS9yVGs5dXdFK3o0cVlKYldPOHRYTWQwTWVINXhpME5mNlVtSDR1MytJZHRueDZKb05rcklBVktVMXFaS1NFR1RTVG9jV0RhT0h4OE5iWGR2Sks3Z2VRZnFFQkJCVVNOQnQzMjRkZGxvWlBaeStGR3p1dDVyQnkwaGUxZld6ZVJPb3oxaFg3L0FLazdSQ3l6a1NGWDhUcVRQUUUwS0MwREsxLyt6UUdpMi9HM2VRWUkzd0F1cDZlaCs2VHJLd2tKay9mUzM5WXJpZUs0Y2dkNlk1L1gxMGVvNlo5ajFCV3V5QUFBQUFBQUFBQkFEUU1BQUFBQUFnZ0dDUUFGQUFvQUFRUURBZ2NHQTNBWEFBQUFBQUFBYVc1MmIybGpaUzAwTWdBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBWTVYODBtS1I5ditpYU9BVXMvT1RpZkZiMTZBSnQ5MmtQRmtkT3V3a05hdUwwY0wrTkFXSlJOVk1tajN4TW9EaDRwUUNkUTl2KzlHNnQ4bjRLYVNFRyJ9LCJ0eXBlIjoiZGVwb3NpdCIsInZvdWNoZXIiOnsiY2hhbm5lbElkIjoiSGpnMlBEZ0x4WURpUVdSSHJKZWVZOVY5aU55ZWJNOU1XdXRvQTY3ZWl2c1oiLCJleHBpcmVzQXQiOjAsIm1heENsYWltYWJsZUFtb3VudCI6IjQwMDAiLCJzaWduYXR1cmUiOiIzV1lOamNtaGQ0c1hvbnhRUHJCcXJGYnNWdDlKb2dGU3RvQVNwajRvMUxUbkx4aTlIZTRiNGU4dEhqc3VDdE1DV0JQa3RvUmZ6R1h4SFNmSjl1WWdhWERSIn19LCJ4NDAyVmVyc2lvbiI6Mn0=" + "x402PaymentHeader": "eyJhY2NlcHRlZCI6eyJhbW91bnQiOiIxMDAwIiwiYXNzZXQiOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsImV4dHJhIjp7ImZlZVBheWVyIjoiSjJ4Y2NSdHVHNDNkckVTTFl6bkhoTGhRa0xUZGZlcGNLWWJpUTlCc0pWYWYiLCJtYXhDbGFpbUNoYW5uZWxzIjoxOCwibWF4U2V0dGxlQ2hhbm5lbHMiOjEzLCJtZW1vIjoiaW52b2ljZS00MiIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwidG9rZW5Qcm9ncmFtIjoiVG9rZW5rZWdRZmVaeWlOd0FKYk5iR0tQRlhDV3VCdmY5U3M2MjNWUTVEQSIsInRyYW5zYWN0aW9uVmVyc2lvbnMiOlswLDFdLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwibWF4VGltZW91dFNlY29uZHMiOjMwMCwibmV0d29yayI6InNvbGFuYTpFdFdUUkFCWmFZcTZpTWZlWUtvdVJ1MTY2VlUyeHFhMSIsInBheVRvIjoiQ1hockZaSkxLcWp6bVAzc2pZTGNGNGRUZVhXS0N5OWUyU1hYWjJZbzZNUFkiLCJzY2hlbWUiOiJiYXRjaC1zZXR0bGVtZW50In0sInBheWxvYWQiOnsiY2hhbm5lbENvbmZpZyI6eyJvcGVuU2xvdCI6MzQxMDAwMDAwLCJwYXllciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicGF5ZXJBdXRob3JpemVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJyZWNlaXZlciI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwicmVjZWl2ZXJBdXRob3JpemVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJzYWx0IjoiNDIiLCJ0b2tlbiI6IjR6TU1DOXNydDVSaTVYMTRHQWdYaGFIaWkzR25QQUVFUllQSmdaSkRuY0RVIiwid2l0aGRyYXdEZWxheSI6MzYwMH0sImRlcG9zaXQiOnsiYW1vdW50IjoiNjAwMCIsInRyYW5zYWN0aW9uIjoiZ1FJQUJBOEFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBSUovUmNrT0ZxZ3gxdGsrM2pOWUMraDJaSDk2L2RyRThXTzF3THF5RFhwOWhqcVNteGo0cHhTQ3I3MVVIc1RMc1g1bFVkMnJyNitlNUpDSHVwcEZFYlNMQkxwTml1bkpEM0t2eEtTdlVkbGRBck04SU9PY01ibi9OR2JmMlN4WGlNZWE0VCtWQVdaa0ticUl3amNaWWhWclpXS1pSNFVWeVlqOS9yVGs5dXdFK3o0cVlKYldPOHRYTWQwTWVINXhpME5mNlVtSDR1MytJZHRueDZKb05rcklBVktVMXFaS1NFR1RTVG9jV0RhT0h4OE5iWGR2Sks3Z2VRZnFFQkJCVVNOQnQzMjRkZGxvWlBaeStGR3p1dDVyQnkwaGUxZld6ZVJPb3oxaFg3L0FLazdSQ3l6a1NGWDhUcVRQUUUwS0MwREsxLyt6UUdpMi9HM2VRWUkzd0F1cDZlaCs2VHJLd2tKay9mUzM5WXJpZUs0Y2dkNlk1L1gxMGVvNlo5ajFCV3V5QUFBQUFBQUFBQkFEUU1BQUFBQUFnZ0dDUUFGQUFvQUFRUURBZ2NHQTNBWEFBQUFBQUFBYVc1MmIybGpaUzAwTWdBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBWTVYODBtS1I5ditpYU9BVXMvT1RpZkZiMTZBSnQ5MmtQRmtkT3V3a05hdUwwY0wrTkFXSlJOVk1tajN4TW9EaDRwUUNkUTl2KzlHNnQ4bjRLYVNFRyJ9LCJ0eXBlIjoiZGVwb3NpdCIsInZvdWNoZXIiOnsiY2hhbm5lbElkIjoiSGpnMlBEZ0x4WURpUVdSSHJKZWVZOVY5aU55ZWJNOU1XdXRvQTY3ZWl2c1oiLCJleHBpcmVzQXQiOjAsIm1heENsYWltYWJsZUFtb3VudCI6IjQwMDAiLCJzaWduYXR1cmUiOiIzV1lOamNtaGQ0c1hvbnhRUHJCcXJGYnNWdDlKb2dGU3RvQVNwajRvMUxUbkx4aTlIZTRiNGU4dEhqc3VDdE1DV0JQa3RvUmZ6R1h4SFNmSjl1WWdhWERSIn19LCJ4NDAyVmVyc2lvbiI6Mn0=" }, "intent": "x402-batch-settlement", "mode": "verify-transaction", "provenance": "authored", "requirements": [ - "X402TX-0f874a9c63", - "X402TX-644919eb3b" + "X402TX-703c03cfb5", + "X402TX-f9bcc1a14a" ], "role": "server", "spec": { "doc": "x402-txv1/specs/schemes/batch-settlement/scheme_batch_settlement_svm.md", - "quote": "`loadedAccountsDataSizeLimit` MUST be present", + "quote": "`loadedAccountsDataSizeLimit` (bit 3) MUST be set", "section": "Top-level instruction layout" }, "tier": "offline" @@ -1170,6 +1185,8 @@ "asset": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", "extra": { "feePayer": "J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf", + "maxClaimChannels": 18, + "maxSettleChannels": 13, "memo": "invoice-42", "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", "tokenProgram": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", @@ -1306,25 +1323,25 @@ "recentBlockhash": "11111111111111111111111111111111", "slot": 341000100 }, - "x402PaymentHeader": "eyJhY2NlcHRlZCI6eyJhbW91bnQiOiIxMDAwIiwiYXNzZXQiOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsImV4dHJhIjp7ImZlZVBheWVyIjoiSjJ4Y2NSdHVHNDNkckVTTFl6bkhoTGhRa0xUZGZlcGNLWWJpUTlCc0pWYWYiLCJtZW1vIjoiaW52b2ljZS00MiIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwidG9rZW5Qcm9ncmFtIjoiVG9rZW5rZWdRZmVaeWlOd0FKYk5iR0tQRlhDV3VCdmY5U3M2MjNWUTVEQSIsInRyYW5zYWN0aW9uVmVyc2lvbnMiOlswLDFdLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwibWF4VGltZW91dFNlY29uZHMiOjMwMCwibmV0d29yayI6InNvbGFuYTpFdFdUUkFCWmFZcTZpTWZlWUtvdVJ1MTY2VlUyeHFhMSIsInBheVRvIjoiQ1hockZaSkxLcWp6bVAzc2pZTGNGNGRUZVhXS0N5OWUyU1hYWjJZbzZNUFkiLCJzY2hlbWUiOiJiYXRjaC1zZXR0bGVtZW50In0sInBheWxvYWQiOnsiY2hhbm5lbENvbmZpZyI6eyJvcGVuU2xvdCI6MzQxMDAwMDAwLCJwYXllciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicGF5ZXJBdXRob3JpemVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJyZWNlaXZlciI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwicmVjZWl2ZXJBdXRob3JpemVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJzYWx0IjoiNDIiLCJ0b2tlbiI6IjR6TU1DOXNydDVSaTVYMTRHQWdYaGFIaWkzR25QQUVFUllQSmdaSkRuY0RVIiwid2l0aGRyYXdEZWxheSI6MzYwMH0sImRlcG9zaXQiOnsiYW1vdW50IjoiNjAwMCIsInRyYW5zYWN0aW9uIjoiZ1FJQUJBOEFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBSUovUmNrT0ZxZ3gxdGsrM2pOWUMraDJaSDk2L2RyRThXTzF3THF5RFhwOWhqcVNteGo0cHhTQ3I3MVVIc1RMc1g1bFVkMnJyNitlNUpDSHVwcEZFYlNMQkxwTml1bkpEM0t2eEtTdlVkbGRBck04SU9PY01ibi9OR2JmMlN4WGlNZWE0VCtWQVdaa0ticUl3amNaWWhWclpXS1pSNFVWeVlqOS9yVGs5dXdFK3o0cVlKYldPOHRYTWQwTWVINXhpME5mNlVtSDR1MytJZHRueDZKb05rcklBVktVMXFaS1NFR1RTVG9jV0RhT0h4OE5iWGR2Sks3Z2VRZnFFQkJCVVNOQnQzMjRkZGxvWlBaeStGR3p1dDVyQnkwaGUxZld6ZVJPb3oxaFg3L0FLazdSQ3l6a1NGWDhUcVRQUUUwS0MwREsxLyt6UUdpMi9HM2VRWUkzd0F1cDZlaCs2VHJLd2tKay9mUzM5WXJpZUs0Y2dkNlk1L1gxMGVvNlo5ajFCV3V5QUFBQUFBQUFBQ0JHZ1lBQUFBQUJBZ0dDUUFGQUFvQUFRUURBZ2NHQTNBWEFBQUFBQUFBYVc1MmIybGpaUzAwTWdBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFDSlJZcGlEdUJjQnNyL1FGMnhFeDhYMUN0U2JNTUxDS0lVbTB0dU1iRVN4OWdpdEZscWREU0l6UGJsNG9Ec1V3bVVwZXAyZExSL1MvSjgwbTI2QTRrSiJ9LCJ0eXBlIjoiZGVwb3NpdCIsInZvdWNoZXIiOnsiY2hhbm5lbElkIjoiSGpnMlBEZ0x4WURpUVdSSHJKZWVZOVY5aU55ZWJNOU1XdXRvQTY3ZWl2c1oiLCJleHBpcmVzQXQiOjAsIm1heENsYWltYWJsZUFtb3VudCI6IjQwMDAiLCJzaWduYXR1cmUiOiIzV1lOamNtaGQ0c1hvbnhRUHJCcXJGYnNWdDlKb2dGU3RvQVNwajRvMUxUbkx4aTlIZTRiNGU4dEhqc3VDdE1DV0JQa3RvUmZ6R1h4SFNmSjl1WWdhWERSIn19LCJ4NDAyVmVyc2lvbiI6Mn0=" + "x402PaymentHeader": "eyJhY2NlcHRlZCI6eyJhbW91bnQiOiIxMDAwIiwiYXNzZXQiOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsImV4dHJhIjp7ImZlZVBheWVyIjoiSjJ4Y2NSdHVHNDNkckVTTFl6bkhoTGhRa0xUZGZlcGNLWWJpUTlCc0pWYWYiLCJtYXhDbGFpbUNoYW5uZWxzIjoxOCwibWF4U2V0dGxlQ2hhbm5lbHMiOjEzLCJtZW1vIjoiaW52b2ljZS00MiIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwidG9rZW5Qcm9ncmFtIjoiVG9rZW5rZWdRZmVaeWlOd0FKYk5iR0tQRlhDV3VCdmY5U3M2MjNWUTVEQSIsInRyYW5zYWN0aW9uVmVyc2lvbnMiOlswLDFdLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwibWF4VGltZW91dFNlY29uZHMiOjMwMCwibmV0d29yayI6InNvbGFuYTpFdFdUUkFCWmFZcTZpTWZlWUtvdVJ1MTY2VlUyeHFhMSIsInBheVRvIjoiQ1hockZaSkxLcWp6bVAzc2pZTGNGNGRUZVhXS0N5OWUyU1hYWjJZbzZNUFkiLCJzY2hlbWUiOiJiYXRjaC1zZXR0bGVtZW50In0sInBheWxvYWQiOnsiY2hhbm5lbENvbmZpZyI6eyJvcGVuU2xvdCI6MzQxMDAwMDAwLCJwYXllciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicGF5ZXJBdXRob3JpemVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJyZWNlaXZlciI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwicmVjZWl2ZXJBdXRob3JpemVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJzYWx0IjoiNDIiLCJ0b2tlbiI6IjR6TU1DOXNydDVSaTVYMTRHQWdYaGFIaWkzR25QQUVFUllQSmdaSkRuY0RVIiwid2l0aGRyYXdEZWxheSI6MzYwMH0sImRlcG9zaXQiOnsiYW1vdW50IjoiNjAwMCIsInRyYW5zYWN0aW9uIjoiZ1FJQUJBOEFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBSUovUmNrT0ZxZ3gxdGsrM2pOWUMraDJaSDk2L2RyRThXTzF3THF5RFhwOWhqcVNteGo0cHhTQ3I3MVVIc1RMc1g1bFVkMnJyNitlNUpDSHVwcEZFYlNMQkxwTml1bkpEM0t2eEtTdlVkbGRBck04SU9PY01ibi9OR2JmMlN4WGlNZWE0VCtWQVdaa0ticUl3amNaWWhWclpXS1pSNFVWeVlqOS9yVGs5dXdFK3o0cVlKYldPOHRYTWQwTWVINXhpME5mNlVtSDR1MytJZHRueDZKb05rcklBVktVMXFaS1NFR1RTVG9jV0RhT0h4OE5iWGR2Sks3Z2VRZnFFQkJCVVNOQnQzMjRkZGxvWlBaeStGR3p1dDVyQnkwaGUxZld6ZVJPb3oxaFg3L0FLazdSQ3l6a1NGWDhUcVRQUUUwS0MwREsxLyt6UUdpMi9HM2VRWUkzd0F1cDZlaCs2VHJLd2tKay9mUzM5WXJpZUs0Y2dkNlk1L1gxMGVvNlo5ajFCV3V5QUFBQUFBQUFBQ0JHZ1lBQUFBQUJBZ0dDUUFGQUFvQUFRUURBZ2NHQTNBWEFBQUFBQUFBYVc1MmIybGpaUzAwTWdBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFDSlJZcGlEdUJjQnNyL1FGMnhFeDhYMUN0U2JNTUxDS0lVbTB0dU1iRVN4OWdpdEZscWREU0l6UGJsNG9Ec1V3bVVwZXAyZExSL1MvSjgwbTI2QTRrSiJ9LCJ0eXBlIjoiZGVwb3NpdCIsInZvdWNoZXIiOnsiY2hhbm5lbElkIjoiSGpnMlBEZ0x4WURpUVdSSHJKZWVZOVY5aU55ZWJNOU1XdXRvQTY3ZWl2c1oiLCJleHBpcmVzQXQiOjAsIm1heENsYWltYWJsZUFtb3VudCI6IjQwMDAiLCJzaWduYXR1cmUiOiIzV1lOamNtaGQ0c1hvbnhRUHJCcXJGYnNWdDlKb2dGU3RvQVNwajRvMUxUbkx4aTlIZTRiNGU4dEhqc3VDdE1DV0JQa3RvUmZ6R1h4SFNmSjl1WWdhWERSIn19LCJ4NDAyVmVyc2lvbiI6Mn0=" }, "intent": "x402-batch-settlement", "mode": "verify-transaction", "provenance": "generated", "requirements": [ - "X402TX-0f874a9c63" + "X402TX-703c03cfb5" ], "role": "server", "spec": { "doc": "x402-txv1/specs/schemes/batch-settlement/scheme_batch_settlement_svm.md", - "quote": "`computeUnitLimit` MUST be present and MUST NOT exceed `400000`", + "quote": "`computeUnitLimit` (bit 2) MUST be set and MUST NOT exceed `400000`", "section": "Top-level instruction layout" }, "tier": "offline" }, { "bugType": "auth-bypass", - "description": "priorityFee 1000001 lamports at computeUnitLimit 200000: 1000001 × 10^6 > 5000000 × 200000 (one lamport over the cap).", + "description": "priorityFee 1501 lamports at computeUnitLimit 300: 1501 × 10^6 > 5000000 × 300 (one lamport over the cap), and still under the sponsor's 2000 lamport cap on the total fee, so only the per-unit rule rejects it.", "expect": { "outcome": "reject", "rejectCode": "setup-transaction" @@ -1336,6 +1353,8 @@ "asset": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", "extra": { "feePayer": "J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf", + "maxClaimChannels": 18, + "maxSettleChannels": 13, "memo": "invoice-42", "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", "tokenProgram": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", @@ -1472,13 +1491,13 @@ "recentBlockhash": "11111111111111111111111111111111", "slot": 341000100 }, - "x402PaymentHeader": "eyJhY2NlcHRlZCI6eyJhbW91bnQiOiIxMDAwIiwiYXNzZXQiOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsImV4dHJhIjp7ImZlZVBheWVyIjoiSjJ4Y2NSdHVHNDNkckVTTFl6bkhoTGhRa0xUZGZlcGNLWWJpUTlCc0pWYWYiLCJtZW1vIjoiaW52b2ljZS00MiIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwidG9rZW5Qcm9ncmFtIjoiVG9rZW5rZWdRZmVaeWlOd0FKYk5iR0tQRlhDV3VCdmY5U3M2MjNWUTVEQSIsInRyYW5zYWN0aW9uVmVyc2lvbnMiOlswLDFdLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwibWF4VGltZW91dFNlY29uZHMiOjMwMCwibmV0d29yayI6InNvbGFuYTpFdFdUUkFCWmFZcTZpTWZlWUtvdVJ1MTY2VlUyeHFhMSIsInBheVRvIjoiQ1hockZaSkxLcWp6bVAzc2pZTGNGNGRUZVhXS0N5OWUyU1hYWjJZbzZNUFkiLCJzY2hlbWUiOiJiYXRjaC1zZXR0bGVtZW50In0sInBheWxvYWQiOnsiY2hhbm5lbENvbmZpZyI6eyJvcGVuU2xvdCI6MzQxMDAwMDAwLCJwYXllciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicGF5ZXJBdXRob3JpemVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJyZWNlaXZlciI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwicmVjZWl2ZXJBdXRob3JpemVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJzYWx0IjoiNDIiLCJ0b2tlbiI6IjR6TU1DOXNydDVSaTVYMTRHQWdYaGFIaWkzR25QQUVFUllQSmdaSkRuY0RVIiwid2l0aGRyYXdEZWxheSI6MzYwMH0sImRlcG9zaXQiOnsiYW1vdW50IjoiNjAwMCIsInRyYW5zYWN0aW9uIjoiZ1FJQUJBOEFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBSUovUmNrT0ZxZ3gxdGsrM2pOWUMraDJaSDk2L2RyRThXTzF3THF5RFhwOWhqcVNteGo0cHhTQ3I3MVVIc1RMc1g1bFVkMnJyNitlNUpDSHVwcEZFYlNMQkxwTml1bkpEM0t2eEtTdlVkbGRBck04SU9PY01ibi9OR2JmMlN4WGlNZWE0VCtWQVdaa0ticUl3amNaWWhWclpXS1pSNFVWeVlqOS9yVGs5dXdFK3o0cVlKYldPOHRYTWQwTWVINXhpME5mNlVtSDR1MytJZHRueDZKb05rcklBVktVMXFaS1NFR1RTVG9jV0RhT0h4OE5iWGR2Sks3Z2VRZnFFQkJCVVNOQnQzMjRkZGxvWlBaeStGR3p1dDVyQnkwaGUxZld6ZVJPb3oxaFg3L0FLazdSQ3l6a1NGWDhUcVRQUUUwS0MwREsxLyt6UUdpMi9HM2VRWUkzd0F1cDZlaCs2VHJLd2tKay9mUzM5WXJpZUs0Y2dkNlk1L1gxMGVvNlo5ajFCV3VRVUlQQUFBQUFBQkFEUU1BQUFBQUJBZ0dDUUFGQUFvQUFRUURBZ2NHQTNBWEFBQUFBQUFBYVc1MmIybGpaUzAwTWdBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFDSlBvZGhSaWtoWTRMRUJsOTN6R2hqSEUzamtoMmZ4Z0lOWUp5VStwbmlpcm9tOGRYdCswMDZLaVBHblNKTitwb3EwYXVCL0Jyc2NQSEdvd2NLQ2tvRCJ9LCJ0eXBlIjoiZGVwb3NpdCIsInZvdWNoZXIiOnsiY2hhbm5lbElkIjoiSGpnMlBEZ0x4WURpUVdSSHJKZWVZOVY5aU55ZWJNOU1XdXRvQTY3ZWl2c1oiLCJleHBpcmVzQXQiOjAsIm1heENsYWltYWJsZUFtb3VudCI6IjQwMDAiLCJzaWduYXR1cmUiOiIzV1lOamNtaGQ0c1hvbnhRUHJCcXJGYnNWdDlKb2dGU3RvQVNwajRvMUxUbkx4aTlIZTRiNGU4dEhqc3VDdE1DV0JQa3RvUmZ6R1h4SFNmSjl1WWdhWERSIn19LCJ4NDAyVmVyc2lvbiI6Mn0=" + "x402PaymentHeader": "eyJhY2NlcHRlZCI6eyJhbW91bnQiOiIxMDAwIiwiYXNzZXQiOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsImV4dHJhIjp7ImZlZVBheWVyIjoiSjJ4Y2NSdHVHNDNkckVTTFl6bkhoTGhRa0xUZGZlcGNLWWJpUTlCc0pWYWYiLCJtYXhDbGFpbUNoYW5uZWxzIjoxOCwibWF4U2V0dGxlQ2hhbm5lbHMiOjEzLCJtZW1vIjoiaW52b2ljZS00MiIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwidG9rZW5Qcm9ncmFtIjoiVG9rZW5rZWdRZmVaeWlOd0FKYk5iR0tQRlhDV3VCdmY5U3M2MjNWUTVEQSIsInRyYW5zYWN0aW9uVmVyc2lvbnMiOlswLDFdLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwibWF4VGltZW91dFNlY29uZHMiOjMwMCwibmV0d29yayI6InNvbGFuYTpFdFdUUkFCWmFZcTZpTWZlWUtvdVJ1MTY2VlUyeHFhMSIsInBheVRvIjoiQ1hockZaSkxLcWp6bVAzc2pZTGNGNGRUZVhXS0N5OWUyU1hYWjJZbzZNUFkiLCJzY2hlbWUiOiJiYXRjaC1zZXR0bGVtZW50In0sInBheWxvYWQiOnsiY2hhbm5lbENvbmZpZyI6eyJvcGVuU2xvdCI6MzQxMDAwMDAwLCJwYXllciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicGF5ZXJBdXRob3JpemVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJyZWNlaXZlciI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwicmVjZWl2ZXJBdXRob3JpemVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJzYWx0IjoiNDIiLCJ0b2tlbiI6IjR6TU1DOXNydDVSaTVYMTRHQWdYaGFIaWkzR25QQUVFUllQSmdaSkRuY0RVIiwid2l0aGRyYXdEZWxheSI6MzYwMH0sImRlcG9zaXQiOnsiYW1vdW50IjoiNjAwMCIsInRyYW5zYWN0aW9uIjoiZ1FJQUJBOEFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBSUovUmNrT0ZxZ3gxdGsrM2pOWUMraDJaSDk2L2RyRThXTzF3THF5RFhwOWhqcVNteGo0cHhTQ3I3MVVIc1RMc1g1bFVkMnJyNitlNUpDSHVwcEZFYlNMQkxwTml1bkpEM0t2eEtTdlVkbGRBck04SU9PY01ibi9OR2JmMlN4WGlNZWE0VCtWQVdaa0ticUl3amNaWWhWclpXS1pSNFVWeVlqOS9yVGs5dXdFK3o0cVlKYldPOHRYTWQwTWVINXhpME5mNlVtSDR1MytJZHRueDZKb05rcklBVktVMXFaS1NFR1RTVG9jV0RhT0h4OE5iWGR2Sks3Z2VRZnFFQkJCVVNOQnQzMjRkZGxvWlBaeStGR3p1dDVyQnkwaGUxZld6ZVJPb3oxaFg3L0FLazdSQ3l6a1NGWDhUcVRQUUUwS0MwREsxLyt6UUdpMi9HM2VRWUkzd0F1cDZlaCs2VHJLd2tKay9mUzM5WXJpZUs0Y2dkNlk1L1gxMGVvNlo5ajFCV3UzUVVBQUFBQUFBQXNBUUFBQUFBQUJBZ0dDUUFGQUFvQUFRUURBZ2NHQTNBWEFBQUFBQUFBYVc1MmIybGpaUzAwTWdBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFDZDFoQ0V2OVYxRVE5Y0Z1cWVmLzBRSnE1V20wM1hjNlNERWNETmJUZ1o0UWlHL1FWbWJyMEY5Mk1KbGJoaGRkMUZkM3Z1UmpRbUpwM3crMGtBTmNJUCJ9LCJ0eXBlIjoiZGVwb3NpdCIsInZvdWNoZXIiOnsiY2hhbm5lbElkIjoiSGpnMlBEZ0x4WURpUVdSSHJKZWVZOVY5aU55ZWJNOU1XdXRvQTY3ZWl2c1oiLCJleHBpcmVzQXQiOjAsIm1heENsYWltYWJsZUFtb3VudCI6IjQwMDAiLCJzaWduYXR1cmUiOiIzV1lOamNtaGQ0c1hvbnhRUHJCcXJGYnNWdDlKb2dGU3RvQVNwajRvMUxUbkx4aTlIZTRiNGU4dEhqc3VDdE1DV0JQa3RvUmZ6R1h4SFNmSjl1WWdhWERSIn19LCJ4NDAyVmVyc2lvbiI6Mn0=" }, "intent": "x402-batch-settlement", "mode": "verify-transaction", "provenance": "generated", "requirements": [ - "X402TX-0f874a9c63" + "X402TX-703c03cfb5" ], "role": "server", "spec": { @@ -1490,7 +1509,7 @@ }, { "bugType": "auth-bypass", - "description": "Paired accept: priorityFee 1000000 lamports at computeUnitLimit 200000 is exactly the cap.", + "description": "Paired accept: priorityFee 1500 lamports at computeUnitLimit 300 is exactly the per-unit cap, and under the sponsor's 2000 lamport cap on the total fee (RULINGS S6).", "expect": { "outcome": "accept" }, @@ -1501,6 +1520,182 @@ "asset": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", "extra": { "feePayer": "J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf", + "maxClaimChannels": 18, + "maxSettleChannels": 13, + "memo": "invoice-42", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "tokenProgram": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "transactionVersions": [ + 0, + 1 + ], + "withdrawDelay": 3600 + }, + "maxTimeoutSeconds": 300, + "network": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "payTo": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "scheme": "batch-settlement" + }, + "batchServer": { + "cluster": "devnet", + "currency": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "decimals": 6, + "feePayerSecretKey": [ + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 253, + 23, + 36, + 56, + 90, + 160, + 199, + 91, + 100, + 251, + 120, + 205, + 96, + 47, + 161, + 217, + 145, + 253, + 235, + 247, + 107, + 19, + 197, + 142, + 215, + 2, + 234, + 200, + 53, + 233, + 246, + 24 + ], + "maxTimeoutSeconds": 300, + "memo": "invoice-42", + "payTo": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "price": "0.001", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "transactionVersions": [ + 0, + 1 + ], + "withdrawDelay": 3600 + }, + "batchServerChannel": { + "channelId": "Hjg2PDgLxYDiQWRHrJeeY9V9iNyebM9MWutoA67eivsZ", + "chargedCumulativeAmount": "3000", + "deposit": "4000", + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "settled": "0" + }, + "rpcFixtures": { + "accounts": { + "8EiF91LJfbatqHRY3k2jp8dwrFY3yDQeEovpMDZnpJiP": { + "data": "O0Qss5EhV/E6kz0BNCgtAytf/s0Botvxt3kGCN8ALqfqSmxj4pxSCr71UHsTLsX5lUd2rr6+e5JCHuppFEbSLADKmjsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + "BSMX9adNvtMHhBSbiuDeaPZZbF82cmPJkSHyptJSHecz": { + "data": "O0Qss5EhV/E6kz0BNCgtAytf/s0Botvxt3kGCN8ALqc7S0pMPs1+WdY0rmfl3rvsCtBvIE3wE6aVozdqV7mNBQDKmjsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + "Hjg2PDgLxYDiQWRHrJeeY9V9iNyebM9MWutoA67eivsZ": { + "data": "AQH/ACoAAAAAAAAAoA8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAOAABKHxlNESMyCQEQHZINFOcuqsCHfS894FMmEGgZV1RQmepKbGPinFIKvvVQexMuxfmVR3auvr57kkIe6mkURtIs/RckOFqgx1tk+3jNYC+h2ZH96/drE8WO1wLqyDXp9hjqSmxj4pxSCr71UHsTLsX5lUd2rr6+e5JCHuppFEbSLDtELLORIVfxOpM9ATQoLQMrX/7NAaLb8bd5BgjfAC6n/RckOFqgx1tk+3jNYC+h2ZH96/drE8WO1wLqyDXp9hhAP1MUAAAAAA==", + "owner": "CHNLxYvVA28MJP9PrFuDXccuoGXAx7jBacfLEkahyGsX" + }, + "PjeTAeWHZHjrBForCEJvMVmRJpW5dngPaRzCp8w1MM4": { + "data": "O0Qss5EhV/E6kz0BNCgtAytf/s0Botvxt3kGCN8ALqerTiszHktPOhVCuuD5Vd1dMwNJx06hxwqSBewGVQkiMwDKmjsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + "f5xag9qZ5qmEkt2MDrBQZENh9QV1orw3UyrqAg5wTc3": { + "data": "O0Qss5EhV/E6kz0BNCgtAytf/s0Botvxt3kGCN8ALqf9FyQ4WqDHW2T7eM1gL6HZkf3r92sTxY7XAurINen2GADKmjsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + } + }, + "mints": { + "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU": { + "decimals": 6, + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + } + }, + "recentBlockhash": "11111111111111111111111111111111", + "slot": 341000100 + }, + "x402PaymentHeader": "eyJhY2NlcHRlZCI6eyJhbW91bnQiOiIxMDAwIiwiYXNzZXQiOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsImV4dHJhIjp7ImZlZVBheWVyIjoiSjJ4Y2NSdHVHNDNkckVTTFl6bkhoTGhRa0xUZGZlcGNLWWJpUTlCc0pWYWYiLCJtYXhDbGFpbUNoYW5uZWxzIjoxOCwibWF4U2V0dGxlQ2hhbm5lbHMiOjEzLCJtZW1vIjoiaW52b2ljZS00MiIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwidG9rZW5Qcm9ncmFtIjoiVG9rZW5rZWdRZmVaeWlOd0FKYk5iR0tQRlhDV3VCdmY5U3M2MjNWUTVEQSIsInRyYW5zYWN0aW9uVmVyc2lvbnMiOlswLDFdLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwibWF4VGltZW91dFNlY29uZHMiOjMwMCwibmV0d29yayI6InNvbGFuYTpFdFdUUkFCWmFZcTZpTWZlWUtvdVJ1MTY2VlUyeHFhMSIsInBheVRvIjoiQ1hockZaSkxLcWp6bVAzc2pZTGNGNGRUZVhXS0N5OWUyU1hYWjJZbzZNUFkiLCJzY2hlbWUiOiJiYXRjaC1zZXR0bGVtZW50In0sInBheWxvYWQiOnsiY2hhbm5lbENvbmZpZyI6eyJvcGVuU2xvdCI6MzQxMDAwMDAwLCJwYXllciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicGF5ZXJBdXRob3JpemVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJyZWNlaXZlciI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwicmVjZWl2ZXJBdXRob3JpemVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJzYWx0IjoiNDIiLCJ0b2tlbiI6IjR6TU1DOXNydDVSaTVYMTRHQWdYaGFIaWkzR25QQUVFUllQSmdaSkRuY0RVIiwid2l0aGRyYXdEZWxheSI6MzYwMH0sImRlcG9zaXQiOnsiYW1vdW50IjoiNjAwMCIsInRyYW5zYWN0aW9uIjoiZ1FJQUJBOEFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBSUovUmNrT0ZxZ3gxdGsrM2pOWUMraDJaSDk2L2RyRThXTzF3THF5RFhwOWhqcVNteGo0cHhTQ3I3MVVIc1RMc1g1bFVkMnJyNitlNUpDSHVwcEZFYlNMQkxwTml1bkpEM0t2eEtTdlVkbGRBck04SU9PY01ibi9OR2JmMlN4WGlNZWE0VCtWQVdaa0ticUl3amNaWWhWclpXS1pSNFVWeVlqOS9yVGs5dXdFK3o0cVlKYldPOHRYTWQwTWVINXhpME5mNlVtSDR1MytJZHRueDZKb05rcklBVktVMXFaS1NFR1RTVG9jV0RhT0h4OE5iWGR2Sks3Z2VRZnFFQkJCVVNOQnQzMjRkZGxvWlBaeStGR3p1dDVyQnkwaGUxZld6ZVJPb3oxaFg3L0FLazdSQ3l6a1NGWDhUcVRQUUUwS0MwREsxLyt6UUdpMi9HM2VRWUkzd0F1cDZlaCs2VHJLd2tKay9mUzM5WXJpZUs0Y2dkNlk1L1gxMGVvNlo5ajFCV3UzQVVBQUFBQUFBQXNBUUFBQUFBQUJBZ0dDUUFGQUFvQUFRUURBZ2NHQTNBWEFBQUFBQUFBYVc1MmIybGpaUzAwTWdBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBODJvQWZVUDZ0OHRRbFZ5V0FRS2FaYS8rRXhPSjd1V2EyZkR6TFVYVXRMS3JKWGl6NnFOeGx5dElzSDhiT1Q5V0dLdjZyY2I4NlFSZXJ4TENFWEY0RCJ9LCJ0eXBlIjoiZGVwb3NpdCIsInZvdWNoZXIiOnsiY2hhbm5lbElkIjoiSGpnMlBEZ0x4WURpUVdSSHJKZWVZOVY5aU55ZWJNOU1XdXRvQTY3ZWl2c1oiLCJleHBpcmVzQXQiOjAsIm1heENsYWltYWJsZUFtb3VudCI6IjQwMDAiLCJzaWduYXR1cmUiOiIzV1lOamNtaGQ0c1hvbnhRUHJCcXJGYnNWdDlKb2dGU3RvQVNwajRvMUxUbkx4aTlIZTRiNGU4dEhqc3VDdE1DV0JQa3RvUmZ6R1h4SFNmSjl1WWdhWERSIn19LCJ4NDAyVmVyc2lvbiI6Mn0=" + }, + "intent": "x402-batch-settlement", + "mode": "verify-transaction", + "provenance": "generated", + "requirements": [ + "X402TX-703c03cfb5" + ], + "role": "server", + "spec": { + "doc": "x402-txv1/specs/schemes/batch-settlement/scheme_batch_settlement_svm.md", + "quote": "`priorityFee * 1000000 <= 5000000 * computeUnitLimit`", + "section": "Top-level instruction layout" + }, + "tier": "offline" + }, + { + "bugType": "auth-bypass", + "description": "priorityFee 2001 lamports at computeUnitLimit 200000: far under the per-unit cap, but one lamport over the cap the sponsor puts on the total fee it pays (RULINGS S6).", + "expect": { + "alsoConformant": [ + { + "outcome": "accept" + } + ], + "alsoConformantReason": "the upto and batch-settlement schemes cap the compute unit limit at 400,000 and the unit price at 5,000,000 micro-lamports (or a version-1 priorityFee at 5 lamports per unit) and this transaction is within them; the 2,000 lamport cap on the total fee is pay-kit's stricter local policy, which the schemes allow but do not require (upto: “A sponsor MAY apply a stricter local policy for compute-unit limit, compute-unit price, and required-signature count”; batch-settlement: “A sponsor MAY apply stricter local compute-unit, priority-fee, or required-signature caps”), so a sponsor without it accepts (RULINGS S6).", + "outcome": "reject", + "rejectCode": "setup-transaction" + }, + "id": "batch-txv1-top-up-v1-priority-fee-over-sponsor-cap-reject", + "input": { + "batchRequirements": { + "amount": "1000", + "asset": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "extra": { + "feePayer": "J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf", + "maxClaimChannels": 18, + "maxSettleChannels": 13, "memo": "invoice-42", "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", "tokenProgram": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", @@ -1637,13 +1832,13 @@ "recentBlockhash": "11111111111111111111111111111111", "slot": 341000100 }, - "x402PaymentHeader": "eyJhY2NlcHRlZCI6eyJhbW91bnQiOiIxMDAwIiwiYXNzZXQiOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsImV4dHJhIjp7ImZlZVBheWVyIjoiSjJ4Y2NSdHVHNDNkckVTTFl6bkhoTGhRa0xUZGZlcGNLWWJpUTlCc0pWYWYiLCJtZW1vIjoiaW52b2ljZS00MiIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwidG9rZW5Qcm9ncmFtIjoiVG9rZW5rZWdRZmVaeWlOd0FKYk5iR0tQRlhDV3VCdmY5U3M2MjNWUTVEQSIsInRyYW5zYWN0aW9uVmVyc2lvbnMiOlswLDFdLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwibWF4VGltZW91dFNlY29uZHMiOjMwMCwibmV0d29yayI6InNvbGFuYTpFdFdUUkFCWmFZcTZpTWZlWUtvdVJ1MTY2VlUyeHFhMSIsInBheVRvIjoiQ1hockZaSkxLcWp6bVAzc2pZTGNGNGRUZVhXS0N5OWUyU1hYWjJZbzZNUFkiLCJzY2hlbWUiOiJiYXRjaC1zZXR0bGVtZW50In0sInBheWxvYWQiOnsiY2hhbm5lbENvbmZpZyI6eyJvcGVuU2xvdCI6MzQxMDAwMDAwLCJwYXllciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicGF5ZXJBdXRob3JpemVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJyZWNlaXZlciI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwicmVjZWl2ZXJBdXRob3JpemVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJzYWx0IjoiNDIiLCJ0b2tlbiI6IjR6TU1DOXNydDVSaTVYMTRHQWdYaGFIaWkzR25QQUVFUllQSmdaSkRuY0RVIiwid2l0aGRyYXdEZWxheSI6MzYwMH0sImRlcG9zaXQiOnsiYW1vdW50IjoiNjAwMCIsInRyYW5zYWN0aW9uIjoiZ1FJQUJBOEFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBSUovUmNrT0ZxZ3gxdGsrM2pOWUMraDJaSDk2L2RyRThXTzF3THF5RFhwOWhqcVNteGo0cHhTQ3I3MVVIc1RMc1g1bFVkMnJyNitlNUpDSHVwcEZFYlNMQkxwTml1bkpEM0t2eEtTdlVkbGRBck04SU9PY01ibi9OR2JmMlN4WGlNZWE0VCtWQVdaa0ticUl3amNaWWhWclpXS1pSNFVWeVlqOS9yVGs5dXdFK3o0cVlKYldPOHRYTWQwTWVINXhpME5mNlVtSDR1MytJZHRueDZKb05rcklBVktVMXFaS1NFR1RTVG9jV0RhT0h4OE5iWGR2Sks3Z2VRZnFFQkJCVVNOQnQzMjRkZGxvWlBaeStGR3p1dDVyQnkwaGUxZld6ZVJPb3oxaFg3L0FLazdSQ3l6a1NGWDhUcVRQUUUwS0MwREsxLyt6UUdpMi9HM2VRWUkzd0F1cDZlaCs2VHJLd2tKay9mUzM5WXJpZUs0Y2dkNlk1L1gxMGVvNlo5ajFCV3VRRUlQQUFBQUFBQkFEUU1BQUFBQUJBZ0dDUUFGQUFvQUFRUURBZ2NHQTNBWEFBQUFBQUFBYVc1MmIybGpaUzAwTWdBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBMDgvaGo1eXNsWXY5KytNbUc4NWJHLzliYWpDOENRUTVhMFZINHcwU1BKdVdubUVWT1dJbEh0eDBQNW5ITVl3L1pYQmJaSnNCMmhJVmkwcUllM3EwSSJ9LCJ0eXBlIjoiZGVwb3NpdCIsInZvdWNoZXIiOnsiY2hhbm5lbElkIjoiSGpnMlBEZ0x4WURpUVdSSHJKZWVZOVY5aU55ZWJNOU1XdXRvQTY3ZWl2c1oiLCJleHBpcmVzQXQiOjAsIm1heENsYWltYWJsZUFtb3VudCI6IjQwMDAiLCJzaWduYXR1cmUiOiIzV1lOamNtaGQ0c1hvbnhRUHJCcXJGYnNWdDlKb2dGU3RvQVNwajRvMUxUbkx4aTlIZTRiNGU4dEhqc3VDdE1DV0JQa3RvUmZ6R1h4SFNmSjl1WWdhWERSIn19LCJ4NDAyVmVyc2lvbiI6Mn0=" + "x402PaymentHeader": "eyJhY2NlcHRlZCI6eyJhbW91bnQiOiIxMDAwIiwiYXNzZXQiOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsImV4dHJhIjp7ImZlZVBheWVyIjoiSjJ4Y2NSdHVHNDNkckVTTFl6bkhoTGhRa0xUZGZlcGNLWWJpUTlCc0pWYWYiLCJtYXhDbGFpbUNoYW5uZWxzIjoxOCwibWF4U2V0dGxlQ2hhbm5lbHMiOjEzLCJtZW1vIjoiaW52b2ljZS00MiIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwidG9rZW5Qcm9ncmFtIjoiVG9rZW5rZWdRZmVaeWlOd0FKYk5iR0tQRlhDV3VCdmY5U3M2MjNWUTVEQSIsInRyYW5zYWN0aW9uVmVyc2lvbnMiOlswLDFdLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwibWF4VGltZW91dFNlY29uZHMiOjMwMCwibmV0d29yayI6InNvbGFuYTpFdFdUUkFCWmFZcTZpTWZlWUtvdVJ1MTY2VlUyeHFhMSIsInBheVRvIjoiQ1hockZaSkxLcWp6bVAzc2pZTGNGNGRUZVhXS0N5OWUyU1hYWjJZbzZNUFkiLCJzY2hlbWUiOiJiYXRjaC1zZXR0bGVtZW50In0sInBheWxvYWQiOnsiY2hhbm5lbENvbmZpZyI6eyJvcGVuU2xvdCI6MzQxMDAwMDAwLCJwYXllciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicGF5ZXJBdXRob3JpemVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJyZWNlaXZlciI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwicmVjZWl2ZXJBdXRob3JpemVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJzYWx0IjoiNDIiLCJ0b2tlbiI6IjR6TU1DOXNydDVSaTVYMTRHQWdYaGFIaWkzR25QQUVFUllQSmdaSkRuY0RVIiwid2l0aGRyYXdEZWxheSI6MzYwMH0sImRlcG9zaXQiOnsiYW1vdW50IjoiNjAwMCIsInRyYW5zYWN0aW9uIjoiZ1FJQUJBOEFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBSUovUmNrT0ZxZ3gxdGsrM2pOWUMraDJaSDk2L2RyRThXTzF3THF5RFhwOWhqcVNteGo0cHhTQ3I3MVVIc1RMc1g1bFVkMnJyNitlNUpDSHVwcEZFYlNMQkxwTml1bkpEM0t2eEtTdlVkbGRBck04SU9PY01ibi9OR2JmMlN4WGlNZWE0VCtWQVdaa0ticUl3amNaWWhWclpXS1pSNFVWeVlqOS9yVGs5dXdFK3o0cVlKYldPOHRYTWQwTWVINXhpME5mNlVtSDR1MytJZHRueDZKb05rcklBVktVMXFaS1NFR1RTVG9jV0RhT0h4OE5iWGR2Sks3Z2VRZnFFQkJCVVNOQnQzMjRkZGxvWlBaeStGR3p1dDVyQnkwaGUxZld6ZVJPb3oxaFg3L0FLazdSQ3l6a1NGWDhUcVRQUUUwS0MwREsxLyt6UUdpMi9HM2VRWUkzd0F1cDZlaCs2VHJLd2tKay9mUzM5WXJpZUs0Y2dkNlk1L1gxMGVvNlo5ajFCV3UwUWNBQUFBQUFBQkFEUU1BQUFBQUJBZ0dDUUFGQUFvQUFRUURBZ2NHQTNBWEFBQUFBQUFBYVc1MmIybGpaUzAwTWdBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBSnZmQzB2UUs0eGxvQzlsalFtMjRNR0NJVGVXWXRaOENucm5NcWY3bmtnMzlwbXZKb09aUHdKbnRMNThqQUh2WlMxNGVCSDR0RFQwNUkybE1ZWE53RCJ9LCJ0eXBlIjoiZGVwb3NpdCIsInZvdWNoZXIiOnsiY2hhbm5lbElkIjoiSGpnMlBEZ0x4WURpUVdSSHJKZWVZOVY5aU55ZWJNOU1XdXRvQTY3ZWl2c1oiLCJleHBpcmVzQXQiOjAsIm1heENsYWltYWJsZUFtb3VudCI6IjQwMDAiLCJzaWduYXR1cmUiOiIzV1lOamNtaGQ0c1hvbnhRUHJCcXJGYnNWdDlKb2dGU3RvQVNwajRvMUxUbkx4aTlIZTRiNGU4dEhqc3VDdE1DV0JQa3RvUmZ6R1h4SFNmSjl1WWdhWERSIn19LCJ4NDAyVmVyc2lvbiI6Mn0=" }, "intent": "x402-batch-settlement", "mode": "verify-transaction", "provenance": "generated", "requirements": [ - "X402TX-0f874a9c63" + "X402TX-703c03cfb5" ], "role": "server", "spec": { @@ -1667,6 +1862,8 @@ "asset": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", "extra": { "feePayer": "J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf", + "maxClaimChannels": 18, + "maxSettleChannels": 13, "memo": "invoice-42", "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", "tokenProgram": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", @@ -1803,7 +2000,7 @@ "recentBlockhash": "11111111111111111111111111111111", "slot": 341000100 }, - "x402PaymentHeader": "eyJhY2NlcHRlZCI6eyJhbW91bnQiOiIxMDAwIiwiYXNzZXQiOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsImV4dHJhIjp7ImZlZVBheWVyIjoiSjJ4Y2NSdHVHNDNkckVTTFl6bkhoTGhRa0xUZGZlcGNLWWJpUTlCc0pWYWYiLCJtZW1vIjoiaW52b2ljZS00MiIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwidG9rZW5Qcm9ncmFtIjoiVG9rZW5rZWdRZmVaeWlOd0FKYk5iR0tQRlhDV3VCdmY5U3M2MjNWUTVEQSIsInRyYW5zYWN0aW9uVmVyc2lvbnMiOlswLDFdLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwibWF4VGltZW91dFNlY29uZHMiOjMwMCwibmV0d29yayI6InNvbGFuYTpFdFdUUkFCWmFZcTZpTWZlWUtvdVJ1MTY2VlUyeHFhMSIsInBheVRvIjoiQ1hockZaSkxLcWp6bVAzc2pZTGNGNGRUZVhXS0N5OWUyU1hYWjJZbzZNUFkiLCJzY2hlbWUiOiJiYXRjaC1zZXR0bGVtZW50In0sInBheWxvYWQiOnsiY2hhbm5lbENvbmZpZyI6eyJvcGVuU2xvdCI6MzQxMDAwMDAwLCJwYXllciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicGF5ZXJBdXRob3JpemVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJyZWNlaXZlciI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwicmVjZWl2ZXJBdXRob3JpemVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJzYWx0IjoiNDIiLCJ0b2tlbiI6IjR6TU1DOXNydDVSaTVYMTRHQWdYaGFIaWkzR25QQUVFUllQSmdaSkRuY0RVIiwid2l0aGRyYXdEZWxheSI6MzYwMH0sImRlcG9zaXQiOnsiYW1vdW50IjoiNjAwMCIsInRyYW5zYWN0aW9uIjoiQWdBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFCMFYwdHhTM2h4d1VUdWJXbnZFOFdxY29qRzZVRnpOMFJYVlg1ZFo4YytMZ1RtTGRyOXppYjZEM3VRTEhOK0djWFNxMTl3dEw0MTRDWnZpRmtHN0JvQmdBSUFCUXI5RnlRNFdxREhXMlQ3ZU0xZ0w2SFprZjNyOTJzVHhZN1hBdXJJTmVuMkdPcEtiR1BpbkZJS3Z2VlFleE11eGZtVlIzYXV2cjU3a2tJZTZta1VSdElzRXVrMks2Y2tQY3EvRXBLOVIyVjBDc3p3ZzQ1d3h1ZjgwWnQvWkxGZUl4NXJoUDVVQlptUXB1b2pDTnhsaUZXdGxZcGxIaFJYSmlQMyt0T1QyN0FUN1BpcGdsdFk3eTFjeDNReDRmbkdMUTEvcFNZZmk3ZjRoMjJmSG9tZzJTc2dCTit0ZVdML3NkMlNYUXFmdGViUURPWVpXNmk3T3BIOUIrK1lZTVhwZTdnRlNsTmFtU2toQmswazZIRmcyamg4ZkRXMTNieVN1NEhrSDZoQVFRVkVqUWJkOXVIWFphR1QyY3ZoUnM3cmVhd2N0SVh0WDFzM2tUcU05WVYrL3dDcE8wUXNzNUVoVi9FNmt6MEJOQ2d0QXl0Zi9zMEJvdHZ4dDNrR0NOOEFMcWVub2Z1azZ5c0pDWlAzMHQvV0s0bml1SElIZW1PZjE5ZEhxT21mWTlRVnJnQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQlFrR0FRUURBZ2dIQ1FOd0Z3QUFBQUFBQUFZQUNtbHVkbTlwWTJVdE5ESUZBTW9DQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFCUURLQWdFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUVVBeWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lBIn0sInR5cGUiOiJkZXBvc2l0Iiwidm91Y2hlciI6eyJjaGFubmVsSWQiOiJIamcyUERnTHhZRGlRV1JIckplZVk5VjlpTnllYk05TVd1dG9BNjdlaXZzWiIsImV4cGlyZXNBdCI6MCwibWF4Q2xhaW1hYmxlQW1vdW50IjoiNDAwMCIsInNpZ25hdHVyZSI6IjNXWU5qY21oZDRzWG9ueFFQckJxckZic1Z0OUpvZ0ZTdG9BU3BqNG8xTFRuTHhpOUhlNGI0ZTh0SGpzdUN0TUNXQlBrdG9SZnpHWHhIU2ZKOXVZZ2FYRFIifX0sIng0MDJWZXJzaW9uIjoyfQ==" + "x402PaymentHeader": "eyJhY2NlcHRlZCI6eyJhbW91bnQiOiIxMDAwIiwiYXNzZXQiOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsImV4dHJhIjp7ImZlZVBheWVyIjoiSjJ4Y2NSdHVHNDNkckVTTFl6bkhoTGhRa0xUZGZlcGNLWWJpUTlCc0pWYWYiLCJtYXhDbGFpbUNoYW5uZWxzIjoxOCwibWF4U2V0dGxlQ2hhbm5lbHMiOjEzLCJtZW1vIjoiaW52b2ljZS00MiIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwidG9rZW5Qcm9ncmFtIjoiVG9rZW5rZWdRZmVaeWlOd0FKYk5iR0tQRlhDV3VCdmY5U3M2MjNWUTVEQSIsInRyYW5zYWN0aW9uVmVyc2lvbnMiOlswLDFdLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwibWF4VGltZW91dFNlY29uZHMiOjMwMCwibmV0d29yayI6InNvbGFuYTpFdFdUUkFCWmFZcTZpTWZlWUtvdVJ1MTY2VlUyeHFhMSIsInBheVRvIjoiQ1hockZaSkxLcWp6bVAzc2pZTGNGNGRUZVhXS0N5OWUyU1hYWjJZbzZNUFkiLCJzY2hlbWUiOiJiYXRjaC1zZXR0bGVtZW50In0sInBheWxvYWQiOnsiY2hhbm5lbENvbmZpZyI6eyJvcGVuU2xvdCI6MzQxMDAwMDAwLCJwYXllciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicGF5ZXJBdXRob3JpemVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJyZWNlaXZlciI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwicmVjZWl2ZXJBdXRob3JpemVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJzYWx0IjoiNDIiLCJ0b2tlbiI6IjR6TU1DOXNydDVSaTVYMTRHQWdYaGFIaWkzR25QQUVFUllQSmdaSkRuY0RVIiwid2l0aGRyYXdEZWxheSI6MzYwMH0sImRlcG9zaXQiOnsiYW1vdW50IjoiNjAwMCIsInRyYW5zYWN0aW9uIjoiQWdBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFCMFYwdHhTM2h4d1VUdWJXbnZFOFdxY29qRzZVRnpOMFJYVlg1ZFo4YytMZ1RtTGRyOXppYjZEM3VRTEhOK0djWFNxMTl3dEw0MTRDWnZpRmtHN0JvQmdBSUFCUXI5RnlRNFdxREhXMlQ3ZU0xZ0w2SFprZjNyOTJzVHhZN1hBdXJJTmVuMkdPcEtiR1BpbkZJS3Z2VlFleE11eGZtVlIzYXV2cjU3a2tJZTZta1VSdElzRXVrMks2Y2tQY3EvRXBLOVIyVjBDc3p3ZzQ1d3h1ZjgwWnQvWkxGZUl4NXJoUDVVQlptUXB1b2pDTnhsaUZXdGxZcGxIaFJYSmlQMyt0T1QyN0FUN1BpcGdsdFk3eTFjeDNReDRmbkdMUTEvcFNZZmk3ZjRoMjJmSG9tZzJTc2dCTit0ZVdML3NkMlNYUXFmdGViUURPWVpXNmk3T3BIOUIrK1lZTVhwZTdnRlNsTmFtU2toQmswazZIRmcyamg4ZkRXMTNieVN1NEhrSDZoQVFRVkVqUWJkOXVIWFphR1QyY3ZoUnM3cmVhd2N0SVh0WDFzM2tUcU05WVYrL3dDcE8wUXNzNUVoVi9FNmt6MEJOQ2d0QXl0Zi9zMEJvdHZ4dDNrR0NOOEFMcWVub2Z1azZ5c0pDWlAzMHQvV0s0bml1SElIZW1PZjE5ZEhxT21mWTlRVnJnQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQlFrR0FRUURBZ2dIQ1FOd0Z3QUFBQUFBQUFZQUNtbHVkbTlwWTJVdE5ESUZBTW9DQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFCUURLQWdFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUVVBeWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lBIn0sInR5cGUiOiJkZXBvc2l0Iiwidm91Y2hlciI6eyJjaGFubmVsSWQiOiJIamcyUERnTHhZRGlRV1JIckplZVk5VjlpTnllYk05TVd1dG9BNjdlaXZzWiIsImV4cGlyZXNBdCI6MCwibWF4Q2xhaW1hYmxlQW1vdW50IjoiNDAwMCIsInNpZ25hdHVyZSI6IjNXWU5qY21oZDRzWG9ueFFQckJxckZic1Z0OUpvZ0ZTdG9BU3BqNG8xTFRuTHhpOUhlNGI0ZTh0SGpzdUN0TUNXQlBrdG9SZnpHWHhIU2ZKOXVZZ2FYRFIifX0sIng0MDJWZXJzaW9uIjoyfQ==" }, "intent": "x402-batch-settlement", "mode": "verify-transaction", @@ -1832,6 +2029,8 @@ "asset": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", "extra": { "feePayer": "J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf", + "maxClaimChannels": 18, + "maxSettleChannels": 13, "memo": "invoice-42", "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", "tokenProgram": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", @@ -1968,7 +2167,7 @@ "recentBlockhash": "11111111111111111111111111111111", "slot": 341000100 }, - "x402PaymentHeader": "eyJhY2NlcHRlZCI6eyJhbW91bnQiOiIxMDAwIiwiYXNzZXQiOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsImV4dHJhIjp7ImZlZVBheWVyIjoiSjJ4Y2NSdHVHNDNkckVTTFl6bkhoTGhRa0xUZGZlcGNLWWJpUTlCc0pWYWYiLCJtZW1vIjoiaW52b2ljZS00MiIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwidG9rZW5Qcm9ncmFtIjoiVG9rZW5rZWdRZmVaeWlOd0FKYk5iR0tQRlhDV3VCdmY5U3M2MjNWUTVEQSIsInRyYW5zYWN0aW9uVmVyc2lvbnMiOlswLDFdLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwibWF4VGltZW91dFNlY29uZHMiOjMwMCwibmV0d29yayI6InNvbGFuYTpFdFdUUkFCWmFZcTZpTWZlWUtvdVJ1MTY2VlUyeHFhMSIsInBheVRvIjoiQ1hockZaSkxLcWp6bVAzc2pZTGNGNGRUZVhXS0N5OWUyU1hYWjJZbzZNUFkiLCJzY2hlbWUiOiJiYXRjaC1zZXR0bGVtZW50In0sInBheWxvYWQiOnsiY2hhbm5lbENvbmZpZyI6eyJvcGVuU2xvdCI6MzQxMDAwMDAwLCJwYXllciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicGF5ZXJBdXRob3JpemVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJyZWNlaXZlciI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwicmVjZWl2ZXJBdXRob3JpemVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJzYWx0IjoiNDIiLCJ0b2tlbiI6IjR6TU1DOXNydDVSaTVYMTRHQWdYaGFIaWkzR25QQUVFUllQSmdaSkRuY0RVIiwid2l0aGRyYXdEZWxheSI6MzYwMH0sImRlcG9zaXQiOnsiYW1vdW50IjoiNjAwMCIsInRyYW5zYWN0aW9uIjoiZ1FJQUJROEFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBVUsvUmNrT0ZxZ3gxdGsrM2pOWUMraDJaSDk2L2RyRThXTzF3THF5RFhwOWhqcVNteGo0cHhTQ3I3MVVIc1RMc1g1bFVkMnJyNitlNUpDSHVwcEZFYlNMQkxwTml1bkpEM0t2eEtTdlVkbGRBck04SU9PY01ibi9OR2JmMlN4WGlNZWE0VCtWQVdaa0ticUl3amNaWWhWclpXS1pSNFVWeVlqOS9yVGs5dXdFK3o0cVlKYldPOHRYTWQwTWVINXhpME5mNlVtSDR1MytJZHRueDZKb05rcklBVGZyWGxpLzdIZGtsMEtuN1htMEF6bUdWdW91enFSL1Fmdm1HREY2WHU0QlVwVFdwa3BJUVpOSk9oeFlObzRmSHcxdGQyOGtydUI1QitvUUVFRlJJMEczZmJoMTJXaGs5bkw0VWJPNjNtc0hMU0Y3VjliTjVFNmpQV0ZmdjhBcVR0RUxMT1JJVmZ4T3BNOUFUUW9MUU1yWC83TkFhTGI4YmQ1QmdqZkFDNm5wNkg3cE9zckNRbVQ5OUxmMWl1SjRyaHlCM3BqbjlmWFI2anBuMlBVRmE3SUFBQUFBQUFBQUVBTkF3QUFBQUFFQ1FZSkFBWUFDZ0FGQUVvQkJRQktBUVVBU2dFQkJBTUNDQWNEY0JjQUFBQUFBQUJwYm5admFXTmxMVFF5QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUkvL0orL1AzS05IWG1lNE9iNkxBOXpSbmpsbmI5SlJLVTNmMGJlN3ZuU2xyRG45TE5zRlZmMEpwR3c5dHFiNWt2U1ZmNkQ0bFNoQVN0emtIV3VMeHdVPSJ9LCJ0eXBlIjoiZGVwb3NpdCIsInZvdWNoZXIiOnsiY2hhbm5lbElkIjoiSGpnMlBEZ0x4WURpUVdSSHJKZWVZOVY5aU55ZWJNOU1XdXRvQTY3ZWl2c1oiLCJleHBpcmVzQXQiOjAsIm1heENsYWltYWJsZUFtb3VudCI6IjQwMDAiLCJzaWduYXR1cmUiOiIzV1lOamNtaGQ0c1hvbnhRUHJCcXJGYnNWdDlKb2dGU3RvQVNwajRvMUxUbkx4aTlIZTRiNGU4dEhqc3VDdE1DV0JQa3RvUmZ6R1h4SFNmSjl1WWdhWERSIn19LCJ4NDAyVmVyc2lvbiI6Mn0=" + "x402PaymentHeader": "eyJhY2NlcHRlZCI6eyJhbW91bnQiOiIxMDAwIiwiYXNzZXQiOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsImV4dHJhIjp7ImZlZVBheWVyIjoiSjJ4Y2NSdHVHNDNkckVTTFl6bkhoTGhRa0xUZGZlcGNLWWJpUTlCc0pWYWYiLCJtYXhDbGFpbUNoYW5uZWxzIjoxOCwibWF4U2V0dGxlQ2hhbm5lbHMiOjEzLCJtZW1vIjoiaW52b2ljZS00MiIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwidG9rZW5Qcm9ncmFtIjoiVG9rZW5rZWdRZmVaeWlOd0FKYk5iR0tQRlhDV3VCdmY5U3M2MjNWUTVEQSIsInRyYW5zYWN0aW9uVmVyc2lvbnMiOlswLDFdLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwibWF4VGltZW91dFNlY29uZHMiOjMwMCwibmV0d29yayI6InNvbGFuYTpFdFdUUkFCWmFZcTZpTWZlWUtvdVJ1MTY2VlUyeHFhMSIsInBheVRvIjoiQ1hockZaSkxLcWp6bVAzc2pZTGNGNGRUZVhXS0N5OWUyU1hYWjJZbzZNUFkiLCJzY2hlbWUiOiJiYXRjaC1zZXR0bGVtZW50In0sInBheWxvYWQiOnsiY2hhbm5lbENvbmZpZyI6eyJvcGVuU2xvdCI6MzQxMDAwMDAwLCJwYXllciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicGF5ZXJBdXRob3JpemVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJyZWNlaXZlciI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwicmVjZWl2ZXJBdXRob3JpemVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJzYWx0IjoiNDIiLCJ0b2tlbiI6IjR6TU1DOXNydDVSaTVYMTRHQWdYaGFIaWkzR25QQUVFUllQSmdaSkRuY0RVIiwid2l0aGRyYXdEZWxheSI6MzYwMH0sImRlcG9zaXQiOnsiYW1vdW50IjoiNjAwMCIsInRyYW5zYWN0aW9uIjoiZ1FJQUJROEFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBVUsvUmNrT0ZxZ3gxdGsrM2pOWUMraDJaSDk2L2RyRThXTzF3THF5RFhwOWhqcVNteGo0cHhTQ3I3MVVIc1RMc1g1bFVkMnJyNitlNUpDSHVwcEZFYlNMQkxwTml1bkpEM0t2eEtTdlVkbGRBck04SU9PY01ibi9OR2JmMlN4WGlNZWE0VCtWQVdaa0ticUl3amNaWWhWclpXS1pSNFVWeVlqOS9yVGs5dXdFK3o0cVlKYldPOHRYTWQwTWVINXhpME5mNlVtSDR1MytJZHRueDZKb05rcklBVGZyWGxpLzdIZGtsMEtuN1htMEF6bUdWdW91enFSL1Fmdm1HREY2WHU0QlVwVFdwa3BJUVpOSk9oeFlObzRmSHcxdGQyOGtydUI1QitvUUVFRlJJMEczZmJoMTJXaGs5bkw0VWJPNjNtc0hMU0Y3VjliTjVFNmpQV0ZmdjhBcVR0RUxMT1JJVmZ4T3BNOUFUUW9MUU1yWC83TkFhTGI4YmQ1QmdqZkFDNm5wNkg3cE9zckNRbVQ5OUxmMWl1SjRyaHlCM3BqbjlmWFI2anBuMlBVRmE3SUFBQUFBQUFBQUVBTkF3QUFBQUFFQ1FZSkFBWUFDZ0FGQUVvQkJRQktBUVVBU2dFQkJBTUNDQWNEY0JjQUFBQUFBQUJwYm5admFXTmxMVFF5QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFRRUJBUUVCQVFFQkFnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUkvL0orL1AzS05IWG1lNE9iNkxBOXpSbmpsbmI5SlJLVTNmMGJlN3ZuU2xyRG45TE5zRlZmMEpwR3c5dHFiNWt2U1ZmNkQ0bFNoQVN0emtIV3VMeHdVPSJ9LCJ0eXBlIjoiZGVwb3NpdCIsInZvdWNoZXIiOnsiY2hhbm5lbElkIjoiSGpnMlBEZ0x4WURpUVdSSHJKZWVZOVY5aU55ZWJNOU1XdXRvQTY3ZWl2c1oiLCJleHBpcmVzQXQiOjAsIm1heENsYWltYWJsZUFtb3VudCI6IjQwMDAiLCJzaWduYXR1cmUiOiIzV1lOamNtaGQ0c1hvbnhRUHJCcXJGYnNWdDlKb2dGU3RvQVNwajRvMUxUbkx4aTlIZTRiNGU4dEhqc3VDdE1DV0JQa3RvUmZ6R1h4SFNmSjl1WWdhWERSIn19LCJ4NDAyVmVyc2lvbiI6Mn0=" }, "intent": "x402-batch-settlement", "mode": "verify-transaction", @@ -1998,6 +2197,8 @@ "asset": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", "extra": { "feePayer": "J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf", + "maxClaimChannels": 18, + "maxSettleChannels": 13, "memo": "invoice-42", "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", "tokenProgram": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", @@ -2134,7 +2335,7 @@ "recentBlockhash": "11111111111111111111111111111111", "slot": 341000100 }, - "x402PaymentHeader": "eyJhY2NlcHRlZCI6eyJhbW91bnQiOiIxMDAwIiwiYXNzZXQiOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsImV4dHJhIjp7ImZlZVBheWVyIjoiSjJ4Y2NSdHVHNDNkckVTTFl6bkhoTGhRa0xUZGZlcGNLWWJpUTlCc0pWYWYiLCJtZW1vIjoiaW52b2ljZS00MiIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwidG9rZW5Qcm9ncmFtIjoiVG9rZW5rZWdRZmVaeWlOd0FKYk5iR0tQRlhDV3VCdmY5U3M2MjNWUTVEQSIsInRyYW5zYWN0aW9uVmVyc2lvbnMiOlswLDFdLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwibWF4VGltZW91dFNlY29uZHMiOjMwMCwibmV0d29yayI6InNvbGFuYTpFdFdUUkFCWmFZcTZpTWZlWUtvdVJ1MTY2VlUyeHFhMSIsInBheVRvIjoiQ1hockZaSkxLcWp6bVAzc2pZTGNGNGRUZVhXS0N5OWUyU1hYWjJZbzZNUFkiLCJzY2hlbWUiOiJiYXRjaC1zZXR0bGVtZW50In0sInBheWxvYWQiOnsiY2hhbm5lbENvbmZpZyI6eyJvcGVuU2xvdCI6MzQxMDAwMDAwLCJwYXllciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicGF5ZXJBdXRob3JpemVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJyZWNlaXZlciI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwicmVjZWl2ZXJBdXRob3JpemVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJzYWx0IjoiNDIiLCJ0b2tlbiI6IjR6TU1DOXNydDVSaTVYMTRHQWdYaGFIaWkzR25QQUVFUllQSmdaSkRuY0RVIiwid2l0aGRyYXdEZWxheSI6MzYwMH0sImRlcG9zaXQiOnsiYW1vdW50IjoiNjAwMCIsInRyYW5zYWN0aW9uIjoiQWdBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFEZWgyZVN0VjdmakZUdmRpR2JoYlI4QklJNVIzWHJBNXBQT1JzbDY1ZXB5RjkvUXBEVHNLTjgzbTE0Ynl2cmNxZTI5bUdJMStYTXVBTjFySmdtUmEwT0FnQUZDdjBYSkRoYW9NZGJaUHQ0eldBdm9kbVIvZXYzYXhQRmp0Y0M2c2cxNmZZWTZrcHNZK0tjVWdxKzlWQjdFeTdGK1pWSGRxNit2bnVTUWg3cWFSUkcwaXdTNlRZcnB5UTl5cjhTa3IxSFpYUUt6UENEam5ERzUvelJtMzlrc1Y0akhtdUUvbFFGbVpDbTZpTUkzR1dJVmEyVmltVWVGRmNtSS9mNjA1UGJzQlBzK0ttQ1cxanZMVnpIZERIaCtjWXREWCtsSmgrTHQvaUhiWjhlaWFEWkt5QURCa1p2NVNFWE12L3NyYnB5dzV2bnZJemx1OFgzRW1zc1E1czZRQUFBQUFWS1UxcVpLU0VHVFNUb2NXRGFPSHg4TmJYZHZKSzdnZVFmcUVCQkJVU05CdDMyNGRkbG9aUFp5K0ZHenV0NXJCeTBoZTFmV3plUk9vejFoWDcvQUtrN1JDeXprU0ZYOFRxVFBRRTBLQzBESzEvK3pRR2kyL0czZVFZSTN3QXVwNmVoKzZUckt3a0prL2ZTMzlZcmllSzRjZ2Q2WTUvWDEwZW82WjlqMUJXdUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFEQlFBSkEwRkxUQUFBQUFBQUNRWUJCQU1DQ0FjSkEzQVhBQUFBQUFBQUJnQUthVzUyYjJsalpTMDBNZz09In0sInR5cGUiOiJkZXBvc2l0Iiwidm91Y2hlciI6eyJjaGFubmVsSWQiOiJIamcyUERnTHhZRGlRV1JIckplZVk5VjlpTnllYk05TVd1dG9BNjdlaXZzWiIsImV4cGlyZXNBdCI6MCwibWF4Q2xhaW1hYmxlQW1vdW50IjoiNDAwMCIsInNpZ25hdHVyZSI6IjNXWU5qY21oZDRzWG9ueFFQckJxckZic1Z0OUpvZ0ZTdG9BU3BqNG8xTFRuTHhpOUhlNGI0ZTh0SGpzdUN0TUNXQlBrdG9SZnpHWHhIU2ZKOXVZZ2FYRFIifX0sIng0MDJWZXJzaW9uIjoyfQ==" + "x402PaymentHeader": "eyJhY2NlcHRlZCI6eyJhbW91bnQiOiIxMDAwIiwiYXNzZXQiOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsImV4dHJhIjp7ImZlZVBheWVyIjoiSjJ4Y2NSdHVHNDNkckVTTFl6bkhoTGhRa0xUZGZlcGNLWWJpUTlCc0pWYWYiLCJtYXhDbGFpbUNoYW5uZWxzIjoxOCwibWF4U2V0dGxlQ2hhbm5lbHMiOjEzLCJtZW1vIjoiaW52b2ljZS00MiIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwidG9rZW5Qcm9ncmFtIjoiVG9rZW5rZWdRZmVaeWlOd0FKYk5iR0tQRlhDV3VCdmY5U3M2MjNWUTVEQSIsInRyYW5zYWN0aW9uVmVyc2lvbnMiOlswLDFdLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwibWF4VGltZW91dFNlY29uZHMiOjMwMCwibmV0d29yayI6InNvbGFuYTpFdFdUUkFCWmFZcTZpTWZlWUtvdVJ1MTY2VlUyeHFhMSIsInBheVRvIjoiQ1hockZaSkxLcWp6bVAzc2pZTGNGNGRUZVhXS0N5OWUyU1hYWjJZbzZNUFkiLCJzY2hlbWUiOiJiYXRjaC1zZXR0bGVtZW50In0sInBheWxvYWQiOnsiY2hhbm5lbENvbmZpZyI6eyJvcGVuU2xvdCI6MzQxMDAwMDAwLCJwYXllciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicGF5ZXJBdXRob3JpemVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJyZWNlaXZlciI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwicmVjZWl2ZXJBdXRob3JpemVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJzYWx0IjoiNDIiLCJ0b2tlbiI6IjR6TU1DOXNydDVSaTVYMTRHQWdYaGFIaWkzR25QQUVFUllQSmdaSkRuY0RVIiwid2l0aGRyYXdEZWxheSI6MzYwMH0sImRlcG9zaXQiOnsiYW1vdW50IjoiNjAwMCIsInRyYW5zYWN0aW9uIjoiQWdBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFEZWgyZVN0VjdmakZUdmRpR2JoYlI4QklJNVIzWHJBNXBQT1JzbDY1ZXB5RjkvUXBEVHNLTjgzbTE0Ynl2cmNxZTI5bUdJMStYTXVBTjFySmdtUmEwT0FnQUZDdjBYSkRoYW9NZGJaUHQ0eldBdm9kbVIvZXYzYXhQRmp0Y0M2c2cxNmZZWTZrcHNZK0tjVWdxKzlWQjdFeTdGK1pWSGRxNit2bnVTUWg3cWFSUkcwaXdTNlRZcnB5UTl5cjhTa3IxSFpYUUt6UENEam5ERzUvelJtMzlrc1Y0akhtdUUvbFFGbVpDbTZpTUkzR1dJVmEyVmltVWVGRmNtSS9mNjA1UGJzQlBzK0ttQ1cxanZMVnpIZERIaCtjWXREWCtsSmgrTHQvaUhiWjhlaWFEWkt5QURCa1p2NVNFWE12L3NyYnB5dzV2bnZJemx1OFgzRW1zc1E1czZRQUFBQUFWS1UxcVpLU0VHVFNUb2NXRGFPSHg4TmJYZHZKSzdnZVFmcUVCQkJVU05CdDMyNGRkbG9aUFp5K0ZHenV0NXJCeTBoZTFmV3plUk9vejFoWDcvQUtrN1JDeXprU0ZYOFRxVFBRRTBLQzBESzEvK3pRR2kyL0czZVFZSTN3QXVwNmVoKzZUckt3a0prL2ZTMzlZcmllSzRjZ2Q2WTUvWDEwZW82WjlqMUJXdUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFEQlFBSkEwRkxUQUFBQUFBQUNRWUJCQU1DQ0FjSkEzQVhBQUFBQUFBQUJnQUthVzUyYjJsalpTMDBNZz09In0sInR5cGUiOiJkZXBvc2l0Iiwidm91Y2hlciI6eyJjaGFubmVsSWQiOiJIamcyUERnTHhZRGlRV1JIckplZVk5VjlpTnllYk05TVd1dG9BNjdlaXZzWiIsImV4cGlyZXNBdCI6MCwibWF4Q2xhaW1hYmxlQW1vdW50IjoiNDAwMCIsInNpZ25hdHVyZSI6IjNXWU5qY21oZDRzWG9ueFFQckJxckZic1Z0OUpvZ0ZTdG9BU3BqNG8xTFRuTHhpOUhlNGI0ZTh0SGpzdUN0TUNXQlBrdG9SZnpHWHhIU2ZKOXVZZ2FYRFIifX0sIng0MDJWZXJzaW9uIjoyfQ==" }, "intent": "x402-batch-settlement", "mode": "verify-transaction", @@ -2152,7 +2353,7 @@ }, { "bugType": "auth-bypass", - "description": "A client-mode refund whose request_close is version 1 on a route that accepts only version 0.", + "description": "A client-mode refund whose request_close is version 1, to a facilitator configured to accept only version 0 (batchServer.transactionVersions [0]).", "expect": { "outcome": "reject", "rejectCode": "unsupported-version" @@ -2249,6 +2450,9 @@ "payTo": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", "price": "0.001", "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "transactionVersions": [ + 0 + ], "withdrawDelay": 3600 }, "batchServerChannel": { diff --git a/harness/vectors/batch-verify-open.json b/harness/vectors/batch-verify-open.json index 9c434efad..90ea3bfe0 100644 --- a/harness/vectors/batch-verify-open.json +++ b/harness/vectors/batch-verify-open.json @@ -145,6 +145,151 @@ }, "tier": "offline" }, + { + "bugType": "settlement", + "description": "The accept open, but the payer's token account holds 1 base unit against the 10000 deposit. The deposit is broadcast only after the handler runs, so a verifier that skips the balance serves the request and only then finds the open cannot land. Pair: batch-verify-open-accept.", + "expect": { + "outcome": "reject", + "rejectCode": "settlement-simulation" + }, + "id": "batch-verify-open-unfunded-payer-reject", + "input": { + "batchRequirements": { + "amount": "1000", + "asset": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "extra": { + "feePayer": "J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf", + "memo": "invoice-42", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "tokenProgram": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "withdrawDelay": 3600 + }, + "maxTimeoutSeconds": 300, + "network": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "payTo": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "scheme": "batch-settlement" + }, + "batchServer": { + "cluster": "devnet", + "currency": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "decimals": 6, + "feePayerSecretKey": [ + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 253, + 23, + 36, + 56, + 90, + 160, + 199, + 91, + 100, + 251, + 120, + 205, + 96, + 47, + 161, + 217, + 145, + 253, + 235, + 247, + 107, + 19, + 197, + 142, + 215, + 2, + 234, + 200, + 53, + 233, + 246, + 24 + ], + "maxTimeoutSeconds": 300, + "memo": "invoice-42", + "payTo": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "price": "0.001", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "withdrawDelay": 3600 + }, + "rpcFixtures": { + "accounts": { + "8EiF91LJfbatqHRY3k2jp8dwrFY3yDQeEovpMDZnpJiP": { + "data": "O0Qss5EhV/E6kz0BNCgtAytf/s0Botvxt3kGCN8ALqfqSmxj4pxSCr71UHsTLsX5lUd2rr6+e5JCHuppFEbSLAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + "BSMX9adNvtMHhBSbiuDeaPZZbF82cmPJkSHyptJSHecz": { + "data": "O0Qss5EhV/E6kz0BNCgtAytf/s0Botvxt3kGCN8ALqc7S0pMPs1+WdY0rmfl3rvsCtBvIE3wE6aVozdqV7mNBQDKmjsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + "PjeTAeWHZHjrBForCEJvMVmRJpW5dngPaRzCp8w1MM4": { + "data": "O0Qss5EhV/E6kz0BNCgtAytf/s0Botvxt3kGCN8ALqerTiszHktPOhVCuuD5Vd1dMwNJx06hxwqSBewGVQkiMwDKmjsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + "f5xag9qZ5qmEkt2MDrBQZENh9QV1orw3UyrqAg5wTc3": { + "data": "O0Qss5EhV/E6kz0BNCgtAytf/s0Botvxt3kGCN8ALqf9FyQ4WqDHW2T7eM1gL6HZkf3r92sTxY7XAurINen2GADKmjsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + } + }, + "mints": { + "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU": { + "decimals": 6, + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + } + }, + "recentBlockhash": "11111111111111111111111111111111", + "slot": 341000100 + }, + "x402PaymentHeader": "eyJhY2NlcHRlZCI6eyJhbW91bnQiOiIxMDAwIiwiYXNzZXQiOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsImV4dHJhIjp7ImZlZVBheWVyIjoiSjJ4Y2NSdHVHNDNkckVTTFl6bkhoTGhRa0xUZGZlcGNLWWJpUTlCc0pWYWYiLCJtZW1vIjoiaW52b2ljZS00MiIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwidG9rZW5Qcm9ncmFtIjoiVG9rZW5rZWdRZmVaeWlOd0FKYk5iR0tQRlhDV3VCdmY5U3M2MjNWUTVEQSIsIndpdGhkcmF3RGVsYXkiOjM2MDB9LCJtYXhUaW1lb3V0U2Vjb25kcyI6MzAwLCJuZXR3b3JrIjoic29sYW5hOkV0V1RSQUJaYVlxNmlNZmVZS291UnUxNjZWVTJ4cWExIiwicGF5VG8iOiJDWGhyRlpKTEtxanptUDNzallMY0Y0ZFRlWFdLQ3k5ZTJTWFhaMllvNk1QWSIsInNjaGVtZSI6ImJhdGNoLXNldHRsZW1lbnQifSwicGF5bG9hZCI6eyJjaGFubmVsQ29uZmlnIjp7Im9wZW5TbG90IjozNDEwMDAwMDAsInBheWVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJwYXllckF1dGhvcml6ZXIiOiJHbWFEcnBwQkM3UDVBUktWOGczZGppd1A4OXZ6MWpMSzIzVjJHQmp1QUVHQiIsInJlY2VpdmVyIjoiQ1hockZaSkxLcWp6bVAzc2pZTGNGNGRUZVhXS0N5OWUyU1hYWjJZbzZNUFkiLCJyZWNlaXZlckF1dGhvcml6ZXIiOiJBb1ZzR2FqOE1TSjZ4d0t4ZkZ4bzlpWldIM2VuQzhSUlRYS0gyZngyRjhvcyIsInNhbHQiOiI0MiIsInRva2VuIjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwiZGVwb3NpdCI6eyJhbW91bnQiOiIxMDAwMCIsInRyYW5zYWN0aW9uIjoiQWdBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFCWDd1ajh4endpcVZzZXRhU3pMN3FCOVM0REdzd0EwWFFEemcwMDJyMDZiRmxMUzlpU0lwZkoweFhLNmdES1BtL3FNaXIyZTJpaUhJZDBabmVyTWx3R2dBSUFDQTM5RnlRNFdxREhXMlQ3ZU0xZ0w2SFprZjNyOTJzVHhZN1hBdXJJTmVuMkdPcEtiR1BpbkZJS3Z2VlFleE11eGZtVlIzYXV2cjU3a2tJZTZta1VSdElzRXVrMks2Y2tQY3EvRXBLOVIyVjBDc3p3ZzQ1d3h1ZjgwWnQvWkxGZUl4NXJoUDVVQlptUXB1b2pDTnhsaUZXdGxZcGxIaFJYSmlQMyt0T1QyN0FUN1BpcGdsdFk3eTFjeDNReDRmbkdMUTEvcFNZZmk3ZjRoMjJmSG9tZzJTc2dBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBRlNsTmFtU2toQmswazZIRmcyamg4ZkRXMTNieVN1NEhrSDZoQVFRVkVqUWFuMVJjWkxGeFJJWXpKVEQxSzhYOVkydTRJbTZIOVJPUGIyWW9BQUFBQUJ0MzI0ZGRsb1pQWnkrRkd6dXQ1ckJ5MGhlMWZXemVST296MWhYNy9BS2s3UkN5emtTRlg4VHFUUFFFMEtDMERLMS8relFHaTIvRzNlUVlJM3dBdXAxcFVEWHRySGlzcnRSZFNHY21qOEdBUWtrSEtqRThYRE1IS0xVanU2dm5RakpjbGowNGtpZkc3UFJBcEZJNE5nd3RhRTVuYS94Q0VCSTU3Mk52cCtGbW5vZnVrNnlzSkNaUDMwdC9XSzRuaXVISUhlbU9mMTlkSHFPbWZZOVFWcmdBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBd3dPQVFBQUNRRUVBd0lJQlFjTENneERBU29BQUFBQUFBQUFFQ2NBQUFBQUFBQVFEZ0FBUUQ5VEZBQUFBQUFCQUFBQXEwNHJNeDVMVHpvVlFycmcrVlhkWFRNRFNjZE9vY2NLa2dYc0JsVUpJak1RSndZQUNtbHVkbTlwWTJVdE5ESUdBRkY0TkRBeU9tSmhkR05vTFhObGRIUnNaVzFsYm5RNmMzWnRPbkpqZG1GMWRHZzZkakU2UVc5V2MwZGhhamhOVTBvMmVIZExlR1pHZUc4NWFWcFhTRE5sYmtNNFVsSlVXRXRJTW1aNE1rWTRiM01BIn0sInR5cGUiOiJkZXBvc2l0Iiwidm91Y2hlciI6eyJjaGFubmVsSWQiOiJIamcyUERnTHhZRGlRV1JIckplZVk5VjlpTnllYk05TVd1dG9BNjdlaXZzWiIsImV4cGlyZXNBdCI6MCwibWF4Q2xhaW1hYmxlQW1vdW50IjoiMTAwMCIsInNpZ25hdHVyZSI6IjVrU3ZpRlE4aGptUXBLOHNSbWdIRDZGeGJFTEFEeld6ZjZNcUNHOHViV0hhdEc0U1hZVjFicms5YlFKUXRYZThxQnRmWmJQWnptQ0hia3Q3ZUptRWRkQkIifX0sIng0MDJWZXJzaW9uIjoyfQ==" + }, + "intent": "x402-batch-settlement", + "mode": "verify-transaction", + "provenance": "generated", + "requirements": [ + "X402-0ff4cabcb4" + ], + "role": "server", + "spec": { + "doc": "x402/specs/schemes/batch-settlement/scheme_batch_settlement_svm.md", + "quote": "It MUST confirm the payer has sufficient tokens for the deposit and the sponsor has sufficient SOL for the transaction fee plus the channel PDA and escrow ATA rent.", + "section": "Canonical open" + }, + "tier": "offline" + }, { "bugType": "auth-bypass", "description": "The open carries only the seller memo: without the binding memo the channel is bound to no receiver authorizer.", diff --git a/harness/vectors/batch-verify-refund.json b/harness/vectors/batch-verify-refund.json index 5c4e95c84..f24db5ba4 100644 --- a/harness/vectors/batch-verify-refund.json +++ b/harness/vectors/batch-verify-refund.json @@ -426,6 +426,7 @@ "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", "settled": "0" }, + "batchVerdictFromStore": true, "rpcFixtures": { "accounts": { "8EiF91LJfbatqHRY3k2jp8dwrFY3yDQeEovpMDZnpJiP": { diff --git a/harness/vectors/batch-verify-setup-policy.json b/harness/vectors/batch-verify-setup-policy.json index 6912d5837..36e0a95cd 100644 --- a/harness/vectors/batch-verify-setup-policy.json +++ b/harness/vectors/batch-verify-setup-policy.json @@ -160,7 +160,7 @@ }, { "bugType": "auth-bypass", - "description": "Paired accept: SetComputeUnitLimit 400000 then SetComputeUnitPrice 5000000 (both at the cap) before the top_up.", + "description": "Paired accept: SetComputeUnitLimit 400000 (at the cap) then SetComputeUnitPrice 5000 before the top_up, a 2000 lamport priority fee: exactly the sponsor's cap on the fee it pays (RULINGS S6).", "expect": { "outcome": "accept" }, @@ -299,7 +299,7 @@ "recentBlockhash": "11111111111111111111111111111111", "slot": 341000100 }, - "x402PaymentHeader": "eyJhY2NlcHRlZCI6eyJhbW91bnQiOiIxMDAwIiwiYXNzZXQiOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsImV4dHJhIjp7ImZlZVBheWVyIjoiSjJ4Y2NSdHVHNDNkckVTTFl6bkhoTGhRa0xUZGZlcGNLWWJpUTlCc0pWYWYiLCJtZW1vIjoiaW52b2ljZS00MiIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwidG9rZW5Qcm9ncmFtIjoiVG9rZW5rZWdRZmVaeWlOd0FKYk5iR0tQRlhDV3VCdmY5U3M2MjNWUTVEQSIsIndpdGhkcmF3RGVsYXkiOjM2MDB9LCJtYXhUaW1lb3V0U2Vjb25kcyI6MzAwLCJuZXR3b3JrIjoic29sYW5hOkV0V1RSQUJaYVlxNmlNZmVZS291UnUxNjZWVTJ4cWExIiwicGF5VG8iOiJDWGhyRlpKTEtxanptUDNzallMY0Y0ZFRlWFdLQ3k5ZTJTWFhaMllvNk1QWSIsInNjaGVtZSI6ImJhdGNoLXNldHRsZW1lbnQifSwicGF5bG9hZCI6eyJjaGFubmVsQ29uZmlnIjp7Im9wZW5TbG90IjozNDEwMDAwMDAsInBheWVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJwYXllckF1dGhvcml6ZXIiOiJHbWFEcnBwQkM3UDVBUktWOGczZGppd1A4OXZ6MWpMSzIzVjJHQmp1QUVHQiIsInJlY2VpdmVyIjoiQ1hockZaSkxLcWp6bVAzc2pZTGNGNGRUZVhXS0N5OWUyU1hYWjJZbzZNUFkiLCJyZWNlaXZlckF1dGhvcml6ZXIiOiJBb1ZzR2FqOE1TSjZ4d0t4ZkZ4bzlpWldIM2VuQzhSUlRYS0gyZngyRjhvcyIsInNhbHQiOiI0MiIsInRva2VuIjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwiZGVwb3NpdCI6eyJhbW91bnQiOiI2MDAwIiwidHJhbnNhY3Rpb24iOiJBZ0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUJFbGxhZGZKRmNmMHk3ZGtqNEtlOFBJeFoycnZxK1R2WXhHRGhBMWZpUVlqT0xNQ1EyWU1ncm56bEpyd1VFTTRkdm82NXNKQ1JpQUdnOWh6VWxzUDRPZ0FJQUJRcjlGeVE0V3FESFcyVDdlTTFnTDZIWmtmM3I5MnNUeFk3WEF1cklOZW4yR09wS2JHUGluRklLdnZWUWV4TXV4Zm1WUjNhdXZyNTdra0llNm1rVVJ0SXNFdWsySzZja1BjcS9FcEs5UjJWMENzendnNDV3eHVmODBadC9aTEZlSXg1cmhQNVVCWm1RcHVvakNOeGxpRld0bFlwbEhoUlhKaVAzK3RPVDI3QVQ3UGlwZ2x0WTd5MWN4M1F4NGZuR0xRMS9wU1lmaTdmNGgyMmZIb21nMlNzZ0F3WkdiK1VoRnpMLzdLMjZjc09iNTd5TTVidkY5eEpyTEVPYk9rQUFBQUFGU2xOYW1Ta2hCazBrNkhGZzJqaDhmRFcxM2J5U3U0SGtINmhBUVFWRWpRYmQ5dUhYWmFHVDJjdmhSczdyZWF3Y3RJWHRYMXMza1RxTTlZVisvd0NwTzBRc3M1RWhWL0U2a3owQk5DZ3RBeXRmL3MwQm90dnh0M2tHQ044QUxxZW5vZnVrNnlzSkNaUDMwdC9XSzRuaXVISUhlbU9mMTlkSHFPbWZZOVFWcmdBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFCQVVBQlFLQUdnWUFCUUFKQTBCTFRBQUFBQUFBQ1FZQkJBTUNDQWNKQTNBWEFBQUFBQUFBQmdBS2FXNTJiMmxqWlMwME1nQT0ifSwidHlwZSI6ImRlcG9zaXQiLCJ2b3VjaGVyIjp7ImNoYW5uZWxJZCI6IkhqZzJQRGdMeFlEaVFXUkhySmVlWTlWOWlOeWViTTlNV3V0b0E2N2VpdnNaIiwiZXhwaXJlc0F0IjowLCJtYXhDbGFpbWFibGVBbW91bnQiOiI0MDAwIiwic2lnbmF0dXJlIjoiM1dZTmpjbWhkNHNYb254UVByQnFyRmJzVnQ5Sm9nRlN0b0FTcGo0bzFMVG5MeGk5SGU0YjRlOHRIanN1Q3RNQ1dCUGt0b1JmekdYeEhTZko5dVlnYVhEUiJ9fSwieDQwMlZlcnNpb24iOjJ9" + "x402PaymentHeader": "eyJhY2NlcHRlZCI6eyJhbW91bnQiOiIxMDAwIiwiYXNzZXQiOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsImV4dHJhIjp7ImZlZVBheWVyIjoiSjJ4Y2NSdHVHNDNkckVTTFl6bkhoTGhRa0xUZGZlcGNLWWJpUTlCc0pWYWYiLCJtZW1vIjoiaW52b2ljZS00MiIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwidG9rZW5Qcm9ncmFtIjoiVG9rZW5rZWdRZmVaeWlOd0FKYk5iR0tQRlhDV3VCdmY5U3M2MjNWUTVEQSIsIndpdGhkcmF3RGVsYXkiOjM2MDB9LCJtYXhUaW1lb3V0U2Vjb25kcyI6MzAwLCJuZXR3b3JrIjoic29sYW5hOkV0V1RSQUJaYVlxNmlNZmVZS291UnUxNjZWVTJ4cWExIiwicGF5VG8iOiJDWGhyRlpKTEtxanptUDNzallMY0Y0ZFRlWFdLQ3k5ZTJTWFhaMllvNk1QWSIsInNjaGVtZSI6ImJhdGNoLXNldHRsZW1lbnQifSwicGF5bG9hZCI6eyJjaGFubmVsQ29uZmlnIjp7Im9wZW5TbG90IjozNDEwMDAwMDAsInBheWVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJwYXllckF1dGhvcml6ZXIiOiJHbWFEcnBwQkM3UDVBUktWOGczZGppd1A4OXZ6MWpMSzIzVjJHQmp1QUVHQiIsInJlY2VpdmVyIjoiQ1hockZaSkxLcWp6bVAzc2pZTGNGNGRUZVhXS0N5OWUyU1hYWjJZbzZNUFkiLCJyZWNlaXZlckF1dGhvcml6ZXIiOiJBb1ZzR2FqOE1TSjZ4d0t4ZkZ4bzlpWldIM2VuQzhSUlRYS0gyZngyRjhvcyIsInNhbHQiOiI0MiIsInRva2VuIjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwiZGVwb3NpdCI6eyJhbW91bnQiOiI2MDAwIiwidHJhbnNhY3Rpb24iOiJBZ0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUNBYk1zejMvMXIvdnVCajdGUFZRYzc0aFQrWVhVTHVXYWE4MTlhQWlFTEI2YjNmQ0QrQ2lxYnBEa2tFWHpHU2svMFR4N3E4OXp1cVlOQ3F4U04zUjROZ0FJQUJRcjlGeVE0V3FESFcyVDdlTTFnTDZIWmtmM3I5MnNUeFk3WEF1cklOZW4yR09wS2JHUGluRklLdnZWUWV4TXV4Zm1WUjNhdXZyNTdra0llNm1rVVJ0SXNFdWsySzZja1BjcS9FcEs5UjJWMENzendnNDV3eHVmODBadC9aTEZlSXg1cmhQNVVCWm1RcHVvakNOeGxpRld0bFlwbEhoUlhKaVAzK3RPVDI3QVQ3UGlwZ2x0WTd5MWN4M1F4NGZuR0xRMS9wU1lmaTdmNGgyMmZIb21nMlNzZ0F3WkdiK1VoRnpMLzdLMjZjc09iNTd5TTVidkY5eEpyTEVPYk9rQUFBQUFGU2xOYW1Ta2hCazBrNkhGZzJqaDhmRFcxM2J5U3U0SGtINmhBUVFWRWpRYmQ5dUhYWmFHVDJjdmhSczdyZWF3Y3RJWHRYMXMza1RxTTlZVisvd0NwTzBRc3M1RWhWL0U2a3owQk5DZ3RBeXRmL3MwQm90dnh0M2tHQ044QUxxZW5vZnVrNnlzSkNaUDMwdC9XSzRuaXVISUhlbU9mMTlkSHFPbWZZOVFWcmdBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFCQVVBQlFLQUdnWUFCUUFKQTRnVEFBQUFBQUFBQ1FZQkJBTUNDQWNKQTNBWEFBQUFBQUFBQmdBS2FXNTJiMmxqWlMwME1nQT0ifSwidHlwZSI6ImRlcG9zaXQiLCJ2b3VjaGVyIjp7ImNoYW5uZWxJZCI6IkhqZzJQRGdMeFlEaVFXUkhySmVlWTlWOWlOeWViTTlNV3V0b0E2N2VpdnNaIiwiZXhwaXJlc0F0IjowLCJtYXhDbGFpbWFibGVBbW91bnQiOiI0MDAwIiwic2lnbmF0dXJlIjoiM1dZTmpjbWhkNHNYb254UVByQnFyRmJzVnQ5Sm9nRlN0b0FTcGo0bzFMVG5MeGk5SGU0YjRlOHRIanN1Q3RNQ1dCUGt0b1JmekdYeEhTZko5dVlnYVhEUiJ9fSwieDQwMlZlcnNpb24iOjJ9" }, "intent": "x402-batch-settlement", "mode": "verify-transaction", @@ -318,6 +318,335 @@ }, "tier": "offline" }, + { + "bugType": "auth-bypass", + "description": "SetComputeUnitLimit 400000 and SetComputeUnitPrice 5000000, each at its own cap: the sponsor would pay a 2000000 lamport priority fee, so it bounds the fee as limit times price (RULINGS S6). Pair: batch-verify-top-up-compute-budget-prefix.", + "expect": { + "alsoConformant": [ + { + "outcome": "accept" + } + ], + "alsoConformantReason": "the upto and batch-settlement schemes cap the compute unit limit at 400,000 and the unit price at 5,000,000 micro-lamports (or a version-1 priorityFee at 5 lamports per unit) and this transaction is within them; the 2,000 lamport cap on the total fee is pay-kit's stricter local policy, which the schemes allow but do not require (upto: “A sponsor MAY apply a stricter local policy for compute-unit limit, compute-unit price, and required-signature count”; batch-settlement: “A sponsor MAY apply stricter local compute-unit, priority-fee, or required-signature caps”), so a sponsor without it accepts (RULINGS S6).", + "outcome": "reject", + "rejectCode": "setup-transaction" + }, + "id": "batch-verify-top-up-priority-fee-over-cap-reject", + "input": { + "batchRequirements": { + "amount": "1000", + "asset": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "extra": { + "feePayer": "J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf", + "memo": "invoice-42", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "tokenProgram": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "withdrawDelay": 3600 + }, + "maxTimeoutSeconds": 300, + "network": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "payTo": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "scheme": "batch-settlement" + }, + "batchServer": { + "cluster": "devnet", + "currency": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "decimals": 6, + "feePayerSecretKey": [ + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 253, + 23, + 36, + 56, + 90, + 160, + 199, + 91, + 100, + 251, + 120, + 205, + 96, + 47, + 161, + 217, + 145, + 253, + 235, + 247, + 107, + 19, + 197, + 142, + 215, + 2, + 234, + 200, + 53, + 233, + 246, + 24 + ], + "maxTimeoutSeconds": 300, + "memo": "invoice-42", + "payTo": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "price": "0.001", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "withdrawDelay": 3600 + }, + "batchServerChannel": { + "channelId": "Hjg2PDgLxYDiQWRHrJeeY9V9iNyebM9MWutoA67eivsZ", + "chargedCumulativeAmount": "3000", + "deposit": "4000", + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "settled": "0" + }, + "rpcFixtures": { + "accounts": { + "8EiF91LJfbatqHRY3k2jp8dwrFY3yDQeEovpMDZnpJiP": { + "data": "O0Qss5EhV/E6kz0BNCgtAytf/s0Botvxt3kGCN8ALqfqSmxj4pxSCr71UHsTLsX5lUd2rr6+e5JCHuppFEbSLADKmjsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + "BSMX9adNvtMHhBSbiuDeaPZZbF82cmPJkSHyptJSHecz": { + "data": "O0Qss5EhV/E6kz0BNCgtAytf/s0Botvxt3kGCN8ALqc7S0pMPs1+WdY0rmfl3rvsCtBvIE3wE6aVozdqV7mNBQDKmjsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + "Hjg2PDgLxYDiQWRHrJeeY9V9iNyebM9MWutoA67eivsZ": { + "data": "AQH/ACoAAAAAAAAAoA8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAOAABKHxlNESMyCQEQHZINFOcuqsCHfS894FMmEGgZV1RQmepKbGPinFIKvvVQexMuxfmVR3auvr57kkIe6mkURtIs/RckOFqgx1tk+3jNYC+h2ZH96/drE8WO1wLqyDXp9hjqSmxj4pxSCr71UHsTLsX5lUd2rr6+e5JCHuppFEbSLDtELLORIVfxOpM9ATQoLQMrX/7NAaLb8bd5BgjfAC6n/RckOFqgx1tk+3jNYC+h2ZH96/drE8WO1wLqyDXp9hhAP1MUAAAAAA==", + "owner": "CHNLxYvVA28MJP9PrFuDXccuoGXAx7jBacfLEkahyGsX" + }, + "PjeTAeWHZHjrBForCEJvMVmRJpW5dngPaRzCp8w1MM4": { + "data": "O0Qss5EhV/E6kz0BNCgtAytf/s0Botvxt3kGCN8ALqerTiszHktPOhVCuuD5Vd1dMwNJx06hxwqSBewGVQkiMwDKmjsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + "f5xag9qZ5qmEkt2MDrBQZENh9QV1orw3UyrqAg5wTc3": { + "data": "O0Qss5EhV/E6kz0BNCgtAytf/s0Botvxt3kGCN8ALqf9FyQ4WqDHW2T7eM1gL6HZkf3r92sTxY7XAurINen2GADKmjsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + } + }, + "mints": { + "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU": { + "decimals": 6, + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + } + }, + "recentBlockhash": "11111111111111111111111111111111", + "slot": 341000100 + }, + "x402PaymentHeader": "eyJhY2NlcHRlZCI6eyJhbW91bnQiOiIxMDAwIiwiYXNzZXQiOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsImV4dHJhIjp7ImZlZVBheWVyIjoiSjJ4Y2NSdHVHNDNkckVTTFl6bkhoTGhRa0xUZGZlcGNLWWJpUTlCc0pWYWYiLCJtZW1vIjoiaW52b2ljZS00MiIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwidG9rZW5Qcm9ncmFtIjoiVG9rZW5rZWdRZmVaeWlOd0FKYk5iR0tQRlhDV3VCdmY5U3M2MjNWUTVEQSIsIndpdGhkcmF3RGVsYXkiOjM2MDB9LCJtYXhUaW1lb3V0U2Vjb25kcyI6MzAwLCJuZXR3b3JrIjoic29sYW5hOkV0V1RSQUJaYVlxNmlNZmVZS291UnUxNjZWVTJ4cWExIiwicGF5VG8iOiJDWGhyRlpKTEtxanptUDNzallMY0Y0ZFRlWFdLQ3k5ZTJTWFhaMllvNk1QWSIsInNjaGVtZSI6ImJhdGNoLXNldHRsZW1lbnQifSwicGF5bG9hZCI6eyJjaGFubmVsQ29uZmlnIjp7Im9wZW5TbG90IjozNDEwMDAwMDAsInBheWVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJwYXllckF1dGhvcml6ZXIiOiJHbWFEcnBwQkM3UDVBUktWOGczZGppd1A4OXZ6MWpMSzIzVjJHQmp1QUVHQiIsInJlY2VpdmVyIjoiQ1hockZaSkxLcWp6bVAzc2pZTGNGNGRUZVhXS0N5OWUyU1hYWjJZbzZNUFkiLCJyZWNlaXZlckF1dGhvcml6ZXIiOiJBb1ZzR2FqOE1TSjZ4d0t4ZkZ4bzlpWldIM2VuQzhSUlRYS0gyZngyRjhvcyIsInNhbHQiOiI0MiIsInRva2VuIjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwiZGVwb3NpdCI6eyJhbW91bnQiOiI2MDAwIiwidHJhbnNhY3Rpb24iOiJBZ0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUJFbGxhZGZKRmNmMHk3ZGtqNEtlOFBJeFoycnZxK1R2WXhHRGhBMWZpUVlqT0xNQ1EyWU1ncm56bEpyd1VFTTRkdm82NXNKQ1JpQUdnOWh6VWxzUDRPZ0FJQUJRcjlGeVE0V3FESFcyVDdlTTFnTDZIWmtmM3I5MnNUeFk3WEF1cklOZW4yR09wS2JHUGluRklLdnZWUWV4TXV4Zm1WUjNhdXZyNTdra0llNm1rVVJ0SXNFdWsySzZja1BjcS9FcEs5UjJWMENzendnNDV3eHVmODBadC9aTEZlSXg1cmhQNVVCWm1RcHVvakNOeGxpRld0bFlwbEhoUlhKaVAzK3RPVDI3QVQ3UGlwZ2x0WTd5MWN4M1F4NGZuR0xRMS9wU1lmaTdmNGgyMmZIb21nMlNzZ0F3WkdiK1VoRnpMLzdLMjZjc09iNTd5TTVidkY5eEpyTEVPYk9rQUFBQUFGU2xOYW1Ta2hCazBrNkhGZzJqaDhmRFcxM2J5U3U0SGtINmhBUVFWRWpRYmQ5dUhYWmFHVDJjdmhSczdyZWF3Y3RJWHRYMXMza1RxTTlZVisvd0NwTzBRc3M1RWhWL0U2a3owQk5DZ3RBeXRmL3MwQm90dnh0M2tHQ044QUxxZW5vZnVrNnlzSkNaUDMwdC9XSzRuaXVISUhlbU9mMTlkSHFPbWZZOVFWcmdBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFCQVVBQlFLQUdnWUFCUUFKQTBCTFRBQUFBQUFBQ1FZQkJBTUNDQWNKQTNBWEFBQUFBQUFBQmdBS2FXNTJiMmxqWlMwME1nQT0ifSwidHlwZSI6ImRlcG9zaXQiLCJ2b3VjaGVyIjp7ImNoYW5uZWxJZCI6IkhqZzJQRGdMeFlEaVFXUkhySmVlWTlWOWlOeWViTTlNV3V0b0E2N2VpdnNaIiwiZXhwaXJlc0F0IjowLCJtYXhDbGFpbWFibGVBbW91bnQiOiI0MDAwIiwic2lnbmF0dXJlIjoiM1dZTmpjbWhkNHNYb254UVByQnFyRmJzVnQ5Sm9nRlN0b0FTcGo0bzFMVG5MeGk5SGU0YjRlOHRIanN1Q3RNQ1dCUGt0b1JmekdYeEhTZko5dVlnYVhEUiJ9fSwieDQwMlZlcnNpb24iOjJ9" + }, + "intent": "x402-batch-settlement", + "mode": "verify-transaction", + "provenance": "generated", + "requirements": [ + "X402-b4167aad45", + "X402-a93234f1d7" + ], + "role": "server", + "spec": { + "doc": "x402/specs/schemes/batch-settlement/scheme_batch_settlement_svm.md", + "quote": "A sponsor MAY apply stricter local compute-unit, priority-fee, or required-signature caps, but MUST NOT relax the absolute maxima above.", + "section": "Client-supplied transaction acceptance policy" + }, + "tier": "offline" + }, + { + "bugType": "auth-bypass", + "description": "SetComputeUnitPrice 5001 with no SetComputeUnitLimit: the runtime budgets 200000 units for each of the top_up and the memo, so the sponsor would pay 2001 lamports, one over its cap (RULINGS S6). A verifier that bounds only declared limits accepts it.", + "expect": { + "alsoConformant": [ + { + "outcome": "accept" + } + ], + "alsoConformantReason": "the upto and batch-settlement schemes cap the compute unit limit at 400,000 and the unit price at 5,000,000 micro-lamports (or a version-1 priorityFee at 5 lamports per unit) and this transaction is within them; the 2,000 lamport cap on the total fee is pay-kit's stricter local policy, which the schemes allow but do not require (upto: “A sponsor MAY apply a stricter local policy for compute-unit limit, compute-unit price, and required-signature count”; batch-settlement: “A sponsor MAY apply stricter local compute-unit, priority-fee, or required-signature caps”), so a sponsor without it accepts (RULINGS S6).", + "outcome": "reject", + "rejectCode": "setup-transaction" + }, + "id": "batch-verify-top-up-implicit-limit-priority-fee-over-cap-reject", + "input": { + "batchRequirements": { + "amount": "1000", + "asset": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "extra": { + "feePayer": "J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf", + "memo": "invoice-42", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "tokenProgram": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "withdrawDelay": 3600 + }, + "maxTimeoutSeconds": 300, + "network": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "payTo": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "scheme": "batch-settlement" + }, + "batchServer": { + "cluster": "devnet", + "currency": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "decimals": 6, + "feePayerSecretKey": [ + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 253, + 23, + 36, + 56, + 90, + 160, + 199, + 91, + 100, + 251, + 120, + 205, + 96, + 47, + 161, + 217, + 145, + 253, + 235, + 247, + 107, + 19, + 197, + 142, + 215, + 2, + 234, + 200, + 53, + 233, + 246, + 24 + ], + "maxTimeoutSeconds": 300, + "memo": "invoice-42", + "payTo": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "price": "0.001", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "withdrawDelay": 3600 + }, + "batchServerChannel": { + "channelId": "Hjg2PDgLxYDiQWRHrJeeY9V9iNyebM9MWutoA67eivsZ", + "chargedCumulativeAmount": "3000", + "deposit": "4000", + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "settled": "0" + }, + "rpcFixtures": { + "accounts": { + "8EiF91LJfbatqHRY3k2jp8dwrFY3yDQeEovpMDZnpJiP": { + "data": "O0Qss5EhV/E6kz0BNCgtAytf/s0Botvxt3kGCN8ALqfqSmxj4pxSCr71UHsTLsX5lUd2rr6+e5JCHuppFEbSLADKmjsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + "BSMX9adNvtMHhBSbiuDeaPZZbF82cmPJkSHyptJSHecz": { + "data": "O0Qss5EhV/E6kz0BNCgtAytf/s0Botvxt3kGCN8ALqc7S0pMPs1+WdY0rmfl3rvsCtBvIE3wE6aVozdqV7mNBQDKmjsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + "Hjg2PDgLxYDiQWRHrJeeY9V9iNyebM9MWutoA67eivsZ": { + "data": "AQH/ACoAAAAAAAAAoA8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAOAABKHxlNESMyCQEQHZINFOcuqsCHfS894FMmEGgZV1RQmepKbGPinFIKvvVQexMuxfmVR3auvr57kkIe6mkURtIs/RckOFqgx1tk+3jNYC+h2ZH96/drE8WO1wLqyDXp9hjqSmxj4pxSCr71UHsTLsX5lUd2rr6+e5JCHuppFEbSLDtELLORIVfxOpM9ATQoLQMrX/7NAaLb8bd5BgjfAC6n/RckOFqgx1tk+3jNYC+h2ZH96/drE8WO1wLqyDXp9hhAP1MUAAAAAA==", + "owner": "CHNLxYvVA28MJP9PrFuDXccuoGXAx7jBacfLEkahyGsX" + }, + "PjeTAeWHZHjrBForCEJvMVmRJpW5dngPaRzCp8w1MM4": { + "data": "O0Qss5EhV/E6kz0BNCgtAytf/s0Botvxt3kGCN8ALqerTiszHktPOhVCuuD5Vd1dMwNJx06hxwqSBewGVQkiMwDKmjsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + "f5xag9qZ5qmEkt2MDrBQZENh9QV1orw3UyrqAg5wTc3": { + "data": "O0Qss5EhV/E6kz0BNCgtAytf/s0Botvxt3kGCN8ALqf9FyQ4WqDHW2T7eM1gL6HZkf3r92sTxY7XAurINen2GADKmjsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + } + }, + "mints": { + "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU": { + "decimals": 6, + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + } + }, + "recentBlockhash": "11111111111111111111111111111111", + "slot": 341000100 + }, + "x402PaymentHeader": "eyJhY2NlcHRlZCI6eyJhbW91bnQiOiIxMDAwIiwiYXNzZXQiOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsImV4dHJhIjp7ImZlZVBheWVyIjoiSjJ4Y2NSdHVHNDNkckVTTFl6bkhoTGhRa0xUZGZlcGNLWWJpUTlCc0pWYWYiLCJtZW1vIjoiaW52b2ljZS00MiIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwidG9rZW5Qcm9ncmFtIjoiVG9rZW5rZWdRZmVaeWlOd0FKYk5iR0tQRlhDV3VCdmY5U3M2MjNWUTVEQSIsIndpdGhkcmF3RGVsYXkiOjM2MDB9LCJtYXhUaW1lb3V0U2Vjb25kcyI6MzAwLCJuZXR3b3JrIjoic29sYW5hOkV0V1RSQUJaYVlxNmlNZmVZS291UnUxNjZWVTJ4cWExIiwicGF5VG8iOiJDWGhyRlpKTEtxanptUDNzallMY0Y0ZFRlWFdLQ3k5ZTJTWFhaMllvNk1QWSIsInNjaGVtZSI6ImJhdGNoLXNldHRsZW1lbnQifSwicGF5bG9hZCI6eyJjaGFubmVsQ29uZmlnIjp7Im9wZW5TbG90IjozNDEwMDAwMDAsInBheWVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJwYXllckF1dGhvcml6ZXIiOiJHbWFEcnBwQkM3UDVBUktWOGczZGppd1A4OXZ6MWpMSzIzVjJHQmp1QUVHQiIsInJlY2VpdmVyIjoiQ1hockZaSkxLcWp6bVAzc2pZTGNGNGRUZVhXS0N5OWUyU1hYWjJZbzZNUFkiLCJyZWNlaXZlckF1dGhvcml6ZXIiOiJBb1ZzR2FqOE1TSjZ4d0t4ZkZ4bzlpWldIM2VuQzhSUlRYS0gyZngyRjhvcyIsInNhbHQiOiI0MiIsInRva2VuIjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwiZGVwb3NpdCI6eyJhbW91bnQiOiI2MDAwIiwidHJhbnNhY3Rpb24iOiJBZ0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQURnb3JVN1hQaXJ2TnhCOGgxWXNZT0xjNVNUU0tsalRVMGFzVTVTaUxJejUyazNIZFVYNG9tQUNMZ1lCWlVMZVJleVRDeXU0QnJqSnFYN1BoZ1lkZEFNZ0FJQUJRcjlGeVE0V3FESFcyVDdlTTFnTDZIWmtmM3I5MnNUeFk3WEF1cklOZW4yR09wS2JHUGluRklLdnZWUWV4TXV4Zm1WUjNhdXZyNTdra0llNm1rVVJ0SXNFdWsySzZja1BjcS9FcEs5UjJWMENzendnNDV3eHVmODBadC9aTEZlSXg1cmhQNVVCWm1RcHVvakNOeGxpRld0bFlwbEhoUlhKaVAzK3RPVDI3QVQ3UGlwZ2x0WTd5MWN4M1F4NGZuR0xRMS9wU1lmaTdmNGgyMmZIb21nMlNzZ0F3WkdiK1VoRnpMLzdLMjZjc09iNTd5TTVidkY5eEpyTEVPYk9rQUFBQUFGU2xOYW1Ta2hCazBrNkhGZzJqaDhmRFcxM2J5U3U0SGtINmhBUVFWRWpRYmQ5dUhYWmFHVDJjdmhSczdyZWF3Y3RJWHRYMXMza1RxTTlZVisvd0NwTzBRc3M1RWhWL0U2a3owQk5DZ3RBeXRmL3MwQm90dnh0M2tHQ044QUxxZW5vZnVrNnlzSkNaUDMwdC9XSzRuaXVISUhlbU9mMTlkSHFPbWZZOVFWcmdBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBd1VBQ1FPSkV3QUFBQUFBQUFrR0FRUURBZ2dIQ1FOd0Z3QUFBQUFBQUFZQUNtbHVkbTlwWTJVdE5ESUEifSwidHlwZSI6ImRlcG9zaXQiLCJ2b3VjaGVyIjp7ImNoYW5uZWxJZCI6IkhqZzJQRGdMeFlEaVFXUkhySmVlWTlWOWlOeWViTTlNV3V0b0E2N2VpdnNaIiwiZXhwaXJlc0F0IjowLCJtYXhDbGFpbWFibGVBbW91bnQiOiI0MDAwIiwic2lnbmF0dXJlIjoiM1dZTmpjbWhkNHNYb254UVByQnFyRmJzVnQ5Sm9nRlN0b0FTcGo0bzFMVG5MeGk5SGU0YjRlOHRIanN1Q3RNQ1dCUGt0b1JmekdYeEhTZko5dVlnYVhEUiJ9fSwieDQwMlZlcnNpb24iOjJ9" + }, + "intent": "x402-batch-settlement", + "mode": "verify-transaction", + "provenance": "generated", + "requirements": [ + "X402-a93234f1d7" + ], + "role": "server", + "spec": { + "doc": "x402/specs/schemes/batch-settlement/scheme_batch_settlement_svm.md", + "quote": "A sponsor MAY apply stricter local compute-unit, priority-fee, or required-signature caps, but MUST NOT relax the absolute maxima above.", + "section": "Client-supplied transaction acceptance policy" + }, + "tier": "offline" + }, { "bugType": "auth-bypass", "description": "Paired accept: the memo followed by three Lighthouse assertions in the suffix.", @@ -628,7 +957,7 @@ "role": "server", "spec": { "doc": "x402/specs/schemes/batch-settlement/scheme_batch_settlement_svm.md", - "quote": "The message MAY be legacy or version `0`, but it MUST NOT contain Address Lookup Table lookups.", + "quote": "The message version MUST be one advertised in `extra.transactionVersions` (0 when the field is absent; see [Transaction versions](#transaction-versions)), and the message MUST NOT contain Address Lookup Table lookups.", "section": "Client-supplied transaction acceptance policy" }, "tier": "offline" @@ -2842,7 +3171,7 @@ "role": "server", "spec": { "doc": "x402/specs/schemes/batch-settlement/scheme_batch_settlement_svm.md", - "quote": "An optional Compute Budget prefix containing at most one `SetComputeUnitLimit` instruction", + "quote": "In a legacy or version-0 transaction, an optional Compute Budget prefix containing at most one `SetComputeUnitLimit` instruction", "section": "Client-supplied transaction acceptance policy" }, "tier": "offline" @@ -3797,8 +4126,14 @@ }, { "bugType": "auth-bypass", - "description": "top_up data with one trailing byte (10 bytes instead of 9).", + "description": "top_up data with one trailing byte (10 bytes instead of 9). The Rust sponsor decodes the top_up as strictly as the open and refuses it; the spec states the trailing-bytes rule for the open only.", "expect": { + "alsoConformant": [ + { + "outcome": "accept" + } + ], + "alsoConformantReason": "“The facilitator MUST fully decode the instruction data, reject truncated data or trailing bytes” is stated under Canonical open only; Canonical top_up requires that “The facilitator MUST confirm the decoded amount equals `payload.deposit.amount`”, which a decoder that ignores the extra byte also confirms.", "outcome": "reject", "rejectCode": "setup-transaction" }, @@ -3943,13 +4278,13 @@ "mode": "verify-transaction", "provenance": "generated", "requirements": [ - "X402-176a26e5b6" + "X402-06bb8f3a9e" ], "role": "server", "spec": { "doc": "x402/specs/schemes/batch-settlement/scheme_batch_settlement_svm.md", - "quote": "The facilitator MUST fully decode the instruction data, reject truncated data or trailing bytes", - "section": "Canonical open" + "quote": "The facilitator MUST confirm the decoded amount equals `payload.deposit.amount`; the channel is `Open`;", + "section": "Canonical top_up" }, "tier": "offline" }, @@ -4582,5 +4917,163 @@ "section": "Canonical top_up" }, "tier": "offline" + }, + { + "bugType": "settlement", + "description": "The accept top-up, but the payer's token account holds 1 base unit against the 6000 top-up. The deposit is broadcast only after the handler runs, so a verifier that skips the balance serves the request and only then finds the deposit cannot land.", + "expect": { + "outcome": "reject", + "rejectCode": "settlement-simulation" + }, + "id": "batch-verify-top-up-unfunded-payer-reject", + "input": { + "batchRequirements": { + "amount": "1000", + "asset": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "extra": { + "feePayer": "J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf", + "memo": "invoice-42", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "tokenProgram": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "withdrawDelay": 3600 + }, + "maxTimeoutSeconds": 300, + "network": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "payTo": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "scheme": "batch-settlement" + }, + "batchServer": { + "cluster": "devnet", + "currency": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "decimals": 6, + "feePayerSecretKey": [ + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 253, + 23, + 36, + 56, + 90, + 160, + 199, + 91, + 100, + 251, + 120, + 205, + 96, + 47, + 161, + 217, + 145, + 253, + 235, + 247, + 107, + 19, + 197, + 142, + 215, + 2, + 234, + 200, + 53, + 233, + 246, + 24 + ], + "maxTimeoutSeconds": 300, + "memo": "invoice-42", + "payTo": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "price": "0.001", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "withdrawDelay": 3600 + }, + "batchServerChannel": { + "channelId": "Hjg2PDgLxYDiQWRHrJeeY9V9iNyebM9MWutoA67eivsZ", + "chargedCumulativeAmount": "3000", + "deposit": "4000", + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "settled": "0" + }, + "rpcFixtures": { + "accounts": { + "8EiF91LJfbatqHRY3k2jp8dwrFY3yDQeEovpMDZnpJiP": { + "data": "O0Qss5EhV/E6kz0BNCgtAytf/s0Botvxt3kGCN8ALqfqSmxj4pxSCr71UHsTLsX5lUd2rr6+e5JCHuppFEbSLAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + "BSMX9adNvtMHhBSbiuDeaPZZbF82cmPJkSHyptJSHecz": { + "data": "O0Qss5EhV/E6kz0BNCgtAytf/s0Botvxt3kGCN8ALqc7S0pMPs1+WdY0rmfl3rvsCtBvIE3wE6aVozdqV7mNBQDKmjsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + "Hjg2PDgLxYDiQWRHrJeeY9V9iNyebM9MWutoA67eivsZ": { + "data": "AQH/ACoAAAAAAAAAoA8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAOAABKHxlNESMyCQEQHZINFOcuqsCHfS894FMmEGgZV1RQmepKbGPinFIKvvVQexMuxfmVR3auvr57kkIe6mkURtIs/RckOFqgx1tk+3jNYC+h2ZH96/drE8WO1wLqyDXp9hjqSmxj4pxSCr71UHsTLsX5lUd2rr6+e5JCHuppFEbSLDtELLORIVfxOpM9ATQoLQMrX/7NAaLb8bd5BgjfAC6n/RckOFqgx1tk+3jNYC+h2ZH96/drE8WO1wLqyDXp9hhAP1MUAAAAAA==", + "owner": "CHNLxYvVA28MJP9PrFuDXccuoGXAx7jBacfLEkahyGsX" + }, + "PjeTAeWHZHjrBForCEJvMVmRJpW5dngPaRzCp8w1MM4": { + "data": "O0Qss5EhV/E6kz0BNCgtAytf/s0Botvxt3kGCN8ALqerTiszHktPOhVCuuD5Vd1dMwNJx06hxwqSBewGVQkiMwDKmjsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + "f5xag9qZ5qmEkt2MDrBQZENh9QV1orw3UyrqAg5wTc3": { + "data": "O0Qss5EhV/E6kz0BNCgtAytf/s0Botvxt3kGCN8ALqf9FyQ4WqDHW2T7eM1gL6HZkf3r92sTxY7XAurINen2GADKmjsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + } + }, + "mints": { + "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU": { + "decimals": 6, + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + } + }, + "recentBlockhash": "11111111111111111111111111111111", + "slot": 341000100 + }, + "x402PaymentHeader": "eyJhY2NlcHRlZCI6eyJhbW91bnQiOiIxMDAwIiwiYXNzZXQiOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsImV4dHJhIjp7ImZlZVBheWVyIjoiSjJ4Y2NSdHVHNDNkckVTTFl6bkhoTGhRa0xUZGZlcGNLWWJpUTlCc0pWYWYiLCJtZW1vIjoiaW52b2ljZS00MiIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwidG9rZW5Qcm9ncmFtIjoiVG9rZW5rZWdRZmVaeWlOd0FKYk5iR0tQRlhDV3VCdmY5U3M2MjNWUTVEQSIsIndpdGhkcmF3RGVsYXkiOjM2MDB9LCJtYXhUaW1lb3V0U2Vjb25kcyI6MzAwLCJuZXR3b3JrIjoic29sYW5hOkV0V1RSQUJaYVlxNmlNZmVZS291UnUxNjZWVTJ4cWExIiwicGF5VG8iOiJDWGhyRlpKTEtxanptUDNzallMY0Y0ZFRlWFdLQ3k5ZTJTWFhaMllvNk1QWSIsInNjaGVtZSI6ImJhdGNoLXNldHRsZW1lbnQifSwicGF5bG9hZCI6eyJjaGFubmVsQ29uZmlnIjp7Im9wZW5TbG90IjozNDEwMDAwMDAsInBheWVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJwYXllckF1dGhvcml6ZXIiOiJHbWFEcnBwQkM3UDVBUktWOGczZGppd1A4OXZ6MWpMSzIzVjJHQmp1QUVHQiIsInJlY2VpdmVyIjoiQ1hockZaSkxLcWp6bVAzc2pZTGNGNGRUZVhXS0N5OWUyU1hYWjJZbzZNUFkiLCJyZWNlaXZlckF1dGhvcml6ZXIiOiJBb1ZzR2FqOE1TSjZ4d0t4ZkZ4bzlpWldIM2VuQzhSUlRYS0gyZngyRjhvcyIsInNhbHQiOiI0MiIsInRva2VuIjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwiZGVwb3NpdCI6eyJhbW91bnQiOiI2MDAwIiwidHJhbnNhY3Rpb24iOiJBZ0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUJKejlBaGkyYTZVNGlRa3J4OGVYK3lEaVZWQ1dyVmNrcmp3VjZjZ1dLY3hLRmNIRTVYYTRuZ3V2dEFxUjBlSGFpRncxSWN0SS9WUDZ1L2xWWnc1b1FKZ0FJQUJBbjlGeVE0V3FESFcyVDdlTTFnTDZIWmtmM3I5MnNUeFk3WEF1cklOZW4yR09wS2JHUGluRklLdnZWUWV4TXV4Zm1WUjNhdXZyNTdra0llNm1rVVJ0SXNFdWsySzZja1BjcS9FcEs5UjJWMENzendnNDV3eHVmODBadC9aTEZlSXg1cmhQNVVCWm1RcHVvakNOeGxpRld0bFlwbEhoUlhKaVAzK3RPVDI3QVQ3UGlwZ2x0WTd5MWN4M1F4NGZuR0xRMS9wU1lmaTdmNGgyMmZIb21nMlNzZ0JVcFRXcGtwSVFaTkpPaHhZTm80Zkh3MXRkMjhrcnVCNUIrb1FFRUZSSTBHM2ZiaDEyV2hrOW5MNFViTzYzbXNITFNGN1Y5Yk41RTZqUFdGZnY4QXFUdEVMTE9SSVZmeE9wTTlBVFFvTFFNclgvN05BYUxiOGJkNUJnamZBQzZucDZIN3BPc3JDUW1UOTlMZjFpdUo0cmh5QjNwam45ZlhSNmpwbjJQVUZhNEFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFJSUJnRUVBd0lIQmdrRGNCY0FBQUFBQUFBRkFBcHBiblp2YVdObExUUXlBQT09In0sInR5cGUiOiJkZXBvc2l0Iiwidm91Y2hlciI6eyJjaGFubmVsSWQiOiJIamcyUERnTHhZRGlRV1JIckplZVk5VjlpTnllYk05TVd1dG9BNjdlaXZzWiIsImV4cGlyZXNBdCI6MCwibWF4Q2xhaW1hYmxlQW1vdW50IjoiNDAwMCIsInNpZ25hdHVyZSI6IjNXWU5qY21oZDRzWG9ueFFQckJxckZic1Z0OUpvZ0ZTdG9BU3BqNG8xTFRuTHhpOUhlNGI0ZTh0SGpzdUN0TUNXQlBrdG9SZnpHWHhIU2ZKOXVZZ2FYRFIifX0sIng0MDJWZXJzaW9uIjoyfQ==" + }, + "intent": "x402-batch-settlement", + "mode": "verify-transaction", + "provenance": "generated", + "requirements": [ + "X402-014270dc81" + ], + "role": "server", + "spec": { + "doc": "x402/specs/schemes/batch-settlement/scheme_batch_settlement_svm.md", + "quote": "It MUST confirm the payer has sufficient tokens.", + "section": "Canonical top_up" + }, + "tier": "offline" } ] diff --git a/harness/vectors/batch-verify-voucher.json b/harness/vectors/batch-verify-voucher.json index dc9ec9642..417993074 100644 --- a/harness/vectors/batch-verify-voucher.json +++ b/harness/vectors/batch-verify-voucher.json @@ -267,6 +267,7 @@ "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", "settled": "0" }, + "batchVerdictFromStore": true, "rpcFixtures": { "accounts": { "8EiF91LJfbatqHRY3k2jp8dwrFY3yDQeEovpMDZnpJiP": { @@ -425,6 +426,7 @@ "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", "settled": "0" }, + "batchVerdictFromStore": true, "rpcFixtures": { "accounts": { "8EiF91LJfbatqHRY3k2jp8dwrFY3yDQeEovpMDZnpJiP": { @@ -583,6 +585,7 @@ "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", "settled": "0" }, + "batchVerdictFromStore": true, "rpcFixtures": { "accounts": { "8EiF91LJfbatqHRY3k2jp8dwrFY3yDQeEovpMDZnpJiP": { @@ -1994,6 +1997,7 @@ "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", "settled": "0" }, + "batchVerdictFromStore": true, "rpcFixtures": { "accounts": { "8EiF91LJfbatqHRY3k2jp8dwrFY3yDQeEovpMDZnpJiP": { @@ -3155,6 +3159,164 @@ }, "tier": "offline" }, + { + "bugType": "auth-bypass", + "description": "channelConfig.receiver is the text invalid_batch_settlement_svm_cumulative_amount_mismatch rather than payTo. The failure is the receiver binding (channel-state), whatever code the client's own text names: a verifier that classifies its error by searching the message reports a cumulative mismatch, and answers it with the corrective 402 carrying the channel's latest voucher.", + "expect": { + "outcome": "reject", + "rejectCode": "channel-state" + }, + "id": "batch-verify-voucher-receiver-quotes-a-code-reject", + "input": { + "batchRequirements": { + "amount": "1000", + "asset": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "extra": { + "feePayer": "J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf", + "memo": "invoice-42", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "tokenProgram": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "withdrawDelay": 3600 + }, + "maxTimeoutSeconds": 300, + "network": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "payTo": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "scheme": "batch-settlement" + }, + "batchServer": { + "cluster": "devnet", + "currency": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "decimals": 6, + "feePayerSecretKey": [ + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 253, + 23, + 36, + 56, + 90, + 160, + 199, + 91, + 100, + 251, + 120, + 205, + 96, + 47, + 161, + 217, + 145, + 253, + 235, + 247, + 107, + 19, + 197, + 142, + 215, + 2, + 234, + 200, + 53, + 233, + 246, + 24 + ], + "maxTimeoutSeconds": 300, + "memo": "invoice-42", + "payTo": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "price": "0.001", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "withdrawDelay": 3600 + }, + "batchServerChannel": { + "channelId": "Hjg2PDgLxYDiQWRHrJeeY9V9iNyebM9MWutoA67eivsZ", + "chargedCumulativeAmount": "3000", + "deposit": "10000", + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "settled": "0" + }, + "rpcFixtures": { + "accounts": { + "8EiF91LJfbatqHRY3k2jp8dwrFY3yDQeEovpMDZnpJiP": { + "data": "O0Qss5EhV/E6kz0BNCgtAytf/s0Botvxt3kGCN8ALqfqSmxj4pxSCr71UHsTLsX5lUd2rr6+e5JCHuppFEbSLADKmjsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + "BSMX9adNvtMHhBSbiuDeaPZZbF82cmPJkSHyptJSHecz": { + "data": "O0Qss5EhV/E6kz0BNCgtAytf/s0Botvxt3kGCN8ALqc7S0pMPs1+WdY0rmfl3rvsCtBvIE3wE6aVozdqV7mNBQDKmjsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + "Hjg2PDgLxYDiQWRHrJeeY9V9iNyebM9MWutoA67eivsZ": { + "data": "AQH/ACoAAAAAAAAAECcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAOAABKHxlNESMyCQEQHZINFOcuqsCHfS894FMmEGgZV1RQmepKbGPinFIKvvVQexMuxfmVR3auvr57kkIe6mkURtIs/RckOFqgx1tk+3jNYC+h2ZH96/drE8WO1wLqyDXp9hjqSmxj4pxSCr71UHsTLsX5lUd2rr6+e5JCHuppFEbSLDtELLORIVfxOpM9ATQoLQMrX/7NAaLb8bd5BgjfAC6n/RckOFqgx1tk+3jNYC+h2ZH96/drE8WO1wLqyDXp9hhAP1MUAAAAAA==", + "owner": "CHNLxYvVA28MJP9PrFuDXccuoGXAx7jBacfLEkahyGsX" + }, + "PjeTAeWHZHjrBForCEJvMVmRJpW5dngPaRzCp8w1MM4": { + "data": "O0Qss5EhV/E6kz0BNCgtAytf/s0Botvxt3kGCN8ALqerTiszHktPOhVCuuD5Vd1dMwNJx06hxwqSBewGVQkiMwDKmjsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + "f5xag9qZ5qmEkt2MDrBQZENh9QV1orw3UyrqAg5wTc3": { + "data": "O0Qss5EhV/E6kz0BNCgtAytf/s0Botvxt3kGCN8ALqf9FyQ4WqDHW2T7eM1gL6HZkf3r92sTxY7XAurINen2GADKmjsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + } + }, + "mints": { + "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU": { + "decimals": 6, + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + } + }, + "recentBlockhash": "11111111111111111111111111111111", + "slot": 341000100 + }, + "x402PaymentHeader": "eyJhY2NlcHRlZCI6eyJhbW91bnQiOiIxMDAwIiwiYXNzZXQiOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsImV4dHJhIjp7ImZlZVBheWVyIjoiSjJ4Y2NSdHVHNDNkckVTTFl6bkhoTGhRa0xUZGZlcGNLWWJpUTlCc0pWYWYiLCJtZW1vIjoiaW52b2ljZS00MiIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwidG9rZW5Qcm9ncmFtIjoiVG9rZW5rZWdRZmVaeWlOd0FKYk5iR0tQRlhDV3VCdmY5U3M2MjNWUTVEQSIsIndpdGhkcmF3RGVsYXkiOjM2MDB9LCJtYXhUaW1lb3V0U2Vjb25kcyI6MzAwLCJuZXR3b3JrIjoic29sYW5hOkV0V1RSQUJaYVlxNmlNZmVZS291UnUxNjZWVTJ4cWExIiwicGF5VG8iOiJDWGhyRlpKTEtxanptUDNzallMY0Y0ZFRlWFdLQ3k5ZTJTWFhaMllvNk1QWSIsInNjaGVtZSI6ImJhdGNoLXNldHRsZW1lbnQifSwicGF5bG9hZCI6eyJjaGFubmVsQ29uZmlnIjp7Im9wZW5TbG90IjozNDEwMDAwMDAsInBheWVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJwYXllckF1dGhvcml6ZXIiOiJHbWFEcnBwQkM3UDVBUktWOGczZGppd1A4OXZ6MWpMSzIzVjJHQmp1QUVHQiIsInJlY2VpdmVyIjoiaW52YWxpZF9iYXRjaF9zZXR0bGVtZW50X3N2bV9jdW11bGF0aXZlX2Ftb3VudF9taXNtYXRjaCIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwic2FsdCI6IjQyIiwidG9rZW4iOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsIndpdGhkcmF3RGVsYXkiOjM2MDB9LCJ0eXBlIjoidm91Y2hlciIsInZvdWNoZXIiOnsiY2hhbm5lbElkIjoiSGpnMlBEZ0x4WURpUVdSSHJKZWVZOVY5aU55ZWJNOU1XdXRvQTY3ZWl2c1oiLCJleHBpcmVzQXQiOjAsIm1heENsYWltYWJsZUFtb3VudCI6IjQwMDAiLCJzaWduYXR1cmUiOiIzV1lOamNtaGQ0c1hvbnhRUHJCcXJGYnNWdDlKb2dGU3RvQVNwajRvMUxUbkx4aTlIZTRiNGU4dEhqc3VDdE1DV0JQa3RvUmZ6R1h4SFNmSjl1WWdhWERSIn19LCJ4NDAyVmVyc2lvbiI6Mn0=" + }, + "intent": "x402-batch-settlement", + "mode": "verify-transaction", + "provenance": "generated", + "requirements": [ + "X402-a2dd2eb911" + ], + "role": "server", + "spec": { + "doc": "x402/specs/schemes/batch-settlement/scheme_batch_settlement_svm.md", + "quote": "Confirm the channel exists, is `Open`, has `mint == channelConfig.token == asset`, `payee == extra.feePayer`", + "section": "Phase 3 - Voucher Acceptance (before serving)" + }, + "tier": "offline" + }, { "bugType": "auth-bypass", "description": "channelConfig.token is another mint than the asset (voucher signed for that config's PDA).", @@ -3633,6 +3795,13 @@ "bugType": "auth-bypass", "description": "channelConfig omits receiverAuthorizer while the requirements advertise one: both MUST be present and equal.", "expect": { + "alsoConformant": [ + { + "outcome": "reject", + "rejectCode": "payload-type" + } + ], + "alsoConformantReason": "channelConfig.receiverAuthorizer is a required field of the wire object (“| `receiverAuthorizer` | string | Required.”), so a verifier that validates the payload shape before comparing it with extra.receiverAuthorizer refuses it as invalid_batch_settlement_svm_payload_type; the spec does not order the two checks.", "outcome": "reject", "rejectCode": "receiver-authorizer-mismatch" }, @@ -3792,6 +3961,13 @@ "bugType": "auth-bypass", "description": "channelConfig.voucherSigner \"server\" on a client-mode route: the mode must equal extra.voucherSigner.", "expect": { + "alsoConformant": [ + { + "outcome": "reject", + "rejectCode": "payload-type" + } + ], + "alsoConformantReason": "no reason code names a voucherSigner that differs from extra.voucherSigner; a server-mode channelConfig on a client-mode route is a payload the route's operation does not take (invalid_batch_settlement_svm_payload_type, “payload `type` is not valid for the current verify or settle operation”) as plausibly as a channel-state mismatch.", "outcome": "reject", "rejectCode": "channel-state" }, diff --git a/harness/vectors/batch-wire.json b/harness/vectors/batch-wire.json index 74c605727..b6ff8510e 100644 --- a/harness/vectors/batch-wire.json +++ b/harness/vectors/batch-wire.json @@ -646,12 +646,12 @@ "mode": "canonical-bytes", "provenance": "generated", "requirements": [ - "X402-7f4ee54a73" + "X402-76654742e7" ], "role": "both", "spec": { "doc": "x402/specs/schemes/batch-settlement/scheme_batch_settlement_svm.md", - "quote": "`claims[]` MUST contain between one and four entries so the instruction pairs fit in a legacy Solana transaction without address lookup tables.", + "quote": "`claims[]` MUST contain at least one entry and at most `extra.maxClaimChannels` entries, or four when the facilitator advertises no `maxClaimChannels`, so the instruction pairs fit in one transaction without address lookup tables.", "section": "4.5 Facilitator Interface" }, "tier": "offline" @@ -677,29 +677,1092 @@ "mode": "canonical-bytes", "provenance": "authored", "requirements": [ - "X402-7f4ee54a73" + "X402-76654742e7" ], "role": "both", "spec": { "doc": "x402/specs/schemes/batch-settlement/scheme_batch_settlement_svm.md", - "quote": "`claims[]` MUST contain between one and four entries so the instruction pairs fit in a legacy Solana transaction without address lookup tables.", + "quote": "`claims[]` MUST contain at least one entry and at most `extra.maxClaimChannels` entries, or four when the facilitator advertises no `maxClaimChannels`, so the instruction pairs fit in one transaction without address lookup tables.", "section": "4.5 Facilitator Interface" }, "tier": "offline" }, { "bugType": "wire", - "description": "Five claims exceed the four entries one legacy transaction can carry.", + "description": "Eighteen claims, the version-1 capacity (extra.maxClaimChannels 18): the payload parses. More than four is no longer a wire error; a facilitator that builds version 0 rejects it against its own capacity.", + "expect": { + "exactBytes": { + "base64Url": "eyJjbGFpbXMiOlt7ImNoYW5uZWxDb25maWciOnsib3BlblNsb3QiOjM0MTAwMDAwMCwicGF5ZXIiOiJHbWFEcnBwQkM3UDVBUktWOGczZGppd1A4OXZ6MWpMSzIzVjJHQmp1QUVHQiIsInBheWVyQXV0aG9yaXplciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicmVjZWl2ZXIiOiJDWGhyRlpKTEtxanptUDNzallMY0Y0ZFRlWFdLQ3k5ZTJTWFhaMllvNk1QWSIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwic2FsdCI6IjEwMCIsInRva2VuIjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwiY2hhbm5lbElkIjoiQnI0d1VpOVRwTlRCN3dMOUJYb0NxS0FhSGhMVkFpaWlhV2J4dmUyb2c1RE0iLCJ2b3VjaGVyIjp7ImNoYW5uZWxJZCI6IkJyNHdVaTlUcE5UQjd3TDlCWG9DcUtBYUhoTFZBaWlpYVdieHZlMm9nNURNIiwiZXhwaXJlc0F0IjowLCJtYXhDbGFpbWFibGVBbW91bnQiOiIxMDAwIiwic2lnbmF0dXJlIjoiNXdlYmlENERiaEpwakdqVG9CTFhQb25DQ2NEcDVqSzZLdkphRzZ5OUxaajhSRnN1eFVnZmVINUZMVUtmWnd4Q2toYzJxcHhuOWQ5bm95Tnhwd2U1dmhXbyJ9fSx7ImNoYW5uZWxDb25maWciOnsib3BlblNsb3QiOjM0MTAwMDAwMCwicGF5ZXIiOiJHbWFEcnBwQkM3UDVBUktWOGczZGppd1A4OXZ6MWpMSzIzVjJHQmp1QUVHQiIsInBheWVyQXV0aG9yaXplciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicmVjZWl2ZXIiOiJDWGhyRlpKTEtxanptUDNzallMY0Y0ZFRlWFdLQ3k5ZTJTWFhaMllvNk1QWSIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwic2FsdCI6IjEwMSIsInRva2VuIjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwiY2hhbm5lbElkIjoiOTZ3aU1wcWRMUXZCSzJ2VEh3MkFMbnpLam9YZUhQZTlVSEw4R1BNNlZCSDMiLCJ2b3VjaGVyIjp7ImNoYW5uZWxJZCI6Ijk2d2lNcHFkTFF2QksydlRIdzJBTG56S2pvWGVIUGU5VUhMOEdQTTZWQkgzIiwiZXhwaXJlc0F0IjowLCJtYXhDbGFpbWFibGVBbW91bnQiOiIxMDAwIiwic2lnbmF0dXJlIjoiMjNlZDd1MXNXVkw2N0RnUDJYUzVTNmE4UU5TTkROang0Nk4zV3JEalFjWU1rZFRLd0p4U292akx2RVNSRXdpbnFhWDdxRkd3WmlINEtoWDh3aHZLZHlybSJ9fSx7ImNoYW5uZWxDb25maWciOnsib3BlblNsb3QiOjM0MTAwMDAwMCwicGF5ZXIiOiJHbWFEcnBwQkM3UDVBUktWOGczZGppd1A4OXZ6MWpMSzIzVjJHQmp1QUVHQiIsInBheWVyQXV0aG9yaXplciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicmVjZWl2ZXIiOiJDWGhyRlpKTEtxanptUDNzallMY0Y0ZFRlWFdLQ3k5ZTJTWFhaMllvNk1QWSIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwic2FsdCI6IjEwMiIsInRva2VuIjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwiY2hhbm5lbElkIjoiOTE4dWpMeGl5cVpBMldteHpudnRIc0VrMzFuRG1QcjZHczhuQTczb1kyeW4iLCJ2b3VjaGVyIjp7ImNoYW5uZWxJZCI6IjkxOHVqTHhpeXFaQTJXbXh6bnZ0SHNFazMxbkRtUHI2R3M4bkE3M29ZMnluIiwiZXhwaXJlc0F0IjowLCJtYXhDbGFpbWFibGVBbW91bnQiOiIxMDAwIiwic2lnbmF0dXJlIjoiNU0xRXdUNlNzaHlVS1JodjZxS2ZTams3cWpqc3c3cnFaMXExYmpmcEhuZnFBVW02UFVkenhNVnNwRFFYMXB0dlF3amR3QjR4ZDZ4ZHBLSjlRQzhna3NkSiJ9fSx7ImNoYW5uZWxDb25maWciOnsib3BlblNsb3QiOjM0MTAwMDAwMCwicGF5ZXIiOiJHbWFEcnBwQkM3UDVBUktWOGczZGppd1A4OXZ6MWpMSzIzVjJHQmp1QUVHQiIsInBheWVyQXV0aG9yaXplciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicmVjZWl2ZXIiOiJDWGhyRlpKTEtxanptUDNzallMY0Y0ZFRlWFdLQ3k5ZTJTWFhaMllvNk1QWSIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwic2FsdCI6IjEwMyIsInRva2VuIjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwiY2hhbm5lbElkIjoiMjdQMlZNNXN3U1NSR0s4M0FxTWhHTmc5WmZUTlZYdHg3NE1rS2V2VjhQcEgiLCJ2b3VjaGVyIjp7ImNoYW5uZWxJZCI6IjI3UDJWTTVzd1NTUkdLODNBcU1oR05nOVpmVE5WWHR4NzRNa0tldlY4UHBIIiwiZXhwaXJlc0F0IjowLCJtYXhDbGFpbWFibGVBbW91bnQiOiIxMDAwIiwic2lnbmF0dXJlIjoiMnl5anFhSHNkaUJLS0h2alI4dmRxcUhlUTM2QUZydXVHZHNhem1EQk1FYnRQaVhqYkRxQTNxNnM5Rnl1Z2ViV3B6TVdSZXNpTFBjTmZrVUJYMm9uVmR5USJ9fSx7ImNoYW5uZWxDb25maWciOnsib3BlblNsb3QiOjM0MTAwMDAwMCwicGF5ZXIiOiJHbWFEcnBwQkM3UDVBUktWOGczZGppd1A4OXZ6MWpMSzIzVjJHQmp1QUVHQiIsInBheWVyQXV0aG9yaXplciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicmVjZWl2ZXIiOiJDWGhyRlpKTEtxanptUDNzallMY0Y0ZFRlWFdLQ3k5ZTJTWFhaMllvNk1QWSIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwic2FsdCI6IjEwNCIsInRva2VuIjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwiY2hhbm5lbElkIjoiQkp0a3FZczljV2Z1eVAxeDlWR3NkVTJibWpRWVRyMnNEelBFMVdxNnZGWHMiLCJ2b3VjaGVyIjp7ImNoYW5uZWxJZCI6IkJKdGtxWXM5Y1dmdXlQMXg5VkdzZFUyYm1qUVlUcjJzRHpQRTFXcTZ2RlhzIiwiZXhwaXJlc0F0IjowLCJtYXhDbGFpbWFibGVBbW91bnQiOiIxMDAwIiwic2lnbmF0dXJlIjoiNTNKdmJkQ3RCVW1EZ1Z3ZFBEYnZ3eVdYTXRYYVpCdlhSN3VVc1FxOEVQTFl0bUI4SEZTYWR0N0xkaHFKMm9Hd1M0aUNjWW0xV2RDQnUzUFRVNDdZRFI0aCJ9fSx7ImNoYW5uZWxDb25maWciOnsib3BlblNsb3QiOjM0MTAwMDAwMCwicGF5ZXIiOiJHbWFEcnBwQkM3UDVBUktWOGczZGppd1A4OXZ6MWpMSzIzVjJHQmp1QUVHQiIsInBheWVyQXV0aG9yaXplciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicmVjZWl2ZXIiOiJDWGhyRlpKTEtxanptUDNzallMY0Y0ZFRlWFdLQ3k5ZTJTWFhaMllvNk1QWSIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwic2FsdCI6IjEwNSIsInRva2VuIjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwiY2hhbm5lbElkIjoiNEFOTlZZeExmak52amdSNmtxRDdXN3dhQWZOR1pRM2l6QXFyUHVvbnZzd04iLCJ2b3VjaGVyIjp7ImNoYW5uZWxJZCI6IjRBTk5WWXhMZmpOdmpnUjZrcUQ3Vzd3YUFmTkdaUTNpekFxclB1b252c3dOIiwiZXhwaXJlc0F0IjowLCJtYXhDbGFpbWFibGVBbW91bnQiOiIxMDAwIiwic2lnbmF0dXJlIjoiNU0zSGtHdGNZaHVnY0Vod2d1RW4za011azNvUDF0Q2VMMWlVS1hjRmpyNVYyRTVlMlFySzQ4cno3ZUVmWks2NnlvNDRnQ0dFRVBQQ0MxVzNWUnprcUdLOSJ9fSx7ImNoYW5uZWxDb25maWciOnsib3BlblNsb3QiOjM0MTAwMDAwMCwicGF5ZXIiOiJHbWFEcnBwQkM3UDVBUktWOGczZGppd1A4OXZ6MWpMSzIzVjJHQmp1QUVHQiIsInBheWVyQXV0aG9yaXplciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicmVjZWl2ZXIiOiJDWGhyRlpKTEtxanptUDNzallMY0Y0ZFRlWFdLQ3k5ZTJTWFhaMllvNk1QWSIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwic2FsdCI6IjEwNiIsInRva2VuIjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwiY2hhbm5lbElkIjoiNHE5akVucUFNcDhodkJpc3VYaDlIdWl0V0JIUk5LdGhIbWRKMWJoQnk3cE4iLCJ2b3VjaGVyIjp7ImNoYW5uZWxJZCI6IjRxOWpFbnFBTXA4aHZCaXN1WGg5SHVpdFdCSFJOS3RoSG1kSjFiaEJ5N3BOIiwiZXhwaXJlc0F0IjowLCJtYXhDbGFpbWFibGVBbW91bnQiOiIxMDAwIiwic2lnbmF0dXJlIjoiMkdpUG5ZR1JrOGZqcVJmNFRucGlYVTN4VjFIeXJTZnlLZ1EySlhKVktLM1I2OGFodmRmVTExRnJjYzVITTJTZVNMUHJIRHJaZG5hWEw5ZXQxaHdIdlF0dCJ9fSx7ImNoYW5uZWxDb25maWciOnsib3BlblNsb3QiOjM0MTAwMDAwMCwicGF5ZXIiOiJHbWFEcnBwQkM3UDVBUktWOGczZGppd1A4OXZ6MWpMSzIzVjJHQmp1QUVHQiIsInBheWVyQXV0aG9yaXplciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicmVjZWl2ZXIiOiJDWGhyRlpKTEtxanptUDNzallMY0Y0ZFRlWFdLQ3k5ZTJTWFhaMllvNk1QWSIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwic2FsdCI6IjEwNyIsInRva2VuIjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwiY2hhbm5lbElkIjoiOEY1eHd6cktjZ3JNS0xhVFlHY0tNWmRjdURoaXE3UHhTR25IdVd0Nk1kOUYiLCJ2b3VjaGVyIjp7ImNoYW5uZWxJZCI6IjhGNXh3enJLY2dyTUtMYVRZR2NLTVpkY3VEaGlxN1B4U0duSHVXdDZNZDlGIiwiZXhwaXJlc0F0IjowLCJtYXhDbGFpbWFibGVBbW91bnQiOiIxMDAwIiwic2lnbmF0dXJlIjoiMk5IcGN0NkVZdFBMY1g3cHZWOUNHNmFCM3RXdVc5a3BuOUpEcVBraUhaWVp2ZlpVYVVDbXF4V3pZU25SZzVaTkNUVXpTc1hjdm5STUR5TGFvS1JVV2plNCJ9fSx7ImNoYW5uZWxDb25maWciOnsib3BlblNsb3QiOjM0MTAwMDAwMCwicGF5ZXIiOiJHbWFEcnBwQkM3UDVBUktWOGczZGppd1A4OXZ6MWpMSzIzVjJHQmp1QUVHQiIsInBheWVyQXV0aG9yaXplciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicmVjZWl2ZXIiOiJDWGhyRlpKTEtxanptUDNzallMY0Y0ZFRlWFdLQ3k5ZTJTWFhaMllvNk1QWSIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwic2FsdCI6IjEwOCIsInRva2VuIjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwiY2hhbm5lbElkIjoiR1VOc0twYzV5YkI3dGo3U1VGOFVhc3VCeUhTN1N4czNhcHR0NWVSaWNBVEMiLCJ2b3VjaGVyIjp7ImNoYW5uZWxJZCI6IkdVTnNLcGM1eWJCN3RqN1NVRjhVYXN1QnlIUzdTeHMzYXB0dDVlUmljQVRDIiwiZXhwaXJlc0F0IjowLCJtYXhDbGFpbWFibGVBbW91bnQiOiIxMDAwIiwic2lnbmF0dXJlIjoiMmFGMVJkYTJoOGVjdnBqNkRnOTlyQlhkM1oxVEFLdGtvcThMUG53Unc0VU1iVFl1cWhWSGpVbjZoclBibnV6UVRRaVVqNFZ2RXdUdTgxM2V1N2R5ekNoMyJ9fSx7ImNoYW5uZWxDb25maWciOnsib3BlblNsb3QiOjM0MTAwMDAwMCwicGF5ZXIiOiJHbWFEcnBwQkM3UDVBUktWOGczZGppd1A4OXZ6MWpMSzIzVjJHQmp1QUVHQiIsInBheWVyQXV0aG9yaXplciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicmVjZWl2ZXIiOiJDWGhyRlpKTEtxanptUDNzallMY0Y0ZFRlWFdLQ3k5ZTJTWFhaMllvNk1QWSIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwic2FsdCI6IjEwOSIsInRva2VuIjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwiY2hhbm5lbElkIjoiRm13NzVESms4Zmk4aTZ5amYzSEE5b3l4ano1UUw2Z3M4U1JYWVY0aGt4UTMiLCJ2b3VjaGVyIjp7ImNoYW5uZWxJZCI6IkZtdzc1REprOGZpOGk2eWpmM0hBOW95eGp6NVFMNmdzOFNSWFlWNGhreFEzIiwiZXhwaXJlc0F0IjowLCJtYXhDbGFpbWFibGVBbW91bnQiOiIxMDAwIiwic2lnbmF0dXJlIjoiNUxFSlR6ZXNVdE1ndmFZMjVLU1VvMVRBUVBRZWh0N1JCcHFZUnlFYzF2UmlqSER6djJQMnRDWUFYS3FLVlU3a2U4Ulp1TW14Y3BhakxBWFhjcVdXWkNxZSJ9fSx7ImNoYW5uZWxDb25maWciOnsib3BlblNsb3QiOjM0MTAwMDAwMCwicGF5ZXIiOiJHbWFEcnBwQkM3UDVBUktWOGczZGppd1A4OXZ6MWpMSzIzVjJHQmp1QUVHQiIsInBheWVyQXV0aG9yaXplciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicmVjZWl2ZXIiOiJDWGhyRlpKTEtxanptUDNzallMY0Y0ZFRlWFdLQ3k5ZTJTWFhaMllvNk1QWSIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwic2FsdCI6IjExMCIsInRva2VuIjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwiY2hhbm5lbElkIjoiQnBkNHN5dmc1QlNCeXQ3eFhiTlZTenRDcGd3SHNDRHJ6U201NHBtNDlWalEiLCJ2b3VjaGVyIjp7ImNoYW5uZWxJZCI6IkJwZDRzeXZnNUJTQnl0N3hYYk5WU3p0Q3Bnd0hzQ0RyelNtNTRwbTQ5VmpRIiwiZXhwaXJlc0F0IjowLCJtYXhDbGFpbWFibGVBbW91bnQiOiIxMDAwIiwic2lnbmF0dXJlIjoiNWp1NVJoQXp2S1k5djF0dWI1dFVSNWFCY0JSSmppb3lmZW9KcVhTbzZXRWQxeXdDYzFudzd0UHBkQWRKQ2pjNEs0czlYRlpQSDlQNlUyRkNKSDhXdURDNyJ9fSx7ImNoYW5uZWxDb25maWciOnsib3BlblNsb3QiOjM0MTAwMDAwMCwicGF5ZXIiOiJHbWFEcnBwQkM3UDVBUktWOGczZGppd1A4OXZ6MWpMSzIzVjJHQmp1QUVHQiIsInBheWVyQXV0aG9yaXplciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicmVjZWl2ZXIiOiJDWGhyRlpKTEtxanptUDNzallMY0Y0ZFRlWFdLQ3k5ZTJTWFhaMllvNk1QWSIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwic2FsdCI6IjExMSIsInRva2VuIjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwiY2hhbm5lbElkIjoiRU1KRlB4U2tDSzhRenR2S0FqUG5pTmJnZXZBdTNUY3g4V3BxRGh3M3pIeEUiLCJ2b3VjaGVyIjp7ImNoYW5uZWxJZCI6IkVNSkZQeFNrQ0s4UXp0dktBalBuaU5iZ2V2QXUzVGN4OFdwcURodzN6SHhFIiwiZXhwaXJlc0F0IjowLCJtYXhDbGFpbWFibGVBbW91bnQiOiIxMDAwIiwic2lnbmF0dXJlIjoiNTdyN281U1J4dExzSnI5d01qOHdFaEI3NGluVmFKRndWQXFFcUFxWTZxcXF0RlptcFdwclVFM0NkQkJqaUNaeW02WmI2ampzWkI0aUw1dXlOdFNIb2Q5VSJ9fSx7ImNoYW5uZWxDb25maWciOnsib3BlblNsb3QiOjM0MTAwMDAwMCwicGF5ZXIiOiJHbWFEcnBwQkM3UDVBUktWOGczZGppd1A4OXZ6MWpMSzIzVjJHQmp1QUVHQiIsInBheWVyQXV0aG9yaXplciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicmVjZWl2ZXIiOiJDWGhyRlpKTEtxanptUDNzallMY0Y0ZFRlWFdLQ3k5ZTJTWFhaMllvNk1QWSIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwic2FsdCI6IjExMiIsInRva2VuIjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwiY2hhbm5lbElkIjoiOVpaTDJOU0Nhb1FSbUtxQkpqdEM1QXlodW9uZ0FMUmNwaUtpOG9QNWZaM3QiLCJ2b3VjaGVyIjp7ImNoYW5uZWxJZCI6IjlaWkwyTlNDYW9RUm1LcUJKanRDNUF5aHVvbmdBTFJjcGlLaThvUDVmWjN0IiwiZXhwaXJlc0F0IjowLCJtYXhDbGFpbWFibGVBbW91bnQiOiIxMDAwIiwic2lnbmF0dXJlIjoiM0RyM2Y0akZhTVJRcjhDVzUyeWpOd3NVTVlla29hUlhzV2Q5M3JtdHNnbzVRN2tHRktzRXQ1YkxLRGRqdzUzTFM5RzJTZUN2VnRiSktueUZkR3hnSGU0SCJ9fSx7ImNoYW5uZWxDb25maWciOnsib3BlblNsb3QiOjM0MTAwMDAwMCwicGF5ZXIiOiJHbWFEcnBwQkM3UDVBUktWOGczZGppd1A4OXZ6MWpMSzIzVjJHQmp1QUVHQiIsInBheWVyQXV0aG9yaXplciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicmVjZWl2ZXIiOiJDWGhyRlpKTEtxanptUDNzallMY0Y0ZFRlWFdLQ3k5ZTJTWFhaMllvNk1QWSIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwic2FsdCI6IjExMyIsInRva2VuIjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwiY2hhbm5lbElkIjoiM2JxcVI0V252dFRNSnhiQ2hLWUpIVGt0SHlha3p5VXZZWmJERXl0VDh1bVYiLCJ2b3VjaGVyIjp7ImNoYW5uZWxJZCI6IjNicXFSNFdudnRUTUp4YkNoS1lKSFRrdEh5YWt6eVV2WVpiREV5dFQ4dW1WIiwiZXhwaXJlc0F0IjowLCJtYXhDbGFpbWFibGVBbW91bnQiOiIxMDAwIiwic2lnbmF0dXJlIjoiM0dVTFltRXFiQkVYVk5WUHZoVUFuS0c5TUhvbjU1a3RrQkFHQ2l4VVNMd0tkb0tQMUNNRFJ0V2lDeVhOOTYzTEh6bUJRNFY0bnhVV2ZKR1BRZ1lvcThxaSJ9fSx7ImNoYW5uZWxDb25maWciOnsib3BlblNsb3QiOjM0MTAwMDAwMCwicGF5ZXIiOiJHbWFEcnBwQkM3UDVBUktWOGczZGppd1A4OXZ6MWpMSzIzVjJHQmp1QUVHQiIsInBheWVyQXV0aG9yaXplciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicmVjZWl2ZXIiOiJDWGhyRlpKTEtxanptUDNzallMY0Y0ZFRlWFdLQ3k5ZTJTWFhaMllvNk1QWSIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwic2FsdCI6IjExNCIsInRva2VuIjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwiY2hhbm5lbElkIjoiQXpBQldodkpmUnBadTljUGZvQUdrZlNnQTduNkNMTjdMMVRzejRrU3NQdEEiLCJ2b3VjaGVyIjp7ImNoYW5uZWxJZCI6IkF6QUJXaHZKZlJwWnU5Y1Bmb0FHa2ZTZ0E3bjZDTE43TDFUc3o0a1NzUHRBIiwiZXhwaXJlc0F0IjowLCJtYXhDbGFpbWFibGVBbW91bnQiOiIxMDAwIiwic2lnbmF0dXJlIjoiMkNXMmlQb2VKeDNFZGVFZ0o2OGJSRWhLaFZSZkdjeXJic1E5TFdXb0tNNHNTTFNGMkdtM3k3QksyQ2FHUnk5aFg1OFFEN1JkaTFwVU05WnY2c1gyNHZRUiJ9fSx7ImNoYW5uZWxDb25maWciOnsib3BlblNsb3QiOjM0MTAwMDAwMCwicGF5ZXIiOiJHbWFEcnBwQkM3UDVBUktWOGczZGppd1A4OXZ6MWpMSzIzVjJHQmp1QUVHQiIsInBheWVyQXV0aG9yaXplciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicmVjZWl2ZXIiOiJDWGhyRlpKTEtxanptUDNzallMY0Y0ZFRlWFdLQ3k5ZTJTWFhaMllvNk1QWSIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwic2FsdCI6IjExNSIsInRva2VuIjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwiY2hhbm5lbElkIjoiNkd3eFhWUk5UUkcxck1udkNzNEFneTVUdzI0QWc3Sm5QZ1pvNXpEUDZhY3YiLCJ2b3VjaGVyIjp7ImNoYW5uZWxJZCI6IjZHd3hYVlJOVFJHMXJNbnZDczRBZ3k1VHcyNEFnN0puUGdabzV6RFA2YWN2IiwiZXhwaXJlc0F0IjowLCJtYXhDbGFpbWFibGVBbW91bnQiOiIxMDAwIiwic2lnbmF0dXJlIjoiMzdITndSUlY2Mm1uVkJnMVgzRjdUNHB1bWoxQjc0aTVUejhZelhqdndFeTZvVTZjY3hpYXd5U0ROaThFeno5Y0NUeXlaSGtXSjdKNGJlYVhoQzZKS1lidCJ9fSx7ImNoYW5uZWxDb25maWciOnsib3BlblNsb3QiOjM0MTAwMDAwMCwicGF5ZXIiOiJHbWFEcnBwQkM3UDVBUktWOGczZGppd1A4OXZ6MWpMSzIzVjJHQmp1QUVHQiIsInBheWVyQXV0aG9yaXplciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicmVjZWl2ZXIiOiJDWGhyRlpKTEtxanptUDNzallMY0Y0ZFRlWFdLQ3k5ZTJTWFhaMllvNk1QWSIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwic2FsdCI6IjExNiIsInRva2VuIjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwiY2hhbm5lbElkIjoiQmhnWGZQWXZOdE1aRmhyS0YzTXBhdFhqVk1NOUttcHBaZ0J1Z3lmVldzbVkiLCJ2b3VjaGVyIjp7ImNoYW5uZWxJZCI6IkJoZ1hmUFl2TnRNWkZocktGM01wYXRYalZNTTlLbXBwWmdCdWd5ZlZXc21ZIiwiZXhwaXJlc0F0IjowLCJtYXhDbGFpbWFibGVBbW91bnQiOiIxMDAwIiwic2lnbmF0dXJlIjoiNUN6V3AyTWZZb2pUODNUdTE5dmRwWTZNdVRGVzlnNVZwaGEyNU44dTFSdzU2MXhBRGVhb1JjRUs2ZmV2SGJvMzV5YkFDbjNpVDl4WGY3eHFSdWlLS3dTdyJ9fSx7ImNoYW5uZWxDb25maWciOnsib3BlblNsb3QiOjM0MTAwMDAwMCwicGF5ZXIiOiJHbWFEcnBwQkM3UDVBUktWOGczZGppd1A4OXZ6MWpMSzIzVjJHQmp1QUVHQiIsInBheWVyQXV0aG9yaXplciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicmVjZWl2ZXIiOiJDWGhyRlpKTEtxanptUDNzallMY0Y0ZFRlWFdLQ3k5ZTJTWFhaMllvNk1QWSIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwic2FsdCI6IjExNyIsInRva2VuIjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwiY2hhbm5lbElkIjoiRjJjVGRqSGM3SkFmQ29nSnp4aXoyWWlUc3Z0RzRrNTVxdkxld0hSUDZ3dlciLCJ2b3VjaGVyIjp7ImNoYW5uZWxJZCI6IkYyY1RkakhjN0pBZkNvZ0p6eGl6MllpVHN2dEc0azU1cXZMZXdIUlA2d3ZXIiwiZXhwaXJlc0F0IjowLCJtYXhDbGFpbWFibGVBbW91bnQiOiIxMDAwIiwic2lnbmF0dXJlIjoiMktwTUtKNGRvTkpydFZra1JteEZUcm43QlVHY1JYOGEyRjVvU1g1cE4yR2ZVVVdXOVhOdWVVZHljWU1MTW9pOXRZb3BuMWlxblFmSjc3b1F6Q3FQc3F1TSJ9fV0sInR5cGUiOiJjbGFpbSJ9", + "canonicalJson": "{\"claims\":[{\"channelConfig\":{\"openSlot\":341000000,\"payer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"payerAuthorizer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"receiver\":\"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY\",\"receiverAuthorizer\":\"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os\",\"salt\":\"100\",\"token\":\"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU\",\"withdrawDelay\":3600},\"channelId\":\"Br4wUi9TpNTB7wL9BXoCqKAaHhLVAiiiaWbxve2og5DM\",\"voucher\":{\"channelId\":\"Br4wUi9TpNTB7wL9BXoCqKAaHhLVAiiiaWbxve2og5DM\",\"expiresAt\":0,\"maxClaimableAmount\":\"1000\",\"signature\":\"5webiD4DbhJpjGjToBLXPonCCcDp5jK6KvJaG6y9LZj8RFsuxUgfeH5FLUKfZwxCkhc2qpxn9d9noyNxpwe5vhWo\"}},{\"channelConfig\":{\"openSlot\":341000000,\"payer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"payerAuthorizer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"receiver\":\"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY\",\"receiverAuthorizer\":\"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os\",\"salt\":\"101\",\"token\":\"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU\",\"withdrawDelay\":3600},\"channelId\":\"96wiMpqdLQvBK2vTHw2ALnzKjoXeHPe9UHL8GPM6VBH3\",\"voucher\":{\"channelId\":\"96wiMpqdLQvBK2vTHw2ALnzKjoXeHPe9UHL8GPM6VBH3\",\"expiresAt\":0,\"maxClaimableAmount\":\"1000\",\"signature\":\"23ed7u1sWVL67DgP2XS5S6a8QNSNDNjx46N3WrDjQcYMkdTKwJxSovjLvESREwinqaX7qFGwZiH4KhX8whvKdyrm\"}},{\"channelConfig\":{\"openSlot\":341000000,\"payer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"payerAuthorizer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"receiver\":\"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY\",\"receiverAuthorizer\":\"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os\",\"salt\":\"102\",\"token\":\"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU\",\"withdrawDelay\":3600},\"channelId\":\"918ujLxiyqZA2WmxznvtHsEk31nDmPr6Gs8nA73oY2yn\",\"voucher\":{\"channelId\":\"918ujLxiyqZA2WmxznvtHsEk31nDmPr6Gs8nA73oY2yn\",\"expiresAt\":0,\"maxClaimableAmount\":\"1000\",\"signature\":\"5M1EwT6SshyUKRhv6qKfSjk7qjjsw7rqZ1q1bjfpHnfqAUm6PUdzxMVspDQX1ptvQwjdwB4xd6xdpKJ9QC8gksdJ\"}},{\"channelConfig\":{\"openSlot\":341000000,\"payer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"payerAuthorizer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"receiver\":\"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY\",\"receiverAuthorizer\":\"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os\",\"salt\":\"103\",\"token\":\"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU\",\"withdrawDelay\":3600},\"channelId\":\"27P2VM5swSSRGK83AqMhGNg9ZfTNVXtx74MkKevV8PpH\",\"voucher\":{\"channelId\":\"27P2VM5swSSRGK83AqMhGNg9ZfTNVXtx74MkKevV8PpH\",\"expiresAt\":0,\"maxClaimableAmount\":\"1000\",\"signature\":\"2yyjqaHsdiBKKHvjR8vdqqHeQ36AFruuGdsazmDBMEbtPiXjbDqA3q6s9FyugebWpzMWResiLPcNfkUBX2onVdyQ\"}},{\"channelConfig\":{\"openSlot\":341000000,\"payer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"payerAuthorizer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"receiver\":\"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY\",\"receiverAuthorizer\":\"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os\",\"salt\":\"104\",\"token\":\"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU\",\"withdrawDelay\":3600},\"channelId\":\"BJtkqYs9cWfuyP1x9VGsdU2bmjQYTr2sDzPE1Wq6vFXs\",\"voucher\":{\"channelId\":\"BJtkqYs9cWfuyP1x9VGsdU2bmjQYTr2sDzPE1Wq6vFXs\",\"expiresAt\":0,\"maxClaimableAmount\":\"1000\",\"signature\":\"53JvbdCtBUmDgVwdPDbvwyWXMtXaZBvXR7uUsQq8EPLYtmB8HFSadt7LdhqJ2oGwS4iCcYm1WdCBu3PTU47YDR4h\"}},{\"channelConfig\":{\"openSlot\":341000000,\"payer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"payerAuthorizer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"receiver\":\"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY\",\"receiverAuthorizer\":\"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os\",\"salt\":\"105\",\"token\":\"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU\",\"withdrawDelay\":3600},\"channelId\":\"4ANNVYxLfjNvjgR6kqD7W7waAfNGZQ3izAqrPuonvswN\",\"voucher\":{\"channelId\":\"4ANNVYxLfjNvjgR6kqD7W7waAfNGZQ3izAqrPuonvswN\",\"expiresAt\":0,\"maxClaimableAmount\":\"1000\",\"signature\":\"5M3HkGtcYhugcEhwguEn3kMuk3oP1tCeL1iUKXcFjr5V2E5e2QrK48rz7eEfZK66yo44gCGEEPPCC1W3VRzkqGK9\"}},{\"channelConfig\":{\"openSlot\":341000000,\"payer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"payerAuthorizer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"receiver\":\"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY\",\"receiverAuthorizer\":\"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os\",\"salt\":\"106\",\"token\":\"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU\",\"withdrawDelay\":3600},\"channelId\":\"4q9jEnqAMp8hvBisuXh9HuitWBHRNKthHmdJ1bhBy7pN\",\"voucher\":{\"channelId\":\"4q9jEnqAMp8hvBisuXh9HuitWBHRNKthHmdJ1bhBy7pN\",\"expiresAt\":0,\"maxClaimableAmount\":\"1000\",\"signature\":\"2GiPnYGRk8fjqRf4TnpiXU3xV1HyrSfyKgQ2JXJVKK3R68ahvdfU11Frcc5HM2SeSLPrHDrZdnaXL9et1hwHvQtt\"}},{\"channelConfig\":{\"openSlot\":341000000,\"payer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"payerAuthorizer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"receiver\":\"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY\",\"receiverAuthorizer\":\"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os\",\"salt\":\"107\",\"token\":\"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU\",\"withdrawDelay\":3600},\"channelId\":\"8F5xwzrKcgrMKLaTYGcKMZdcuDhiq7PxSGnHuWt6Md9F\",\"voucher\":{\"channelId\":\"8F5xwzrKcgrMKLaTYGcKMZdcuDhiq7PxSGnHuWt6Md9F\",\"expiresAt\":0,\"maxClaimableAmount\":\"1000\",\"signature\":\"2NHpct6EYtPLcX7pvV9CG6aB3tWuW9kpn9JDqPkiHZYZvfZUaUCmqxWzYSnRg5ZNCTUzSsXcvnRMDyLaoKRUWje4\"}},{\"channelConfig\":{\"openSlot\":341000000,\"payer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"payerAuthorizer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"receiver\":\"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY\",\"receiverAuthorizer\":\"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os\",\"salt\":\"108\",\"token\":\"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU\",\"withdrawDelay\":3600},\"channelId\":\"GUNsKpc5ybB7tj7SUF8UasuByHS7Sxs3aptt5eRicATC\",\"voucher\":{\"channelId\":\"GUNsKpc5ybB7tj7SUF8UasuByHS7Sxs3aptt5eRicATC\",\"expiresAt\":0,\"maxClaimableAmount\":\"1000\",\"signature\":\"2aF1Rda2h8ecvpj6Dg99rBXd3Z1TAKtkoq8LPnwRw4UMbTYuqhVHjUn6hrPbnuzQTQiUj4VvEwTu813eu7dyzCh3\"}},{\"channelConfig\":{\"openSlot\":341000000,\"payer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"payerAuthorizer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"receiver\":\"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY\",\"receiverAuthorizer\":\"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os\",\"salt\":\"109\",\"token\":\"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU\",\"withdrawDelay\":3600},\"channelId\":\"Fmw75DJk8fi8i6yjf3HA9oyxjz5QL6gs8SRXYV4hkxQ3\",\"voucher\":{\"channelId\":\"Fmw75DJk8fi8i6yjf3HA9oyxjz5QL6gs8SRXYV4hkxQ3\",\"expiresAt\":0,\"maxClaimableAmount\":\"1000\",\"signature\":\"5LEJTzesUtMgvaY25KSUo1TAQPQeht7RBpqYRyEc1vRijHDzv2P2tCYAXKqKVU7ke8RZuMmxcpajLAXXcqWWZCqe\"}},{\"channelConfig\":{\"openSlot\":341000000,\"payer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"payerAuthorizer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"receiver\":\"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY\",\"receiverAuthorizer\":\"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os\",\"salt\":\"110\",\"token\":\"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU\",\"withdrawDelay\":3600},\"channelId\":\"Bpd4syvg5BSByt7xXbNVSztCpgwHsCDrzSm54pm49VjQ\",\"voucher\":{\"channelId\":\"Bpd4syvg5BSByt7xXbNVSztCpgwHsCDrzSm54pm49VjQ\",\"expiresAt\":0,\"maxClaimableAmount\":\"1000\",\"signature\":\"5ju5RhAzvKY9v1tub5tUR5aBcBRJjioyfeoJqXSo6WEd1ywCc1nw7tPpdAdJCjc4K4s9XFZPH9P6U2FCJH8WuDC7\"}},{\"channelConfig\":{\"openSlot\":341000000,\"payer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"payerAuthorizer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"receiver\":\"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY\",\"receiverAuthorizer\":\"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os\",\"salt\":\"111\",\"token\":\"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU\",\"withdrawDelay\":3600},\"channelId\":\"EMJFPxSkCK8QztvKAjPniNbgevAu3Tcx8WpqDhw3zHxE\",\"voucher\":{\"channelId\":\"EMJFPxSkCK8QztvKAjPniNbgevAu3Tcx8WpqDhw3zHxE\",\"expiresAt\":0,\"maxClaimableAmount\":\"1000\",\"signature\":\"57r7o5SRxtLsJr9wMj8wEhB74inVaJFwVAqEqAqY6qqqtFZmpWprUE3CdBBjiCZym6Zb6jjsZB4iL5uyNtSHod9U\"}},{\"channelConfig\":{\"openSlot\":341000000,\"payer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"payerAuthorizer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"receiver\":\"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY\",\"receiverAuthorizer\":\"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os\",\"salt\":\"112\",\"token\":\"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU\",\"withdrawDelay\":3600},\"channelId\":\"9ZZL2NSCaoQRmKqBJjtC5AyhuongALRcpiKi8oP5fZ3t\",\"voucher\":{\"channelId\":\"9ZZL2NSCaoQRmKqBJjtC5AyhuongALRcpiKi8oP5fZ3t\",\"expiresAt\":0,\"maxClaimableAmount\":\"1000\",\"signature\":\"3Dr3f4jFaMRQr8CW52yjNwsUMYekoaRXsWd93rmtsgo5Q7kGFKsEt5bLKDdjw53LS9G2SeCvVtbJKnyFdGxgHe4H\"}},{\"channelConfig\":{\"openSlot\":341000000,\"payer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"payerAuthorizer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"receiver\":\"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY\",\"receiverAuthorizer\":\"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os\",\"salt\":\"113\",\"token\":\"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU\",\"withdrawDelay\":3600},\"channelId\":\"3bqqR4WnvtTMJxbChKYJHTktHyakzyUvYZbDEytT8umV\",\"voucher\":{\"channelId\":\"3bqqR4WnvtTMJxbChKYJHTktHyakzyUvYZbDEytT8umV\",\"expiresAt\":0,\"maxClaimableAmount\":\"1000\",\"signature\":\"3GULYmEqbBEXVNVPvhUAnKG9MHon55ktkBAGCixUSLwKdoKP1CMDRtWiCyXN963LHzmBQ4V4nxUWfJGPQgYoq8qi\"}},{\"channelConfig\":{\"openSlot\":341000000,\"payer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"payerAuthorizer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"receiver\":\"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY\",\"receiverAuthorizer\":\"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os\",\"salt\":\"114\",\"token\":\"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU\",\"withdrawDelay\":3600},\"channelId\":\"AzABWhvJfRpZu9cPfoAGkfSgA7n6CLN7L1Tsz4kSsPtA\",\"voucher\":{\"channelId\":\"AzABWhvJfRpZu9cPfoAGkfSgA7n6CLN7L1Tsz4kSsPtA\",\"expiresAt\":0,\"maxClaimableAmount\":\"1000\",\"signature\":\"2CW2iPoeJx3EdeEgJ68bREhKhVRfGcyrbsQ9LWWoKM4sSLSF2Gm3y7BK2CaGRy9hX58QD7Rdi1pUM9Zv6sX24vQR\"}},{\"channelConfig\":{\"openSlot\":341000000,\"payer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"payerAuthorizer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"receiver\":\"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY\",\"receiverAuthorizer\":\"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os\",\"salt\":\"115\",\"token\":\"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU\",\"withdrawDelay\":3600},\"channelId\":\"6GwxXVRNTRG1rMnvCs4Agy5Tw24Ag7JnPgZo5zDP6acv\",\"voucher\":{\"channelId\":\"6GwxXVRNTRG1rMnvCs4Agy5Tw24Ag7JnPgZo5zDP6acv\",\"expiresAt\":0,\"maxClaimableAmount\":\"1000\",\"signature\":\"37HNwRRV62mnVBg1X3F7T4pumj1B74i5Tz8YzXjvwEy6oU6ccxiawySDNi8Ezz9cCTyyZHkWJ7J4beaXhC6JKYbt\"}},{\"channelConfig\":{\"openSlot\":341000000,\"payer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"payerAuthorizer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"receiver\":\"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY\",\"receiverAuthorizer\":\"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os\",\"salt\":\"116\",\"token\":\"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU\",\"withdrawDelay\":3600},\"channelId\":\"BhgXfPYvNtMZFhrKF3MpatXjVMM9KmppZgBugyfVWsmY\",\"voucher\":{\"channelId\":\"BhgXfPYvNtMZFhrKF3MpatXjVMM9KmppZgBugyfVWsmY\",\"expiresAt\":0,\"maxClaimableAmount\":\"1000\",\"signature\":\"5CzWp2MfYojT83Tu19vdpY6MuTFW9g5Vpha25N8u1Rw561xADeaoRcEK6fevHbo35ybACn3iT9xXf7xqRuiKKwSw\"}},{\"channelConfig\":{\"openSlot\":341000000,\"payer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"payerAuthorizer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"receiver\":\"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY\",\"receiverAuthorizer\":\"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os\",\"salt\":\"117\",\"token\":\"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU\",\"withdrawDelay\":3600},\"channelId\":\"F2cTdjHc7JAfCogJzxiz2YiTsvtG4k55qvLewHRP6wvW\",\"voucher\":{\"channelId\":\"F2cTdjHc7JAfCogJzxiz2YiTsvtG4k55qvLewHRP6wvW\",\"expiresAt\":0,\"maxClaimableAmount\":\"1000\",\"signature\":\"2KpMKJ4doNJrtVkkRmxFTrn7BUGcRX8a2F5oSX5pN2GfUUWW9XNueUdycYMLMoi9tYopn1iqnQfJ77oQzCqPsquM\"}}],\"type\":\"claim\"}" + }, + "outcome": "accept" + }, + "id": "batch-wire-redemption-claim-eighteen-entries", + "input": { + "batchWire": { + "shape": "redemption", + "value": { + "claims": [ + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "100", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "Br4wUi9TpNTB7wL9BXoCqKAaHhLVAiiiaWbxve2og5DM", + "voucher": { + "channelId": "Br4wUi9TpNTB7wL9BXoCqKAaHhLVAiiiaWbxve2og5DM", + "expiresAt": 0, + "maxClaimableAmount": "1000", + "signature": "5webiD4DbhJpjGjToBLXPonCCcDp5jK6KvJaG6y9LZj8RFsuxUgfeH5FLUKfZwxCkhc2qpxn9d9noyNxpwe5vhWo" + } + }, + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "101", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "96wiMpqdLQvBK2vTHw2ALnzKjoXeHPe9UHL8GPM6VBH3", + "voucher": { + "channelId": "96wiMpqdLQvBK2vTHw2ALnzKjoXeHPe9UHL8GPM6VBH3", + "expiresAt": 0, + "maxClaimableAmount": "1000", + "signature": "23ed7u1sWVL67DgP2XS5S6a8QNSNDNjx46N3WrDjQcYMkdTKwJxSovjLvESREwinqaX7qFGwZiH4KhX8whvKdyrm" + } + }, + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "102", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "918ujLxiyqZA2WmxznvtHsEk31nDmPr6Gs8nA73oY2yn", + "voucher": { + "channelId": "918ujLxiyqZA2WmxznvtHsEk31nDmPr6Gs8nA73oY2yn", + "expiresAt": 0, + "maxClaimableAmount": "1000", + "signature": "5M1EwT6SshyUKRhv6qKfSjk7qjjsw7rqZ1q1bjfpHnfqAUm6PUdzxMVspDQX1ptvQwjdwB4xd6xdpKJ9QC8gksdJ" + } + }, + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "103", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "27P2VM5swSSRGK83AqMhGNg9ZfTNVXtx74MkKevV8PpH", + "voucher": { + "channelId": "27P2VM5swSSRGK83AqMhGNg9ZfTNVXtx74MkKevV8PpH", + "expiresAt": 0, + "maxClaimableAmount": "1000", + "signature": "2yyjqaHsdiBKKHvjR8vdqqHeQ36AFruuGdsazmDBMEbtPiXjbDqA3q6s9FyugebWpzMWResiLPcNfkUBX2onVdyQ" + } + }, + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "104", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "BJtkqYs9cWfuyP1x9VGsdU2bmjQYTr2sDzPE1Wq6vFXs", + "voucher": { + "channelId": "BJtkqYs9cWfuyP1x9VGsdU2bmjQYTr2sDzPE1Wq6vFXs", + "expiresAt": 0, + "maxClaimableAmount": "1000", + "signature": "53JvbdCtBUmDgVwdPDbvwyWXMtXaZBvXR7uUsQq8EPLYtmB8HFSadt7LdhqJ2oGwS4iCcYm1WdCBu3PTU47YDR4h" + } + }, + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "105", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "4ANNVYxLfjNvjgR6kqD7W7waAfNGZQ3izAqrPuonvswN", + "voucher": { + "channelId": "4ANNVYxLfjNvjgR6kqD7W7waAfNGZQ3izAqrPuonvswN", + "expiresAt": 0, + "maxClaimableAmount": "1000", + "signature": "5M3HkGtcYhugcEhwguEn3kMuk3oP1tCeL1iUKXcFjr5V2E5e2QrK48rz7eEfZK66yo44gCGEEPPCC1W3VRzkqGK9" + } + }, + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "106", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "4q9jEnqAMp8hvBisuXh9HuitWBHRNKthHmdJ1bhBy7pN", + "voucher": { + "channelId": "4q9jEnqAMp8hvBisuXh9HuitWBHRNKthHmdJ1bhBy7pN", + "expiresAt": 0, + "maxClaimableAmount": "1000", + "signature": "2GiPnYGRk8fjqRf4TnpiXU3xV1HyrSfyKgQ2JXJVKK3R68ahvdfU11Frcc5HM2SeSLPrHDrZdnaXL9et1hwHvQtt" + } + }, + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "107", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "8F5xwzrKcgrMKLaTYGcKMZdcuDhiq7PxSGnHuWt6Md9F", + "voucher": { + "channelId": "8F5xwzrKcgrMKLaTYGcKMZdcuDhiq7PxSGnHuWt6Md9F", + "expiresAt": 0, + "maxClaimableAmount": "1000", + "signature": "2NHpct6EYtPLcX7pvV9CG6aB3tWuW9kpn9JDqPkiHZYZvfZUaUCmqxWzYSnRg5ZNCTUzSsXcvnRMDyLaoKRUWje4" + } + }, + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "108", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "GUNsKpc5ybB7tj7SUF8UasuByHS7Sxs3aptt5eRicATC", + "voucher": { + "channelId": "GUNsKpc5ybB7tj7SUF8UasuByHS7Sxs3aptt5eRicATC", + "expiresAt": 0, + "maxClaimableAmount": "1000", + "signature": "2aF1Rda2h8ecvpj6Dg99rBXd3Z1TAKtkoq8LPnwRw4UMbTYuqhVHjUn6hrPbnuzQTQiUj4VvEwTu813eu7dyzCh3" + } + }, + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "109", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "Fmw75DJk8fi8i6yjf3HA9oyxjz5QL6gs8SRXYV4hkxQ3", + "voucher": { + "channelId": "Fmw75DJk8fi8i6yjf3HA9oyxjz5QL6gs8SRXYV4hkxQ3", + "expiresAt": 0, + "maxClaimableAmount": "1000", + "signature": "5LEJTzesUtMgvaY25KSUo1TAQPQeht7RBpqYRyEc1vRijHDzv2P2tCYAXKqKVU7ke8RZuMmxcpajLAXXcqWWZCqe" + } + }, + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "110", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "Bpd4syvg5BSByt7xXbNVSztCpgwHsCDrzSm54pm49VjQ", + "voucher": { + "channelId": "Bpd4syvg5BSByt7xXbNVSztCpgwHsCDrzSm54pm49VjQ", + "expiresAt": 0, + "maxClaimableAmount": "1000", + "signature": "5ju5RhAzvKY9v1tub5tUR5aBcBRJjioyfeoJqXSo6WEd1ywCc1nw7tPpdAdJCjc4K4s9XFZPH9P6U2FCJH8WuDC7" + } + }, + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "111", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "EMJFPxSkCK8QztvKAjPniNbgevAu3Tcx8WpqDhw3zHxE", + "voucher": { + "channelId": "EMJFPxSkCK8QztvKAjPniNbgevAu3Tcx8WpqDhw3zHxE", + "expiresAt": 0, + "maxClaimableAmount": "1000", + "signature": "57r7o5SRxtLsJr9wMj8wEhB74inVaJFwVAqEqAqY6qqqtFZmpWprUE3CdBBjiCZym6Zb6jjsZB4iL5uyNtSHod9U" + } + }, + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "112", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "9ZZL2NSCaoQRmKqBJjtC5AyhuongALRcpiKi8oP5fZ3t", + "voucher": { + "channelId": "9ZZL2NSCaoQRmKqBJjtC5AyhuongALRcpiKi8oP5fZ3t", + "expiresAt": 0, + "maxClaimableAmount": "1000", + "signature": "3Dr3f4jFaMRQr8CW52yjNwsUMYekoaRXsWd93rmtsgo5Q7kGFKsEt5bLKDdjw53LS9G2SeCvVtbJKnyFdGxgHe4H" + } + }, + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "113", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "3bqqR4WnvtTMJxbChKYJHTktHyakzyUvYZbDEytT8umV", + "voucher": { + "channelId": "3bqqR4WnvtTMJxbChKYJHTktHyakzyUvYZbDEytT8umV", + "expiresAt": 0, + "maxClaimableAmount": "1000", + "signature": "3GULYmEqbBEXVNVPvhUAnKG9MHon55ktkBAGCixUSLwKdoKP1CMDRtWiCyXN963LHzmBQ4V4nxUWfJGPQgYoq8qi" + } + }, + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "114", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "AzABWhvJfRpZu9cPfoAGkfSgA7n6CLN7L1Tsz4kSsPtA", + "voucher": { + "channelId": "AzABWhvJfRpZu9cPfoAGkfSgA7n6CLN7L1Tsz4kSsPtA", + "expiresAt": 0, + "maxClaimableAmount": "1000", + "signature": "2CW2iPoeJx3EdeEgJ68bREhKhVRfGcyrbsQ9LWWoKM4sSLSF2Gm3y7BK2CaGRy9hX58QD7Rdi1pUM9Zv6sX24vQR" + } + }, + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "115", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "6GwxXVRNTRG1rMnvCs4Agy5Tw24Ag7JnPgZo5zDP6acv", + "voucher": { + "channelId": "6GwxXVRNTRG1rMnvCs4Agy5Tw24Ag7JnPgZo5zDP6acv", + "expiresAt": 0, + "maxClaimableAmount": "1000", + "signature": "37HNwRRV62mnVBg1X3F7T4pumj1B74i5Tz8YzXjvwEy6oU6ccxiawySDNi8Ezz9cCTyyZHkWJ7J4beaXhC6JKYbt" + } + }, + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "116", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "BhgXfPYvNtMZFhrKF3MpatXjVMM9KmppZgBugyfVWsmY", + "voucher": { + "channelId": "BhgXfPYvNtMZFhrKF3MpatXjVMM9KmppZgBugyfVWsmY", + "expiresAt": 0, + "maxClaimableAmount": "1000", + "signature": "5CzWp2MfYojT83Tu19vdpY6MuTFW9g5Vpha25N8u1Rw561xADeaoRcEK6fevHbo35ybACn3iT9xXf7xqRuiKKwSw" + } + }, + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "117", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "F2cTdjHc7JAfCogJzxiz2YiTsvtG4k55qvLewHRP6wvW", + "voucher": { + "channelId": "F2cTdjHc7JAfCogJzxiz2YiTsvtG4k55qvLewHRP6wvW", + "expiresAt": 0, + "maxClaimableAmount": "1000", + "signature": "2KpMKJ4doNJrtVkkRmxFTrn7BUGcRX8a2F5oSX5pN2GfUUWW9XNueUdycYMLMoi9tYopn1iqnQfJ77oQzCqPsquM" + } + } + ], + "type": "claim" + } + } + }, + "intent": "x402-batch-settlement", + "mode": "canonical-bytes", + "provenance": "generated", + "requirements": [ + "X402-76654742e7" + ], + "role": "both", + "spec": { + "doc": "x402/specs/schemes/batch-settlement/scheme_batch_settlement_svm.md", + "quote": "`claims[]` MUST contain at least one entry and at most `extra.maxClaimChannels` entries, or four when the facilitator advertises no `maxClaimChannels`, so the instruction pairs fit in one transaction without address lookup tables.", + "section": "4.5 Facilitator Interface" + }, + "tier": "offline" + }, + { + "bugType": "wire", + "description": "Nineteen claims exceed what fits one version-1 transaction, so no facilitator can advertise that capacity: the payload is malformed for every facilitator.", + "expect": { + "outcome": "reject", + "rejectCode": "invalid-payload" + }, + "id": "batch-wire-redemption-claim-nineteen-entries-reject", + "input": { + "batchWire": { + "shape": "redemption", + "value": { + "claims": [ + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "100", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "Br4wUi9TpNTB7wL9BXoCqKAaHhLVAiiiaWbxve2og5DM", + "voucher": { + "channelId": "Br4wUi9TpNTB7wL9BXoCqKAaHhLVAiiiaWbxve2og5DM", + "expiresAt": 0, + "maxClaimableAmount": "1000", + "signature": "5webiD4DbhJpjGjToBLXPonCCcDp5jK6KvJaG6y9LZj8RFsuxUgfeH5FLUKfZwxCkhc2qpxn9d9noyNxpwe5vhWo" + } + }, + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "101", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "96wiMpqdLQvBK2vTHw2ALnzKjoXeHPe9UHL8GPM6VBH3", + "voucher": { + "channelId": "96wiMpqdLQvBK2vTHw2ALnzKjoXeHPe9UHL8GPM6VBH3", + "expiresAt": 0, + "maxClaimableAmount": "1000", + "signature": "23ed7u1sWVL67DgP2XS5S6a8QNSNDNjx46N3WrDjQcYMkdTKwJxSovjLvESREwinqaX7qFGwZiH4KhX8whvKdyrm" + } + }, + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "102", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "918ujLxiyqZA2WmxznvtHsEk31nDmPr6Gs8nA73oY2yn", + "voucher": { + "channelId": "918ujLxiyqZA2WmxznvtHsEk31nDmPr6Gs8nA73oY2yn", + "expiresAt": 0, + "maxClaimableAmount": "1000", + "signature": "5M1EwT6SshyUKRhv6qKfSjk7qjjsw7rqZ1q1bjfpHnfqAUm6PUdzxMVspDQX1ptvQwjdwB4xd6xdpKJ9QC8gksdJ" + } + }, + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "103", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "27P2VM5swSSRGK83AqMhGNg9ZfTNVXtx74MkKevV8PpH", + "voucher": { + "channelId": "27P2VM5swSSRGK83AqMhGNg9ZfTNVXtx74MkKevV8PpH", + "expiresAt": 0, + "maxClaimableAmount": "1000", + "signature": "2yyjqaHsdiBKKHvjR8vdqqHeQ36AFruuGdsazmDBMEbtPiXjbDqA3q6s9FyugebWpzMWResiLPcNfkUBX2onVdyQ" + } + }, + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "104", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "BJtkqYs9cWfuyP1x9VGsdU2bmjQYTr2sDzPE1Wq6vFXs", + "voucher": { + "channelId": "BJtkqYs9cWfuyP1x9VGsdU2bmjQYTr2sDzPE1Wq6vFXs", + "expiresAt": 0, + "maxClaimableAmount": "1000", + "signature": "53JvbdCtBUmDgVwdPDbvwyWXMtXaZBvXR7uUsQq8EPLYtmB8HFSadt7LdhqJ2oGwS4iCcYm1WdCBu3PTU47YDR4h" + } + }, + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "105", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "4ANNVYxLfjNvjgR6kqD7W7waAfNGZQ3izAqrPuonvswN", + "voucher": { + "channelId": "4ANNVYxLfjNvjgR6kqD7W7waAfNGZQ3izAqrPuonvswN", + "expiresAt": 0, + "maxClaimableAmount": "1000", + "signature": "5M3HkGtcYhugcEhwguEn3kMuk3oP1tCeL1iUKXcFjr5V2E5e2QrK48rz7eEfZK66yo44gCGEEPPCC1W3VRzkqGK9" + } + }, + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "106", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "4q9jEnqAMp8hvBisuXh9HuitWBHRNKthHmdJ1bhBy7pN", + "voucher": { + "channelId": "4q9jEnqAMp8hvBisuXh9HuitWBHRNKthHmdJ1bhBy7pN", + "expiresAt": 0, + "maxClaimableAmount": "1000", + "signature": "2GiPnYGRk8fjqRf4TnpiXU3xV1HyrSfyKgQ2JXJVKK3R68ahvdfU11Frcc5HM2SeSLPrHDrZdnaXL9et1hwHvQtt" + } + }, + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "107", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "8F5xwzrKcgrMKLaTYGcKMZdcuDhiq7PxSGnHuWt6Md9F", + "voucher": { + "channelId": "8F5xwzrKcgrMKLaTYGcKMZdcuDhiq7PxSGnHuWt6Md9F", + "expiresAt": 0, + "maxClaimableAmount": "1000", + "signature": "2NHpct6EYtPLcX7pvV9CG6aB3tWuW9kpn9JDqPkiHZYZvfZUaUCmqxWzYSnRg5ZNCTUzSsXcvnRMDyLaoKRUWje4" + } + }, + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "108", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "GUNsKpc5ybB7tj7SUF8UasuByHS7Sxs3aptt5eRicATC", + "voucher": { + "channelId": "GUNsKpc5ybB7tj7SUF8UasuByHS7Sxs3aptt5eRicATC", + "expiresAt": 0, + "maxClaimableAmount": "1000", + "signature": "2aF1Rda2h8ecvpj6Dg99rBXd3Z1TAKtkoq8LPnwRw4UMbTYuqhVHjUn6hrPbnuzQTQiUj4VvEwTu813eu7dyzCh3" + } + }, + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "109", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "Fmw75DJk8fi8i6yjf3HA9oyxjz5QL6gs8SRXYV4hkxQ3", + "voucher": { + "channelId": "Fmw75DJk8fi8i6yjf3HA9oyxjz5QL6gs8SRXYV4hkxQ3", + "expiresAt": 0, + "maxClaimableAmount": "1000", + "signature": "5LEJTzesUtMgvaY25KSUo1TAQPQeht7RBpqYRyEc1vRijHDzv2P2tCYAXKqKVU7ke8RZuMmxcpajLAXXcqWWZCqe" + } + }, + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "110", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "Bpd4syvg5BSByt7xXbNVSztCpgwHsCDrzSm54pm49VjQ", + "voucher": { + "channelId": "Bpd4syvg5BSByt7xXbNVSztCpgwHsCDrzSm54pm49VjQ", + "expiresAt": 0, + "maxClaimableAmount": "1000", + "signature": "5ju5RhAzvKY9v1tub5tUR5aBcBRJjioyfeoJqXSo6WEd1ywCc1nw7tPpdAdJCjc4K4s9XFZPH9P6U2FCJH8WuDC7" + } + }, + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "111", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "EMJFPxSkCK8QztvKAjPniNbgevAu3Tcx8WpqDhw3zHxE", + "voucher": { + "channelId": "EMJFPxSkCK8QztvKAjPniNbgevAu3Tcx8WpqDhw3zHxE", + "expiresAt": 0, + "maxClaimableAmount": "1000", + "signature": "57r7o5SRxtLsJr9wMj8wEhB74inVaJFwVAqEqAqY6qqqtFZmpWprUE3CdBBjiCZym6Zb6jjsZB4iL5uyNtSHod9U" + } + }, + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "112", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "9ZZL2NSCaoQRmKqBJjtC5AyhuongALRcpiKi8oP5fZ3t", + "voucher": { + "channelId": "9ZZL2NSCaoQRmKqBJjtC5AyhuongALRcpiKi8oP5fZ3t", + "expiresAt": 0, + "maxClaimableAmount": "1000", + "signature": "3Dr3f4jFaMRQr8CW52yjNwsUMYekoaRXsWd93rmtsgo5Q7kGFKsEt5bLKDdjw53LS9G2SeCvVtbJKnyFdGxgHe4H" + } + }, + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "113", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "3bqqR4WnvtTMJxbChKYJHTktHyakzyUvYZbDEytT8umV", + "voucher": { + "channelId": "3bqqR4WnvtTMJxbChKYJHTktHyakzyUvYZbDEytT8umV", + "expiresAt": 0, + "maxClaimableAmount": "1000", + "signature": "3GULYmEqbBEXVNVPvhUAnKG9MHon55ktkBAGCixUSLwKdoKP1CMDRtWiCyXN963LHzmBQ4V4nxUWfJGPQgYoq8qi" + } + }, + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "114", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "AzABWhvJfRpZu9cPfoAGkfSgA7n6CLN7L1Tsz4kSsPtA", + "voucher": { + "channelId": "AzABWhvJfRpZu9cPfoAGkfSgA7n6CLN7L1Tsz4kSsPtA", + "expiresAt": 0, + "maxClaimableAmount": "1000", + "signature": "2CW2iPoeJx3EdeEgJ68bREhKhVRfGcyrbsQ9LWWoKM4sSLSF2Gm3y7BK2CaGRy9hX58QD7Rdi1pUM9Zv6sX24vQR" + } + }, + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "115", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "6GwxXVRNTRG1rMnvCs4Agy5Tw24Ag7JnPgZo5zDP6acv", + "voucher": { + "channelId": "6GwxXVRNTRG1rMnvCs4Agy5Tw24Ag7JnPgZo5zDP6acv", + "expiresAt": 0, + "maxClaimableAmount": "1000", + "signature": "37HNwRRV62mnVBg1X3F7T4pumj1B74i5Tz8YzXjvwEy6oU6ccxiawySDNi8Ezz9cCTyyZHkWJ7J4beaXhC6JKYbt" + } + }, + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "116", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "BhgXfPYvNtMZFhrKF3MpatXjVMM9KmppZgBugyfVWsmY", + "voucher": { + "channelId": "BhgXfPYvNtMZFhrKF3MpatXjVMM9KmppZgBugyfVWsmY", + "expiresAt": 0, + "maxClaimableAmount": "1000", + "signature": "5CzWp2MfYojT83Tu19vdpY6MuTFW9g5Vpha25N8u1Rw561xADeaoRcEK6fevHbo35ybACn3iT9xXf7xqRuiKKwSw" + } + }, + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "117", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "F2cTdjHc7JAfCogJzxiz2YiTsvtG4k55qvLewHRP6wvW", + "voucher": { + "channelId": "F2cTdjHc7JAfCogJzxiz2YiTsvtG4k55qvLewHRP6wvW", + "expiresAt": 0, + "maxClaimableAmount": "1000", + "signature": "2KpMKJ4doNJrtVkkRmxFTrn7BUGcRX8a2F5oSX5pN2GfUUWW9XNueUdycYMLMoi9tYopn1iqnQfJ77oQzCqPsquM" + } + }, + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "118", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "CutmAqgrNnmJq5uptvRKB691MVM1eWSLJX7ThpUi9iSp", + "voucher": { + "channelId": "CutmAqgrNnmJq5uptvRKB691MVM1eWSLJX7ThpUi9iSp", + "expiresAt": 0, + "maxClaimableAmount": "1000", + "signature": "2YSMAb1267LSdqmqEwKrucL5Tpcpcgg43cpjJy8qL8BwKZwcwQDLqCsdowxXavMgDjsb4favobzMpqfPQrxLxYpV" + } + } + ], + "type": "claim" + } + } + }, + "intent": "x402-batch-settlement", + "mode": "canonical-bytes", + "provenance": "authored", + "requirements": [ + "X402-76654742e7" + ], + "role": "both", + "spec": { + "doc": "x402/specs/schemes/batch-settlement/scheme_batch_settlement_svm.md", + "quote": "`claims[]` MUST contain at least one entry and at most `extra.maxClaimChannels` entries, or four when the facilitator advertises no `maxClaimChannels`, so the instruction pairs fit in one transaction without address lookup tables.", + "section": "4.5 Facilitator Interface" + }, + "tier": "offline" + }, + { + "bugType": "wire", + "description": "A claim entry without its channelConfig cannot be derived or validated.", + "expect": { + "outcome": "reject", + "rejectCode": "invalid-payload" + }, + "id": "batch-wire-redemption-claim-entry-without-config-reject", + "input": { + "batchWire": { + "shape": "redemption", + "value": { + "claims": [ + { + "channelId": "Hjg2PDgLxYDiQWRHrJeeY9V9iNyebM9MWutoA67eivsZ", + "voucher": { + "channelId": "Hjg2PDgLxYDiQWRHrJeeY9V9iNyebM9MWutoA67eivsZ", + "expiresAt": 0, + "maxClaimableAmount": "5000", + "signature": "pJgs3Kk5XkcdbKcwd6y1AupQ3ncgPtFMkS6WSCNfDt4FvgbRe8HCabuFNPHroAmE8VCvsWKgHJxWjDwAtESXmQ2" + } + } + ], + "type": "claim" + } + } + }, + "intent": "x402-batch-settlement", + "mode": "canonical-bytes", + "provenance": "generated", + "requirements": [ + "X402-76654742e7" + ], + "role": "both", + "spec": { + "doc": "x402/specs/schemes/batch-settlement/scheme_batch_settlement_svm.md", + "quote": "| Claim | `claims[].channelConfig` | `ChannelConfig` | Full channel configuration. |", + "section": "4.5 Facilitator Interface" + }, + "tier": "offline" + }, + { + "bugType": "wire", + "description": "settle payload: channels[] of {channelId, channelConfig}.", + "expect": { + "exactBytes": { + "base64Url": "eyJjaGFubmVscyI6W3siY2hhbm5lbENvbmZpZyI6eyJvcGVuU2xvdCI6MzQxMDAwMDAwLCJwYXllciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicGF5ZXJBdXRob3JpemVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJyZWNlaXZlciI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwicmVjZWl2ZXJBdXRob3JpemVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJzYWx0IjoiNDIiLCJ0b2tlbiI6IjR6TU1DOXNydDVSaTVYMTRHQWdYaGFIaWkzR25QQUVFUllQSmdaSkRuY0RVIiwid2l0aGRyYXdEZWxheSI6MzYwMH0sImNoYW5uZWxJZCI6IkhqZzJQRGdMeFlEaVFXUkhySmVlWTlWOWlOeWViTTlNV3V0b0E2N2VpdnNaIn1dLCJ0eXBlIjoic2V0dGxlIn0", + "canonicalJson": "{\"channels\":[{\"channelConfig\":{\"openSlot\":341000000,\"payer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"payerAuthorizer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"receiver\":\"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY\",\"receiverAuthorizer\":\"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os\",\"salt\":\"42\",\"token\":\"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU\",\"withdrawDelay\":3600},\"channelId\":\"Hjg2PDgLxYDiQWRHrJeeY9V9iNyebM9MWutoA67eivsZ\"}],\"type\":\"settle\"}" + }, + "outcome": "accept" + }, + "id": "batch-wire-redemption-settle-frozen", + "input": { + "batchWire": { + "shape": "redemption", + "value": { + "channels": [ + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "42", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "Hjg2PDgLxYDiQWRHrJeeY9V9iNyebM9MWutoA67eivsZ" + } + ], + "type": "settle" + } + } + }, + "intent": "x402-batch-settlement", + "mode": "canonical-bytes", + "provenance": "generated", + "requirements": [ + "X402-c2ca42b7a4" + ], + "role": "both", + "spec": { + "doc": "x402/specs/schemes/batch-settlement/scheme_batch_settlement_svm.md", + "quote": "`channels[]` MUST contain at least one entry and at most `extra.maxSettleChannels` entries, or four when the facilitator advertises no `maxSettleChannels`.", + "section": "4.5 Facilitator Interface" + }, + "tier": "offline" + }, + { + "bugType": "wire", + "description": "Thirteen settle channels, the version-1 capacity (extra.maxSettleChannels 13): the payload parses.", + "expect": { + "exactBytes": { + "base64Url": "eyJjaGFubmVscyI6W3siY2hhbm5lbENvbmZpZyI6eyJvcGVuU2xvdCI6MzQxMDAwMDAwLCJwYXllciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicGF5ZXJBdXRob3JpemVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJyZWNlaXZlciI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwicmVjZWl2ZXJBdXRob3JpemVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJzYWx0IjoiMjAwIiwidG9rZW4iOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsIndpdGhkcmF3RGVsYXkiOjM2MDB9LCJjaGFubmVsSWQiOiJDS2tzUHlMazRDaWV3UG83YTNYZVNMVDY3c1J3c253WGc3OVJycFNzMktQdyJ9LHsiY2hhbm5lbENvbmZpZyI6eyJvcGVuU2xvdCI6MzQxMDAwMDAwLCJwYXllciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicGF5ZXJBdXRob3JpemVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJyZWNlaXZlciI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwicmVjZWl2ZXJBdXRob3JpemVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJzYWx0IjoiMjAxIiwidG9rZW4iOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsIndpdGhkcmF3RGVsYXkiOjM2MDB9LCJjaGFubmVsSWQiOiI2Q0pBdWRBTGcycEVmdU5VODZ3YmV3Vm1TUTFTYmJxZ3hBYkt5dXlvcW9aWiJ9LHsiY2hhbm5lbENvbmZpZyI6eyJvcGVuU2xvdCI6MzQxMDAwMDAwLCJwYXllciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicGF5ZXJBdXRob3JpemVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJyZWNlaXZlciI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwicmVjZWl2ZXJBdXRob3JpemVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJzYWx0IjoiMjAyIiwidG9rZW4iOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsIndpdGhkcmF3RGVsYXkiOjM2MDB9LCJjaGFubmVsSWQiOiI1c1BOSllaYzVkam45UHQ3czJmWGp3em1OUkNWVHJTdGZVbnltaFQxd25KZCJ9LHsiY2hhbm5lbENvbmZpZyI6eyJvcGVuU2xvdCI6MzQxMDAwMDAwLCJwYXllciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicGF5ZXJBdXRob3JpemVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJyZWNlaXZlciI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwicmVjZWl2ZXJBdXRob3JpemVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJzYWx0IjoiMjAzIiwidG9rZW4iOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsIndpdGhkcmF3RGVsYXkiOjM2MDB9LCJjaGFubmVsSWQiOiI3d3lHQXU4VVhRYXA4V2hqVVA3ajNwVFRRMzcxTmJkVDZxTVVQdGV6c1phNyJ9LHsiY2hhbm5lbENvbmZpZyI6eyJvcGVuU2xvdCI6MzQxMDAwMDAwLCJwYXllciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicGF5ZXJBdXRob3JpemVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJyZWNlaXZlciI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwicmVjZWl2ZXJBdXRob3JpemVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJzYWx0IjoiMjA0IiwidG9rZW4iOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsIndpdGhkcmF3RGVsYXkiOjM2MDB9LCJjaGFubmVsSWQiOiIzN2o4eHppYjd2enFjdVo5MmlQUTZlNGI3OHRuOWttNzdDZTJCZXA1NmZENCJ9LHsiY2hhbm5lbENvbmZpZyI6eyJvcGVuU2xvdCI6MzQxMDAwMDAwLCJwYXllciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicGF5ZXJBdXRob3JpemVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJyZWNlaXZlciI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwicmVjZWl2ZXJBdXRob3JpemVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJzYWx0IjoiMjA1IiwidG9rZW4iOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsIndpdGhkcmF3RGVsYXkiOjM2MDB9LCJjaGFubmVsSWQiOiIzRUNWN1E3ZUF0bVhIOU5CSzRLaU44RUtvZ2tZV2E0SG1Wck1rcGJaajZyaiJ9LHsiY2hhbm5lbENvbmZpZyI6eyJvcGVuU2xvdCI6MzQxMDAwMDAwLCJwYXllciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicGF5ZXJBdXRob3JpemVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJyZWNlaXZlciI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwicmVjZWl2ZXJBdXRob3JpemVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJzYWx0IjoiMjA2IiwidG9rZW4iOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsIndpdGhkcmF3RGVsYXkiOjM2MDB9LCJjaGFubmVsSWQiOiJBcEFjbmRja0I3Ukh5M0g2dFJVUzR2QnlVb3VDVkthZXZVcXpHZFZVdUdGZiJ9LHsiY2hhbm5lbENvbmZpZyI6eyJvcGVuU2xvdCI6MzQxMDAwMDAwLCJwYXllciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicGF5ZXJBdXRob3JpemVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJyZWNlaXZlciI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwicmVjZWl2ZXJBdXRob3JpemVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJzYWx0IjoiMjA3IiwidG9rZW4iOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsIndpdGhkcmF3RGVsYXkiOjM2MDB9LCJjaGFubmVsSWQiOiJIR0FOblJEVGVHQ1A3YWRmZFByc2hxUlBwWTREcnVKbU5XMWVkWlZtTDE5QSJ9LHsiY2hhbm5lbENvbmZpZyI6eyJvcGVuU2xvdCI6MzQxMDAwMDAwLCJwYXllciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicGF5ZXJBdXRob3JpemVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJyZWNlaXZlciI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwicmVjZWl2ZXJBdXRob3JpemVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJzYWx0IjoiMjA4IiwidG9rZW4iOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsIndpdGhkcmF3RGVsYXkiOjM2MDB9LCJjaGFubmVsSWQiOiJHdDRNVlVDRzM5M0VRM3JnNFBxYk5YTjQ4OHNFdGVaSEVIOFQ5aVNmejVieiJ9LHsiY2hhbm5lbENvbmZpZyI6eyJvcGVuU2xvdCI6MzQxMDAwMDAwLCJwYXllciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicGF5ZXJBdXRob3JpemVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJyZWNlaXZlciI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwicmVjZWl2ZXJBdXRob3JpemVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJzYWx0IjoiMjA5IiwidG9rZW4iOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsIndpdGhkcmF3RGVsYXkiOjM2MDB9LCJjaGFubmVsSWQiOiJGdHY2SnFQamtMcWtyWXZMc1ViS1JONW9oRGRDM0FGUzlGeWNQV2I0YnhmbSJ9LHsiY2hhbm5lbENvbmZpZyI6eyJvcGVuU2xvdCI6MzQxMDAwMDAwLCJwYXllciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicGF5ZXJBdXRob3JpemVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJyZWNlaXZlciI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwicmVjZWl2ZXJBdXRob3JpemVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJzYWx0IjoiMjEwIiwidG9rZW4iOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsIndpdGhkcmF3RGVsYXkiOjM2MDB9LCJjaGFubmVsSWQiOiJFb3FmTEFCZDFQemN2MUc0Tm5tWGt4QUxXUGVxUXc3Y2FUTHI1a1Y3UTQ4ZyJ9LHsiY2hhbm5lbENvbmZpZyI6eyJvcGVuU2xvdCI6MzQxMDAwMDAwLCJwYXllciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicGF5ZXJBdXRob3JpemVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJyZWNlaXZlciI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwicmVjZWl2ZXJBdXRob3JpemVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJzYWx0IjoiMjExIiwidG9rZW4iOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsIndpdGhkcmF3RGVsYXkiOjM2MDB9LCJjaGFubmVsSWQiOiJFNXRBS3g4WHNmN1U4ZXpZeUdlMWZINjNrNnFpRm5yemdlUG0zZDZYelBlbyJ9LHsiY2hhbm5lbENvbmZpZyI6eyJvcGVuU2xvdCI6MzQxMDAwMDAwLCJwYXllciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicGF5ZXJBdXRob3JpemVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJyZWNlaXZlciI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwicmVjZWl2ZXJBdXRob3JpemVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJzYWx0IjoiMjEyIiwidG9rZW4iOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsIndpdGhkcmF3RGVsYXkiOjM2MDB9LCJjaGFubmVsSWQiOiIydzRtTGFFM2VYTEtwNDZGWldBUXZxYjJpVWdIQldOODg5QnhKcWE3YXFhUyJ9XSwidHlwZSI6InNldHRsZSJ9", + "canonicalJson": "{\"channels\":[{\"channelConfig\":{\"openSlot\":341000000,\"payer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"payerAuthorizer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"receiver\":\"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY\",\"receiverAuthorizer\":\"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os\",\"salt\":\"200\",\"token\":\"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU\",\"withdrawDelay\":3600},\"channelId\":\"CKksPyLk4CiewPo7a3XeSLT67sRwsnwXg79RrpSs2KPw\"},{\"channelConfig\":{\"openSlot\":341000000,\"payer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"payerAuthorizer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"receiver\":\"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY\",\"receiverAuthorizer\":\"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os\",\"salt\":\"201\",\"token\":\"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU\",\"withdrawDelay\":3600},\"channelId\":\"6CJAudALg2pEfuNU86wbewVmSQ1SbbqgxAbKyuyoqoZZ\"},{\"channelConfig\":{\"openSlot\":341000000,\"payer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"payerAuthorizer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"receiver\":\"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY\",\"receiverAuthorizer\":\"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os\",\"salt\":\"202\",\"token\":\"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU\",\"withdrawDelay\":3600},\"channelId\":\"5sPNJYZc5djn9Pt7s2fXjwzmNRCVTrStfUnymhT1wnJd\"},{\"channelConfig\":{\"openSlot\":341000000,\"payer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"payerAuthorizer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"receiver\":\"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY\",\"receiverAuthorizer\":\"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os\",\"salt\":\"203\",\"token\":\"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU\",\"withdrawDelay\":3600},\"channelId\":\"7wyGAu8UXQap8WhjUP7j3pTTQ371NbdT6qMUPtezsZa7\"},{\"channelConfig\":{\"openSlot\":341000000,\"payer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"payerAuthorizer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"receiver\":\"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY\",\"receiverAuthorizer\":\"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os\",\"salt\":\"204\",\"token\":\"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU\",\"withdrawDelay\":3600},\"channelId\":\"37j8xzib7vzqcuZ92iPQ6e4b78tn9km77Ce2Bep56fD4\"},{\"channelConfig\":{\"openSlot\":341000000,\"payer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"payerAuthorizer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"receiver\":\"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY\",\"receiverAuthorizer\":\"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os\",\"salt\":\"205\",\"token\":\"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU\",\"withdrawDelay\":3600},\"channelId\":\"3ECV7Q7eAtmXH9NBK4KiN8EKogkYWa4HmVrMkpbZj6rj\"},{\"channelConfig\":{\"openSlot\":341000000,\"payer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"payerAuthorizer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"receiver\":\"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY\",\"receiverAuthorizer\":\"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os\",\"salt\":\"206\",\"token\":\"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU\",\"withdrawDelay\":3600},\"channelId\":\"ApAcndckB7RHy3H6tRUS4vByUouCVKaevUqzGdVUuGFf\"},{\"channelConfig\":{\"openSlot\":341000000,\"payer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"payerAuthorizer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"receiver\":\"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY\",\"receiverAuthorizer\":\"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os\",\"salt\":\"207\",\"token\":\"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU\",\"withdrawDelay\":3600},\"channelId\":\"HGANnRDTeGCP7adfdPrshqRPpY4DruJmNW1edZVmL19A\"},{\"channelConfig\":{\"openSlot\":341000000,\"payer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"payerAuthorizer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"receiver\":\"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY\",\"receiverAuthorizer\":\"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os\",\"salt\":\"208\",\"token\":\"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU\",\"withdrawDelay\":3600},\"channelId\":\"Gt4MVUCG393EQ3rg4PqbNXN488sEteZHEH8T9iSfz5bz\"},{\"channelConfig\":{\"openSlot\":341000000,\"payer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"payerAuthorizer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"receiver\":\"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY\",\"receiverAuthorizer\":\"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os\",\"salt\":\"209\",\"token\":\"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU\",\"withdrawDelay\":3600},\"channelId\":\"Ftv6JqPjkLqkrYvLsUbKRN5ohDdC3AFS9FycPWb4bxfm\"},{\"channelConfig\":{\"openSlot\":341000000,\"payer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"payerAuthorizer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"receiver\":\"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY\",\"receiverAuthorizer\":\"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os\",\"salt\":\"210\",\"token\":\"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU\",\"withdrawDelay\":3600},\"channelId\":\"EoqfLABd1Pzcv1G4NnmXkxALWPeqQw7caTLr5kV7Q48g\"},{\"channelConfig\":{\"openSlot\":341000000,\"payer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"payerAuthorizer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"receiver\":\"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY\",\"receiverAuthorizer\":\"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os\",\"salt\":\"211\",\"token\":\"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU\",\"withdrawDelay\":3600},\"channelId\":\"E5tAKx8Xsf7U8ezYyGe1fH63k6qiFnrzgePm3d6XzPeo\"},{\"channelConfig\":{\"openSlot\":341000000,\"payer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"payerAuthorizer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"receiver\":\"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY\",\"receiverAuthorizer\":\"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os\",\"salt\":\"212\",\"token\":\"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU\",\"withdrawDelay\":3600},\"channelId\":\"2w4mLaE3eXLKp46FZWAQvqb2iUgHBWN889BxJqa7aqaS\"}],\"type\":\"settle\"}" + }, + "outcome": "accept" + }, + "id": "batch-wire-redemption-settle-thirteen-channels", + "input": { + "batchWire": { + "shape": "redemption", + "value": { + "channels": [ + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "200", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "CKksPyLk4CiewPo7a3XeSLT67sRwsnwXg79RrpSs2KPw" + }, + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "201", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "6CJAudALg2pEfuNU86wbewVmSQ1SbbqgxAbKyuyoqoZZ" + }, + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "202", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "5sPNJYZc5djn9Pt7s2fXjwzmNRCVTrStfUnymhT1wnJd" + }, + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "203", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "7wyGAu8UXQap8WhjUP7j3pTTQ371NbdT6qMUPtezsZa7" + }, + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "204", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "37j8xzib7vzqcuZ92iPQ6e4b78tn9km77Ce2Bep56fD4" + }, + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "205", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "3ECV7Q7eAtmXH9NBK4KiN8EKogkYWa4HmVrMkpbZj6rj" + }, + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "206", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "ApAcndckB7RHy3H6tRUS4vByUouCVKaevUqzGdVUuGFf" + }, + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "207", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "HGANnRDTeGCP7adfdPrshqRPpY4DruJmNW1edZVmL19A" + }, + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "208", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "Gt4MVUCG393EQ3rg4PqbNXN488sEteZHEH8T9iSfz5bz" + }, + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "209", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "Ftv6JqPjkLqkrYvLsUbKRN5ohDdC3AFS9FycPWb4bxfm" + }, + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "210", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "EoqfLABd1Pzcv1G4NnmXkxALWPeqQw7caTLr5kV7Q48g" + }, + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "211", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "E5tAKx8Xsf7U8ezYyGe1fH63k6qiFnrzgePm3d6XzPeo" + }, + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "212", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "2w4mLaE3eXLKp46FZWAQvqb2iUgHBWN889BxJqa7aqaS" + } + ], + "type": "settle" + } + } + }, + "intent": "x402-batch-settlement", + "mode": "canonical-bytes", + "provenance": "generated", + "requirements": [ + "X402-c2ca42b7a4" + ], + "role": "both", + "spec": { + "doc": "x402/specs/schemes/batch-settlement/scheme_batch_settlement_svm.md", + "quote": "`channels[]` MUST contain at least one entry and at most `extra.maxSettleChannels` entries, or four when the facilitator advertises no `maxSettleChannels`.", + "section": "4.5 Facilitator Interface" + }, + "tier": "offline" + }, + { + "bugType": "wire", + "description": "Fourteen settle channels exceed the largest capacity a facilitator may advertise (13): the payload is malformed for every facilitator.", "expect": { "outcome": "reject", "rejectCode": "invalid-payload" }, - "id": "batch-wire-redemption-claim-five-entries-reject", + "id": "batch-wire-redemption-settle-fourteen-channels-reject", "input": { "batchWire": { "shape": "redemption", "value": { - "claims": [ + "channels": [ { "channelConfig": { "openSlot": 341000000, @@ -707,17 +1770,11 @@ "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", - "salt": "100", + "salt": "200", "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", "withdrawDelay": 3600 }, - "channelId": "Br4wUi9TpNTB7wL9BXoCqKAaHhLVAiiiaWbxve2og5DM", - "voucher": { - "channelId": "Br4wUi9TpNTB7wL9BXoCqKAaHhLVAiiiaWbxve2og5DM", - "expiresAt": 0, - "maxClaimableAmount": "1000", - "signature": "5webiD4DbhJpjGjToBLXPonCCcDp5jK6KvJaG6y9LZj8RFsuxUgfeH5FLUKfZwxCkhc2qpxn9d9noyNxpwe5vhWo" - } + "channelId": "CKksPyLk4CiewPo7a3XeSLT67sRwsnwXg79RrpSs2KPw" }, { "channelConfig": { @@ -726,17 +1783,11 @@ "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", - "salt": "101", + "salt": "201", "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", "withdrawDelay": 3600 }, - "channelId": "96wiMpqdLQvBK2vTHw2ALnzKjoXeHPe9UHL8GPM6VBH3", - "voucher": { - "channelId": "96wiMpqdLQvBK2vTHw2ALnzKjoXeHPe9UHL8GPM6VBH3", - "expiresAt": 0, - "maxClaimableAmount": "1000", - "signature": "23ed7u1sWVL67DgP2XS5S6a8QNSNDNjx46N3WrDjQcYMkdTKwJxSovjLvESREwinqaX7qFGwZiH4KhX8whvKdyrm" - } + "channelId": "6CJAudALg2pEfuNU86wbewVmSQ1SbbqgxAbKyuyoqoZZ" }, { "channelConfig": { @@ -745,17 +1796,11 @@ "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", - "salt": "102", + "salt": "202", "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", "withdrawDelay": 3600 }, - "channelId": "918ujLxiyqZA2WmxznvtHsEk31nDmPr6Gs8nA73oY2yn", - "voucher": { - "channelId": "918ujLxiyqZA2WmxznvtHsEk31nDmPr6Gs8nA73oY2yn", - "expiresAt": 0, - "maxClaimableAmount": "1000", - "signature": "5M1EwT6SshyUKRhv6qKfSjk7qjjsw7rqZ1q1bjfpHnfqAUm6PUdzxMVspDQX1ptvQwjdwB4xd6xdpKJ9QC8gksdJ" - } + "channelId": "5sPNJYZc5djn9Pt7s2fXjwzmNRCVTrStfUnymhT1wnJd" }, { "channelConfig": { @@ -764,17 +1809,11 @@ "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", - "salt": "103", + "salt": "203", "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", "withdrawDelay": 3600 }, - "channelId": "27P2VM5swSSRGK83AqMhGNg9ZfTNVXtx74MkKevV8PpH", - "voucher": { - "channelId": "27P2VM5swSSRGK83AqMhGNg9ZfTNVXtx74MkKevV8PpH", - "expiresAt": 0, - "maxClaimableAmount": "1000", - "signature": "2yyjqaHsdiBKKHvjR8vdqqHeQ36AFruuGdsazmDBMEbtPiXjbDqA3q6s9FyugebWpzMWResiLPcNfkUBX2onVdyQ" - } + "channelId": "7wyGAu8UXQap8WhjUP7j3pTTQ371NbdT6qMUPtezsZa7" }, { "channelConfig": { @@ -783,94 +1822,25 @@ "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", - "salt": "104", + "salt": "204", "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", "withdrawDelay": 3600 }, - "channelId": "BJtkqYs9cWfuyP1x9VGsdU2bmjQYTr2sDzPE1Wq6vFXs", - "voucher": { - "channelId": "BJtkqYs9cWfuyP1x9VGsdU2bmjQYTr2sDzPE1Wq6vFXs", - "expiresAt": 0, - "maxClaimableAmount": "1000", - "signature": "53JvbdCtBUmDgVwdPDbvwyWXMtXaZBvXR7uUsQq8EPLYtmB8HFSadt7LdhqJ2oGwS4iCcYm1WdCBu3PTU47YDR4h" - } - } - ], - "type": "claim" - } - } - }, - "intent": "x402-batch-settlement", - "mode": "canonical-bytes", - "provenance": "authored", - "requirements": [ - "X402-7f4ee54a73" - ], - "role": "both", - "spec": { - "doc": "x402/specs/schemes/batch-settlement/scheme_batch_settlement_svm.md", - "quote": "`claims[]` MUST contain between one and four entries so the instruction pairs fit in a legacy Solana transaction without address lookup tables.", - "section": "4.5 Facilitator Interface" - }, - "tier": "offline" - }, - { - "bugType": "wire", - "description": "A claim entry without its channelConfig cannot be derived or validated.", - "expect": { - "outcome": "reject", - "rejectCode": "invalid-payload" - }, - "id": "batch-wire-redemption-claim-entry-without-config-reject", - "input": { - "batchWire": { - "shape": "redemption", - "value": { - "claims": [ + "channelId": "37j8xzib7vzqcuZ92iPQ6e4b78tn9km77Ce2Bep56fD4" + }, { - "channelId": "Hjg2PDgLxYDiQWRHrJeeY9V9iNyebM9MWutoA67eivsZ", - "voucher": { - "channelId": "Hjg2PDgLxYDiQWRHrJeeY9V9iNyebM9MWutoA67eivsZ", - "expiresAt": 0, - "maxClaimableAmount": "5000", - "signature": "pJgs3Kk5XkcdbKcwd6y1AupQ3ncgPtFMkS6WSCNfDt4FvgbRe8HCabuFNPHroAmE8VCvsWKgHJxWjDwAtESXmQ2" - } - } - ], - "type": "claim" - } - } - }, - "intent": "x402-batch-settlement", - "mode": "canonical-bytes", - "provenance": "generated", - "requirements": [ - "X402-7f4ee54a73" - ], - "role": "both", - "spec": { - "doc": "x402/specs/schemes/batch-settlement/scheme_batch_settlement_svm.md", - "quote": "| Claim | `claims[].channelConfig` | `ChannelConfig` | Full channel configuration. |", - "section": "4.5 Facilitator Interface" - }, - "tier": "offline" - }, - { - "bugType": "wire", - "description": "settle payload: channels[] of {channelId, channelConfig}.", - "expect": { - "exactBytes": { - "base64Url": "eyJjaGFubmVscyI6W3siY2hhbm5lbENvbmZpZyI6eyJvcGVuU2xvdCI6MzQxMDAwMDAwLCJwYXllciI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwicGF5ZXJBdXRob3JpemVyIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJyZWNlaXZlciI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwicmVjZWl2ZXJBdXRob3JpemVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJzYWx0IjoiNDIiLCJ0b2tlbiI6IjR6TU1DOXNydDVSaTVYMTRHQWdYaGFIaWkzR25QQUVFUllQSmdaSkRuY0RVIiwid2l0aGRyYXdEZWxheSI6MzYwMH0sImNoYW5uZWxJZCI6IkhqZzJQRGdMeFlEaVFXUkhySmVlWTlWOWlOeWViTTlNV3V0b0E2N2VpdnNaIn1dLCJ0eXBlIjoic2V0dGxlIn0", - "canonicalJson": "{\"channels\":[{\"channelConfig\":{\"openSlot\":341000000,\"payer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"payerAuthorizer\":\"GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB\",\"receiver\":\"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY\",\"receiverAuthorizer\":\"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os\",\"salt\":\"42\",\"token\":\"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU\",\"withdrawDelay\":3600},\"channelId\":\"Hjg2PDgLxYDiQWRHrJeeY9V9iNyebM9MWutoA67eivsZ\"}],\"type\":\"settle\"}" - }, - "outcome": "accept" - }, - "id": "batch-wire-redemption-settle-frozen", - "input": { - "batchWire": { - "shape": "redemption", - "value": { - "channels": [ + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "205", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "3ECV7Q7eAtmXH9NBK4KiN8EKogkYWa4HmVrMkpbZj6rj" + }, { "channelConfig": { "openSlot": 341000000, @@ -878,11 +1848,102 @@ "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", - "salt": "42", + "salt": "206", "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", "withdrawDelay": 3600 }, - "channelId": "Hjg2PDgLxYDiQWRHrJeeY9V9iNyebM9MWutoA67eivsZ" + "channelId": "ApAcndckB7RHy3H6tRUS4vByUouCVKaevUqzGdVUuGFf" + }, + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "207", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "HGANnRDTeGCP7adfdPrshqRPpY4DruJmNW1edZVmL19A" + }, + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "208", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "Gt4MVUCG393EQ3rg4PqbNXN488sEteZHEH8T9iSfz5bz" + }, + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "209", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "Ftv6JqPjkLqkrYvLsUbKRN5ohDdC3AFS9FycPWb4bxfm" + }, + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "210", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "EoqfLABd1Pzcv1G4NnmXkxALWPeqQw7caTLr5kV7Q48g" + }, + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "211", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "E5tAKx8Xsf7U8ezYyGe1fH63k6qiFnrzgePm3d6XzPeo" + }, + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "212", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "2w4mLaE3eXLKp46FZWAQvqb2iUgHBWN889BxJqa7aqaS" + }, + { + "channelConfig": { + "openSlot": 341000000, + "payer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "payerAuthorizer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB", + "receiver": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "salt": "213", + "token": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "withdrawDelay": 3600 + }, + "channelId": "C9s2aCByGGsp78EWjAqDirgZdKpcXPtQPGcjotGMKXCB" } ], "type": "settle" @@ -891,14 +1952,14 @@ }, "intent": "x402-batch-settlement", "mode": "canonical-bytes", - "provenance": "generated", + "provenance": "authored", "requirements": [ - "X402-7f4ee54a73" + "X402-c2ca42b7a4" ], "role": "both", "spec": { "doc": "x402/specs/schemes/batch-settlement/scheme_batch_settlement_svm.md", - "quote": "`channels[]` MUST contain between one and four entries, the same transaction-size bound as `claims[]`.", + "quote": "`channels[]` MUST contain at least one entry and at most `extra.maxSettleChannels` entries, or four when the facilitator advertises no `maxSettleChannels`.", "section": "4.5 Facilitator Interface" }, "tier": "offline" @@ -1073,8 +2134,8 @@ "description": "Requirements of a route whose facilitator accepts versions 0 and 1 carry extra.transactionVersions [0, 1].", "expect": { "exactBytes": { - "base64Url": "eyJhbW91bnQiOiIxMDAwIiwiYXNzZXQiOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsImV4dHJhIjp7ImZlZVBheWVyIjoiSjJ4Y2NSdHVHNDNkckVTTFl6bkhoTGhRa0xUZGZlcGNLWWJpUTlCc0pWYWYiLCJtZW1vIjoiaW52b2ljZS00MiIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwidG9rZW5Qcm9ncmFtIjoiVG9rZW5rZWdRZmVaeWlOd0FKYk5iR0tQRlhDV3VCdmY5U3M2MjNWUTVEQSIsInRyYW5zYWN0aW9uVmVyc2lvbnMiOlswLDFdLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwibWF4VGltZW91dFNlY29uZHMiOjMwMCwibmV0d29yayI6InNvbGFuYTpFdFdUUkFCWmFZcTZpTWZlWUtvdVJ1MTY2VlUyeHFhMSIsInBheVRvIjoiQ1hockZaSkxLcWp6bVAzc2pZTGNGNGRUZVhXS0N5OWUyU1hYWjJZbzZNUFkiLCJzY2hlbWUiOiJiYXRjaC1zZXR0bGVtZW50In0", - "canonicalJson": "{\"amount\":\"1000\",\"asset\":\"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU\",\"extra\":{\"feePayer\":\"J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf\",\"memo\":\"invoice-42\",\"receiverAuthorizer\":\"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os\",\"tokenProgram\":\"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\",\"transactionVersions\":[0,1],\"withdrawDelay\":3600},\"maxTimeoutSeconds\":300,\"network\":\"solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1\",\"payTo\":\"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY\",\"scheme\":\"batch-settlement\"}" + "base64Url": "eyJhbW91bnQiOiIxMDAwIiwiYXNzZXQiOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsImV4dHJhIjp7ImZlZVBheWVyIjoiSjJ4Y2NSdHVHNDNkckVTTFl6bkhoTGhRa0xUZGZlcGNLWWJpUTlCc0pWYWYiLCJtYXhDbGFpbUNoYW5uZWxzIjoxOCwibWF4U2V0dGxlQ2hhbm5lbHMiOjEzLCJtZW1vIjoiaW52b2ljZS00MiIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwidG9rZW5Qcm9ncmFtIjoiVG9rZW5rZWdRZmVaeWlOd0FKYk5iR0tQRlhDV3VCdmY5U3M2MjNWUTVEQSIsInRyYW5zYWN0aW9uVmVyc2lvbnMiOlswLDFdLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwibWF4VGltZW91dFNlY29uZHMiOjMwMCwibmV0d29yayI6InNvbGFuYTpFdFdUUkFCWmFZcTZpTWZlWUtvdVJ1MTY2VlUyeHFhMSIsInBheVRvIjoiQ1hockZaSkxLcWp6bVAzc2pZTGNGNGRUZVhXS0N5OWUyU1hYWjJZbzZNUFkiLCJzY2hlbWUiOiJiYXRjaC1zZXR0bGVtZW50In0", + "canonicalJson": "{\"amount\":\"1000\",\"asset\":\"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU\",\"extra\":{\"feePayer\":\"J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf\",\"maxClaimChannels\":18,\"maxSettleChannels\":13,\"memo\":\"invoice-42\",\"receiverAuthorizer\":\"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os\",\"tokenProgram\":\"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\",\"transactionVersions\":[0,1],\"withdrawDelay\":3600},\"maxTimeoutSeconds\":300,\"network\":\"solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1\",\"payTo\":\"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY\",\"scheme\":\"batch-settlement\"}" }, "outcome": "accept" }, @@ -1087,6 +2148,8 @@ "asset": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", "extra": { "feePayer": "J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf", + "maxClaimChannels": 18, + "maxSettleChannels": 13, "memo": "invoice-42", "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", "tokenProgram": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", @@ -1117,6 +2180,57 @@ }, "tier": "offline" }, + { + "bugType": "wire", + "description": "Requirements of a route whose facilitator builds redemptions as version 1 carry its capacity, extra.maxClaimChannels 18 and extra.maxSettleChannels 13, copied from /supported; the SDK's requirements type keeps both.", + "expect": { + "exactBytes": { + "base64Url": "eyJhbW91bnQiOiIxMDAwIiwiYXNzZXQiOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsImV4dHJhIjp7ImZlZVBheWVyIjoiSjJ4Y2NSdHVHNDNkckVTTFl6bkhoTGhRa0xUZGZlcGNLWWJpUTlCc0pWYWYiLCJtYXhDbGFpbUNoYW5uZWxzIjoxOCwibWF4U2V0dGxlQ2hhbm5lbHMiOjEzLCJtZW1vIjoiaW52b2ljZS00MiIsInJlY2VpdmVyQXV0aG9yaXplciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwidG9rZW5Qcm9ncmFtIjoiVG9rZW5rZWdRZmVaeWlOd0FKYk5iR0tQRlhDV3VCdmY5U3M2MjNWUTVEQSIsInRyYW5zYWN0aW9uVmVyc2lvbnMiOlswLDFdLCJ3aXRoZHJhd0RlbGF5IjozNjAwfSwibWF4VGltZW91dFNlY29uZHMiOjMwMCwibmV0d29yayI6InNvbGFuYTpFdFdUUkFCWmFZcTZpTWZlWUtvdVJ1MTY2VlUyeHFhMSIsInBheVRvIjoiQ1hockZaSkxLcWp6bVAzc2pZTGNGNGRUZVhXS0N5OWUyU1hYWjJZbzZNUFkiLCJzY2hlbWUiOiJiYXRjaC1zZXR0bGVtZW50In0", + "canonicalJson": "{\"amount\":\"1000\",\"asset\":\"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU\",\"extra\":{\"feePayer\":\"J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf\",\"maxClaimChannels\":18,\"maxSettleChannels\":13,\"memo\":\"invoice-42\",\"receiverAuthorizer\":\"AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os\",\"tokenProgram\":\"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\",\"transactionVersions\":[0,1],\"withdrawDelay\":3600},\"maxTimeoutSeconds\":300,\"network\":\"solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1\",\"payTo\":\"CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY\",\"scheme\":\"batch-settlement\"}" + }, + "outcome": "accept" + }, + "id": "batch-wire-requirements-redemption-capacity", + "input": { + "batchWire": { + "shape": "requirements", + "value": { + "amount": "1000", + "asset": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "extra": { + "feePayer": "J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf", + "maxClaimChannels": 18, + "maxSettleChannels": 13, + "memo": "invoice-42", + "receiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "tokenProgram": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "transactionVersions": [ + 0, + 1 + ], + "withdrawDelay": 3600 + }, + "maxTimeoutSeconds": 300, + "network": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "payTo": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "scheme": "batch-settlement" + } + } + }, + "intent": "x402-batch-settlement", + "mode": "canonical-bytes", + "provenance": "generated", + "requirements": [ + "X402-8f57677e36" + ], + "role": "both", + "spec": { + "doc": "x402/specs/schemes/batch-settlement/scheme_batch_settlement_svm.md", + "quote": "The server MUST copy `feePayer`, `transactionVersions`, `maxClaimChannels`, `maxSettleChannels`, and `maxIdleSecs` into `PaymentRequirements.extra`", + "section": "GET /supported" + }, + "tier": "offline" + }, { "bugType": "wire", "description": "extra.transactionVersions [0, 2]: 2 is not a transaction message version.", @@ -1158,7 +2272,7 @@ "role": "both", "spec": { "doc": "x402-txv1/specs/schemes/batch-settlement/scheme_batch_settlement_svm.md", - "quote": "Entries are the integers `0` and `1`, the Wallet Standard `supportedTransactionVersions` vocabulary.", + "quote": "Entries MUST be the JSON integers `0` and `1` only.", "section": "Transaction versions" }, "tier": "offline" diff --git a/harness/vectors/session-build.json b/harness/vectors/session-build.json index 019fe3e52..a69a08194 100644 --- a/harness/vectors/session-build.json +++ b/harness/vectors/session-build.json @@ -33,6 +33,7 @@ "recentBlockhash": "EkSnNWid2cvwEVnVx9aBqawnmiCNiDgp3gUdkDPTKN1N", "recentSlot": "250000000" }, + "deposit": "1000", "request": { "amount": "25", "currency": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", @@ -251,6 +252,7 @@ "recentBlockhash": "EkSnNWid2cvwEVnVx9aBqawnmiCNiDgp3gUdkDPTKN1N", "recentSlot": "250000000" }, + "deposit": "1000", "request": { "amount": "25", "currency": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", @@ -538,6 +540,7 @@ "recentBlockhash": "EkSnNWid2cvwEVnVx9aBqawnmiCNiDgp3gUdkDPTKN1N", "recentSlot": "250000000" }, + "deposit": "1000", "request": { "amount": "25", "currency": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", @@ -762,6 +765,7 @@ "recentBlockhash": "EkSnNWid2cvwEVnVx9aBqawnmiCNiDgp3gUdkDPTKN1N", "recentSlot": "250000000" }, + "deposit": "1000", "request": { "amount": "25", "currency": "2b1kV6DkPAnxd5ixfnxCpjxmKwqjjaYmCZfHsFu24GXo", @@ -976,6 +980,7 @@ "recentBlockhash": "EkSnNWid2cvwEVnVx9aBqawnmiCNiDgp3gUdkDPTKN1N", "recentSlot": "250000000" }, + "deposit": "1000", "request": { "amount": "25", "currency": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", @@ -1169,6 +1174,7 @@ "recentBlockhash": "EkSnNWid2cvwEVnVx9aBqawnmiCNiDgp3gUdkDPTKN1N", "recentSlot": "250000000" }, + "deposit": "1000", "request": { "amount": "25", "currency": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", @@ -1347,6 +1353,203 @@ }, "tier": "offline" }, + { + "bugType": "defaults", + "description": "The challenged recentBlockhash is not a live blockhash on the client's cluster (its RPC's latest is another), so it is not from the selected network: an open signed over it would be valid on another cluster. The client refuses before signing. Pair: session-build-open-client-paid.", + "expect": { + "outcome": "reject", + "rejectCode": "invalid-challenge" + }, + "id": "session-build-foreign-blockhash-reject", + "input": { + "rpcFixtures": { + "recentBlockhash": "9zrUHnA1nCByPksy3aL8tQ47vqdaG2vnFs4HrxgcZj4F" + }, + "sessionOpenBuild": { + "challenge": { + "id": "c_session_conformance_0001", + "recentBlockhash": "EkSnNWid2cvwEVnVx9aBqawnmiCNiDgp3gUdkDPTKN1N", + "recentSlot": "250000000" + }, + "deposit": "1000", + "request": { + "amount": "25", + "currency": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "methodDetails": { + "channelProgram": "CHNLxYvVA28MJP9PrFuDXccuoGXAx7jBacfLEkahyGsX", + "decimals": 6, + "gracePeriodSeconds": 900, + "network": "devnet", + "recentBlockhash": "EkSnNWid2cvwEVnVx9aBqawnmiCNiDgp3gUdkDPTKN1N", + "recentSlot": "250000000", + "voucherSigner": "client" + }, + "minimumDeposit": "100", + "recipient": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "suggestedDeposit": "1000" + }, + "salt": "7", + "server": { + "amount": "25", + "currency": "USDC", + "decimals": 6, + "gracePeriodSeconds": 900, + "idleTimeoutSeconds": 300, + "minimumDeposit": "100", + "network": "devnet", + "operator": "7v54NWdBtkjuAFJrLGsS2SXnuk8nKam81mZJeeYxVFi9", + "recipient": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "suggestedDeposit": "1000", + "voucherSigner": "client" + } + }, + "sessionSignerSecretKey": [ + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 145, + 162, + 138, + 11, + 116, + 56, + 21, + 147, + 164, + 217, + 70, + 149, + 121, + 32, + 137, + 38, + 175, + 200, + 173, + 130, + 200, + 131, + 155, + 118, + 68, + 53, + 155, + 158, + 186, + 154, + 75, + 58 + ], + "signerSecretKey": [ + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 234, + 74, + 108, + 99, + 226, + 156, + 82, + 10, + 190, + 245, + 80, + 123, + 19, + 46, + 197, + 249, + 149, + 71, + 118, + 174, + 190, + 190, + 123, + 146, + 66, + 30, + 234, + 105, + 20, + 70, + 210, + 44 + ] + }, + "intent": "session", + "mode": "build-transaction", + "provenance": "generated", + "requirements": [ + "MPP-d235eadc2e" + ], + "role": "client", + "spec": { + "doc": "mpp-specs/specs/methods/solana/draft-solana-session-00.md", + "quote": "The server MUST obtain it from the selected network, and the client MUST use it as the transaction message's recent blockhash.", + "section": "Method Details" + }, + "tier": "offline" + }, { "bugType": "defaults", "description": "A new-channel challenge without recentSlot. Pair: session-build-open-client-paid. Challenge edit: challenge /methodDetails/recentSlot removed.", @@ -1362,6 +1565,7 @@ "recentBlockhash": "EkSnNWid2cvwEVnVx9aBqawnmiCNiDgp3gUdkDPTKN1N", "recentSlot": "250000000" }, + "deposit": "1000", "request": { "amount": "25", "currency": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", @@ -1554,6 +1758,7 @@ "recentBlockhash": "EkSnNWid2cvwEVnVx9aBqawnmiCNiDgp3gUdkDPTKN1N", "recentSlot": "250000000" }, + "deposit": "1000", "request": { "amount": "25", "currency": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", @@ -1748,6 +1953,7 @@ "recentBlockhash": "EkSnNWid2cvwEVnVx9aBqawnmiCNiDgp3gUdkDPTKN1N", "recentSlot": "250000000" }, + "deposit": "1000", "request": { "amount": "25", "currency": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", @@ -1942,6 +2148,7 @@ "recentBlockhash": "EkSnNWid2cvwEVnVx9aBqawnmiCNiDgp3gUdkDPTKN1N", "recentSlot": "250000000" }, + "deposit": "1000", "request": { "amount": "25", "currency": "sol", @@ -2135,6 +2342,7 @@ "recentBlockhash": "EkSnNWid2cvwEVnVx9aBqawnmiCNiDgp3gUdkDPTKN1N", "recentSlot": "250000000" }, + "deposit": "1000", "request": { "amount": "25", "currency": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", @@ -2329,6 +2537,7 @@ "recentBlockhash": "EkSnNWid2cvwEVnVx9aBqawnmiCNiDgp3gUdkDPTKN1N", "recentSlot": "250000000" }, + "deposit": "1000", "request": { "amount": "25", "currency": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", @@ -2522,6 +2731,7 @@ "recentBlockhash": "EkSnNWid2cvwEVnVx9aBqawnmiCNiDgp3gUdkDPTKN1N", "recentSlot": "250000000" }, + "deposit": "1000", "request": { "amount": "25", "currency": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", @@ -2715,6 +2925,7 @@ "recentBlockhash": "EkSnNWid2cvwEVnVx9aBqawnmiCNiDgp3gUdkDPTKN1N", "recentSlot": "250000000" }, + "deposit": "1000", "request": { "amount": "25", "currency": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", @@ -2908,6 +3119,7 @@ "recentBlockhash": "EkSnNWid2cvwEVnVx9aBqawnmiCNiDgp3gUdkDPTKN1N", "recentSlot": "250000000" }, + "deposit": "1000", "request": { "amount": "25", "currency": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", diff --git a/harness/vectors/x402-tx-versions.json b/harness/vectors/x402-tx-versions.json index a027dfbbe..e2e8aef1b 100644 --- a/harness/vectors/x402-tx-versions.json +++ b/harness/vectors/x402-tx-versions.json @@ -936,6 +936,239 @@ }, "tier": "offline" }, + { + "bugType": "defaults", + "description": "extra.transactionVersions [2, 1, 0]: version 2 is not a defined entry, so the whole field is invalid and the client fails with unsupported_transaction_version instead of building version 1 from the entries it knows. The build judge verifies the header with a Rust sponsor accepting the offer's versions and compares the message version and header config with the kit's build.", + "expect": { + "outcome": "reject", + "rejectCode": "unsupported-version", + "rejectReason": "unsupported_transaction_version: invalid entry 2" + }, + "id": "x402-build-unknown-entry-reject", + "input": { + "rpcFixtures": { + "mints": { + "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU": { + "decimals": 6, + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + } + }, + "recentBlockhash": "11111111111111111111111111111111" + }, + "signerSecretKey": [ + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 234, + 74, + 108, + 99, + 226, + 156, + 82, + 10, + 190, + 245, + 80, + 123, + 19, + 46, + 197, + 249, + 149, + 71, + 118, + 174, + 190, + 190, + 123, + 146, + 66, + 30, + 234, + 105, + 20, + 70, + 210, + 44 + ], + "x402Offer": { + "amount": "1000", + "asset": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "extra": { + "feePayer": "7v54NWdBtkjuAFJrLGsS2SXnuk8nKam81mZJeeYxVFi9", + "transactionVersions": [ + 2, + 1, + 0 + ] + }, + "maxTimeoutSeconds": 300, + "network": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "payTo": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "scheme": "exact" + }, + "x402Version": 2 + }, + "intent": "x402-exact", + "mode": "build-transaction", + "provenance": "authored", + "requirements": [ + "X402TX-927d17b62e" + ], + "role": "client", + "spec": { + "doc": "x402-txv1/specs/schemes/exact/scheme_exact_svm.md", + "quote": "A client or server MUST treat a field containing any non-integer entry (a string, null, or \"legacy\") or any integer other than 0 or 1 as invalid and fail closed with unsupported_transaction_version.", + "section": "1.5 Transaction Versions (MUST)" + }, + "tier": "offline" + }, + { + "bugType": "defaults", + "description": "extra.transactionVersions [\"1\", 0]: a stringified version is not a valid entry, so the client fails with unsupported_transaction_version rather than reading it as 1 or skipping it. The build judge verifies the header with a Rust sponsor accepting the offer's versions and compares the message version and header config with the kit's build.", + "expect": { + "outcome": "reject", + "rejectCode": "unsupported-version", + "rejectReason": "unsupported_transaction_version: string entry" + }, + "id": "x402-build-string-entry-reject", + "input": { + "rpcFixtures": { + "mints": { + "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU": { + "decimals": 6, + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + } + }, + "recentBlockhash": "11111111111111111111111111111111" + }, + "signerSecretKey": [ + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 234, + 74, + 108, + 99, + 226, + 156, + 82, + 10, + 190, + 245, + 80, + 123, + 19, + 46, + 197, + 249, + 149, + 71, + 118, + 174, + 190, + 190, + 123, + 146, + 66, + 30, + 234, + 105, + 20, + 70, + 210, + 44 + ], + "x402Offer": { + "amount": "1000", + "asset": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "extra": { + "feePayer": "7v54NWdBtkjuAFJrLGsS2SXnuk8nKam81mZJeeYxVFi9", + "transactionVersions": [ + "1", + 0 + ] + }, + "maxTimeoutSeconds": 300, + "network": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "payTo": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "scheme": "exact" + }, + "x402Version": 2 + }, + "intent": "x402-exact", + "mode": "build-transaction", + "provenance": "authored", + "requirements": [ + "X402TX-927d17b62e" + ], + "role": "client", + "spec": { + "doc": "x402-txv1/specs/schemes/exact/scheme_exact_svm.md", + "quote": "A client or server MUST treat a field containing any non-integer entry (a string, null, or \"legacy\") or any integer other than 0 or 1 as invalid and fail closed with unsupported_transaction_version.", + "section": "1.5 Transaction Versions (MUST)" + }, + "tier": "offline" + }, { "bugType": "defaults", "description": "extra.transactionVersions [\"legacy\"]: clients MUST NOT build legacy, so nothing in the advertisement is buildable and the client fails with unsupported_transaction_version. The build judge verifies the header with a Rust sponsor accepting the offer's versions and compares the message version and header config with the kit's build.", @@ -1001,64 +1234,393 @@ 80, 123, 19, - 46, + 46, + 197, + 249, + 149, + 71, + 118, + 174, + 190, + 190, + 123, + 146, + 66, + 30, + 234, + 105, + 20, + 70, + 210, + 44 + ], + "x402Offer": { + "amount": "1000", + "asset": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "extra": { + "feePayer": "7v54NWdBtkjuAFJrLGsS2SXnuk8nKam81mZJeeYxVFi9", + "transactionVersions": [ + "legacy" + ] + }, + "maxTimeoutSeconds": 300, + "network": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "payTo": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "scheme": "exact" + }, + "x402Version": 2 + }, + "intent": "x402-exact", + "mode": "build-transaction", + "provenance": "authored", + "requirements": [ + "X402TX-77742f428c", + "X402TX-2909c4b4ec" + ], + "role": "client", + "spec": { + "doc": "x402-txv1/specs/schemes/exact/scheme_exact_svm.md", + "quote": "They are never advertised in extra.transactionVersions and clients MUST NOT build them.", + "section": "1.5 Transaction Versions (MUST)" + }, + "tier": "offline" + }, + { + "bugType": "wire", + "description": "A sponsor accepting [0, 1] verifies the version-1 static layout (TransferChecked, Memo; computeUnitLimit 200000, priorityFee 1 lamport, maximum loadedAccountsDataSizeLimit in the header): accepted.", + "expect": { + "outcome": "accept" + }, + "id": "x402-verify-v1-accept", + "input": { + "rpcFixtures": { + "mints": { + "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU": { + "decimals": 6, + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + } + }, + "recentBlockhash": "11111111111111111111111111111111" + }, + "x402PaymentHeader": "eyJ4NDAyVmVyc2lvbiI6MiwiYWNjZXB0ZWQiOnsic2NoZW1lIjoiZXhhY3QiLCJuZXR3b3JrIjoic29sYW5hOkV0V1RSQUJaYVlxNmlNZmVZS291UnUxNjZWVTJ4cWExIiwiYW1vdW50IjoiMTAwMCIsImFzc2V0IjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJwYXlUbyI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwibWF4VGltZW91dFNlY29uZHMiOjMwMCwiZXh0cmEiOnsiZmVlUGF5ZXIiOiJKMnhjY1J0dUc0M2RyRVNMWXpuSGhMaFFrTFRkZmVwY0tZYmlROUJzSlZhZiIsInRyYW5zYWN0aW9uVmVyc2lvbnMiOlswLDFdfX0sInBheWxvYWQiOnsidHJhbnNhY3Rpb24iOiJnUUlCQXc4QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFJSC9SY2tPRnFneDF0ayszak5ZQytoMlpIOTYvZHJFOFdPMXdMcXlEWHA5aGpxU214ajRweFNDcjcxVUhzVExzWDVsVWQycnI2K2U1SkNIdXBwRkViU0xBWFMvMWxXNlZ1R1E2eEFmMjIxYnE0bU9YU1FYUkFqNXgyajNsTW80Y3BiYTRUK1ZBV1prS2JxSXdqY1pZaFZyWldLWlI0VVZ5WWo5L3JUazl1d0Urd0ZTbE5hbVNraEJrMGs2SEZnMmpoOGZEVzEzYnlTdTRIa0g2aEFRUVZFalFiZDl1SFhaYUdUMmN2aFJzN3JlYXdjdElYdFgxczNrVHFNOVlWKy93Q3BPMFFzczVFaFYvRTZrejBCTkNndEF5dGYvczBCb3R2eHQza0dDTjhBTHFjQkFBQUFBQUFBQUVBTkF3QUFBQUFFQlFRS0FBUUFJQUFEQmdJQkRPZ0RBQUFBQUFBQUJuZzBNREoyWlhKcFpubDJNV0ZqWTJVd01EQXdNREF3TURBd01EQXdNREF3QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUNIYW5GdFdPK2VYUFJrWWNNYzE3ek4zOUNMQmxtQUxObVl2OXhGRlgvQ3krVWdReFV1cUpodm9HT0FyY0dSL0NYaXN5MGNoTDhmWlVSTWYzdVRnWWc4PSJ9fQ==", + "x402ServerAmount": "1000", + "x402ServerCurrency": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "x402ServerFeePayer": "J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf", + "x402ServerFeePayerSecretKey": [ + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 253, + 23, + 36, + 56, + 90, + 160, + 199, + 91, + 100, + 251, + 120, + 205, + 96, + 47, + 161, + 217, + 145, + 253, + 235, + 247, + 107, + 19, + 197, + 142, + 215, + 2, + 234, + 200, + 53, + 233, + 246, + 24 + ], + "x402ServerNetwork": "devnet", + "x402ServerRecipient": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "x402ServerTransactionVersions": [ + 0, + 1 + ] + }, + "intent": "x402-exact", + "mode": "verify-transaction", + "provenance": "generated", + "requirements": [ + "X402TX-24efe57db3", + "X402TX-10b3fe2ef3", + "X402TX-4c2fd60e66" + ], + "role": "server", + "spec": { + "doc": "x402-txv1/specs/schemes/exact/scheme_exact_svm.md", + "quote": "The sponsor MUST reject a message whose version is outside the set it accepts, before inspecting any instruction, with unsupported_transaction_version.", + "section": "1.5 Transaction Versions (MUST)" + }, + "tier": "offline" + }, + { + "bugType": "auth-bypass", + "description": "A sponsor whose accepted set is [0] receives the same valid version-1 transaction: rejected with unsupported_transaction_version before any instruction is inspected. The set is stated explicitly (input.x402ServerTransactionVersions): §1.5 gives the sponsor's own set no default. Pair: x402-verify-v1-accept.", + "expect": { + "outcome": "reject", + "rejectCode": "unsupported-version", + "rejectReason": "unsupported_transaction_version" + }, + "id": "x402-verify-v1-not-accepted-reject", + "input": { + "rpcFixtures": { + "mints": { + "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU": { + "decimals": 6, + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + } + }, + "recentBlockhash": "11111111111111111111111111111111" + }, + "x402PaymentHeader": "eyJ4NDAyVmVyc2lvbiI6MiwiYWNjZXB0ZWQiOnsic2NoZW1lIjoiZXhhY3QiLCJuZXR3b3JrIjoic29sYW5hOkV0V1RSQUJaYVlxNmlNZmVZS291UnUxNjZWVTJ4cWExIiwiYW1vdW50IjoiMTAwMCIsImFzc2V0IjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJwYXlUbyI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwibWF4VGltZW91dFNlY29uZHMiOjMwMCwiZXh0cmEiOnsiZmVlUGF5ZXIiOiJKMnhjY1J0dUc0M2RyRVNMWXpuSGhMaFFrTFRkZmVwY0tZYmlROUJzSlZhZiJ9fSwicGF5bG9hZCI6eyJ0cmFuc2FjdGlvbiI6ImdRSUJBdzhBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUlIL1Jja09GcWd4MXRrKzNqTllDK2gyWkg5Ni9kckU4V08xd0xxeURYcDloanFTbXhqNHB4U0NyNzFVSHNUTHNYNWxVZDJycjYrZTVKQ0h1cHBGRWJTTEFYUy8xbFc2VnVHUTZ4QWYyMjFicTRtT1hTUVhSQWo1eDJqM2xNbzRjcGJhNFQrVkFXWmtLYnFJd2pjWlloVnJaV0taUjRVVnlZajkvclRrOXV3RSt3RlNsTmFtU2toQmswazZIRmcyamg4ZkRXMTNieVN1NEhrSDZoQVFRVkVqUWJkOXVIWFphR1QyY3ZoUnM3cmVhd2N0SVh0WDFzM2tUcU05WVYrL3dDcE8wUXNzNUVoVi9FNmt6MEJOQ2d0QXl0Zi9zMEJvdHZ4dDNrR0NOOEFMcWNCQUFBQUFBQUFBRUFOQXdBQUFBQUVCUVFLQUFRQUlBQURCZ0lCRE9nREFBQUFBQUFBQm5nME1ESjJaWEpwWm5sMk1XNXZkR0V3TURBd01EQXdNREF3TURBd01EQXdBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBSjNMaXQ5ZllJazQ4bTNqZTlRcURHMjAvczF5dTJZNEhJUTNwWUVDUTlpc2Vubnc0YlNHV2kxV3dmdWxUVTJsWklOdkdTUGVKN1JjNVJ3Qmt3TlBvUU09In19", + "x402ServerAmount": "1000", + "x402ServerCurrency": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "x402ServerFeePayer": "J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf", + "x402ServerFeePayerSecretKey": [ + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 253, + 23, + 36, + 56, + 90, + 160, + 199, + 91, + 100, + 251, + 120, + 205, + 96, + 47, + 161, + 217, + 145, + 253, + 235, + 247, + 107, + 19, + 197, + 142, + 215, + 2, + 234, + 200, + 53, + 233, + 246, + 24 + ], + "x402ServerNetwork": "devnet", + "x402ServerRecipient": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "x402ServerTransactionVersions": [ + 0 + ] + }, + "intent": "x402-exact", + "mode": "verify-transaction", + "provenance": "generated", + "requirements": [ + "X402TX-24efe57db3", + "X402TX-10b3fe2ef3" + ], + "role": "server", + "spec": { + "doc": "x402-txv1/specs/schemes/exact/scheme_exact_svm.md", + "quote": "The sponsor MUST reject a message whose version is outside the set it accepts, before inspecting any instruction, with unsupported_transaction_version.", + "section": "1.5 Transaction Versions (MUST)" + }, + "tier": "offline" + }, + { + "bugType": "auth-bypass", + "description": "A sponsor configured with [0] explicitly receives a version-1 transaction.", + "expect": { + "outcome": "reject", + "rejectCode": "unsupported-version", + "rejectReason": "unsupported_transaction_version" + }, + "id": "x402-verify-v1-explicit-v0-sponsor-reject", + "input": { + "rpcFixtures": { + "mints": { + "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU": { + "decimals": 6, + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + } + }, + "recentBlockhash": "11111111111111111111111111111111" + }, + "x402PaymentHeader": "eyJ4NDAyVmVyc2lvbiI6MiwiYWNjZXB0ZWQiOnsic2NoZW1lIjoiZXhhY3QiLCJuZXR3b3JrIjoic29sYW5hOkV0V1RSQUJaYVlxNmlNZmVZS291UnUxNjZWVTJ4cWExIiwiYW1vdW50IjoiMTAwMCIsImFzc2V0IjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJwYXlUbyI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwibWF4VGltZW91dFNlY29uZHMiOjMwMCwiZXh0cmEiOnsiZmVlUGF5ZXIiOiJKMnhjY1J0dUc0M2RyRVNMWXpuSGhMaFFrTFRkZmVwY0tZYmlROUJzSlZhZiJ9fSwicGF5bG9hZCI6eyJ0cmFuc2FjdGlvbiI6ImdRSUJBdzhBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUlIL1Jja09GcWd4MXRrKzNqTllDK2gyWkg5Ni9kckU4V08xd0xxeURYcDloanFTbXhqNHB4U0NyNzFVSHNUTHNYNWxVZDJycjYrZTVKQ0h1cHBGRWJTTEFYUy8xbFc2VnVHUTZ4QWYyMjFicTRtT1hTUVhSQWo1eDJqM2xNbzRjcGJhNFQrVkFXWmtLYnFJd2pjWlloVnJaV0taUjRVVnlZajkvclRrOXV3RSt3RlNsTmFtU2toQmswazZIRmcyamg4ZkRXMTNieVN1NEhrSDZoQVFRVkVqUWJkOXVIWFphR1QyY3ZoUnM3cmVhd2N0SVh0WDFzM2tUcU05WVYrL3dDcE8wUXNzNUVoVi9FNmt6MEJOQ2d0QXl0Zi9zMEJvdHZ4dDNrR0NOOEFMcWNCQUFBQUFBQUFBRUFOQXdBQUFBQUVCUVFLQUFRQUlBQURCZ0lCRE9nREFBQUFBQUFBQm5nME1ESjJaWEpwWm5sMk1XVjRjR3d3TURBd01EQXdNREF3TURBd01EQXdBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT0NuRUZxNjFvR0ppWFhiWEZhSW9PTzR6S01RY09rY051Ukd0cTA2dDUyZVVJdzFQaW9wb0lIaEdRTVZkM0FVZC9EeEc2WEVZQnUrUWhPaUxac1c0QUE9In19", + "x402ServerAmount": "1000", + "x402ServerCurrency": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "x402ServerFeePayer": "J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf", + "x402ServerFeePayerSecretKey": [ + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 253, + 23, + 36, + 56, + 90, + 160, + 199, + 91, + 100, + 251, + 120, + 205, + 96, + 47, + 161, + 217, + 145, + 253, + 235, + 247, + 107, + 19, 197, - 249, - 149, - 71, - 118, - 174, - 190, - 190, - 123, - 146, - 66, - 30, + 142, + 215, + 2, 234, - 105, - 20, - 70, - 210, - 44 + 200, + 53, + 233, + 246, + 24 ], - "x402Offer": { - "amount": "1000", - "asset": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", - "extra": { - "feePayer": "7v54NWdBtkjuAFJrLGsS2SXnuk8nKam81mZJeeYxVFi9", - "transactionVersions": [ - "legacy" - ] - }, - "maxTimeoutSeconds": 300, - "network": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", - "payTo": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", - "scheme": "exact" - }, - "x402Version": 2 + "x402ServerNetwork": "devnet", + "x402ServerRecipient": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "x402ServerTransactionVersions": [ + 0 + ] }, "intent": "x402-exact", - "mode": "build-transaction", - "provenance": "authored", + "mode": "verify-transaction", + "provenance": "generated", "requirements": [ - "X402TX-77742f428c", - "X402TX-2909c4b4ec" + "X402TX-24efe57db3" ], - "role": "client", + "role": "server", "spec": { "doc": "x402-txv1/specs/schemes/exact/scheme_exact_svm.md", - "quote": "They are never advertised in extra.transactionVersions and clients MUST NOT build them.", + "quote": "The sponsor MUST reject a message whose version is outside the set it accepts, before inspecting any instruction, with unsupported_transaction_version.", "section": "1.5 Transaction Versions (MUST)" }, "tier": "offline" }, { "bugType": "wire", - "description": "A sponsor accepting [0, 1] verifies the version-1 static layout (TransferChecked, Memo; computeUnitLimit 200000, priorityFee 1 lamport, maximum loadedAccountsDataSizeLimit in the header): accepted.", + "description": "A sponsor accepting [0, 1] still accepts the version-0 static layout, with extra.transactionVersions [0, 1] echoed in accepted.", "expect": { "outcome": "accept" }, - "id": "x402-verify-v1-accept", + "id": "x402-verify-v0-with-v1-sponsor-accept", "input": { "rpcFixtures": { "mints": { @@ -1069,7 +1631,7 @@ }, "recentBlockhash": "11111111111111111111111111111111" }, - "x402PaymentHeader": "eyJ4NDAyVmVyc2lvbiI6MiwiYWNjZXB0ZWQiOnsic2NoZW1lIjoiZXhhY3QiLCJuZXR3b3JrIjoic29sYW5hOkV0V1RSQUJaYVlxNmlNZmVZS291UnUxNjZWVTJ4cWExIiwiYW1vdW50IjoiMTAwMCIsImFzc2V0IjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJwYXlUbyI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwibWF4VGltZW91dFNlY29uZHMiOjMwMCwiZXh0cmEiOnsiZmVlUGF5ZXIiOiJKMnhjY1J0dUc0M2RyRVNMWXpuSGhMaFFrTFRkZmVwY0tZYmlROUJzSlZhZiIsInRyYW5zYWN0aW9uVmVyc2lvbnMiOlswLDFdfX0sInBheWxvYWQiOnsidHJhbnNhY3Rpb24iOiJnUUlCQXc4QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFJSC9SY2tPRnFneDF0ayszak5ZQytoMlpIOTYvZHJFOFdPMXdMcXlEWHA5aGpxU214ajRweFNDcjcxVUhzVExzWDVsVWQycnI2K2U1SkNIdXBwRkViU0xBWFMvMWxXNlZ1R1E2eEFmMjIxYnE0bU9YU1FYUkFqNXgyajNsTW80Y3BiYTRUK1ZBV1prS2JxSXdqY1pZaFZyWldLWlI0VVZ5WWo5L3JUazl1d0Urd0ZTbE5hbVNraEJrMGs2SEZnMmpoOGZEVzEzYnlTdTRIa0g2aEFRUVZFalFiZDl1SFhaYUdUMmN2aFJzN3JlYXdjdElYdFgxczNrVHFNOVlWKy93Q3BPMFFzczVFaFYvRTZrejBCTkNndEF5dGYvczBCb3R2eHQza0dDTjhBTHFjQkFBQUFBQUFBQUVBTkF3QUFBQUFFQlFRS0FBUUFJQUFEQmdJQkRPZ0RBQUFBQUFBQUJuZzBNREoyWlhKcFpubDJNV0ZqWTJVd01EQXdNREF3TURBd01EQXdNREF3QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUNIYW5GdFdPK2VYUFJrWWNNYzE3ek4zOUNMQmxtQUxObVl2OXhGRlgvQ3krVWdReFV1cUpodm9HT0FyY0dSL0NYaXN5MGNoTDhmWlVSTWYzdVRnWWc4PSJ9fQ==", + "x402PaymentHeader": "eyJ4NDAyVmVyc2lvbiI6MiwiYWNjZXB0ZWQiOnsic2NoZW1lIjoiZXhhY3QiLCJuZXR3b3JrIjoic29sYW5hOkV0V1RSQUJaYVlxNmlNZmVZS291UnUxNjZWVTJ4cWExIiwiYW1vdW50IjoiMTAwMCIsImFzc2V0IjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJwYXlUbyI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwibWF4VGltZW91dFNlY29uZHMiOjMwMCwiZXh0cmEiOnsiZmVlUGF5ZXIiOiJKMnhjY1J0dUc0M2RyRVNMWXpuSGhMaFFrTFRkZmVwY0tZYmlROUJzSlZhZiIsInRyYW5zYWN0aW9uVmVyc2lvbnMiOlswLDFdfX0sInBheWxvYWQiOnsidHJhbnNhY3Rpb24iOiJBZ0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUQxVGtXVTByUnl0dzQ4bDI1NHltdGVwSjVPbGlzOE40cmRhN3V5WExCMGIveURRQ3NSUXFzemVvUU5NY2IwN1pzOTR5bi91V0VVRjhwcjRpQW9kTzhBZ0FJQkJBajlGeVE0V3FESFcyVDdlTTFnTDZIWmtmM3I5MnNUeFk3WEF1cklOZW4yR09wS2JHUGluRklLdnZWUWV4TXV4Zm1WUjNhdXZyNTdra0llNm1rVVJ0SXNCZEwvV1ZicFc0WkRyRUIvYmJWdXJpWTVkSkJkRUNQbkhhUGVVeWpoeWx0cmhQNVVCWm1RcHVvakNOeGxpRld0bFlwbEhoUlhKaVAzK3RPVDI3QVQ3QU1HUm0vbElSY3kvK3l0dW5MRG0rZThqT1c3eGZjU2F5eERtenBBQUFBQUJVcFRXcGtwSVFaTkpPaHhZTm80Zkh3MXRkMjhrcnVCNUIrb1FFRUZSSTBHM2ZiaDEyV2hrOW5MNFViTzYzbXNITFNGN1Y5Yk41RTZqUFdGZnY4QXFUdEVMTE9SSVZmeE9wTTlBVFFvTFFNclgvN05BYUxiOGJkNUJnamZBQzZuQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUVCQUFGQWtBTkF3QUVBQWtEQVFBQUFBQUFBQUFHQkFNSEFnRUtET2dEQUFBQUFBQUFCZ1VBSUhnME1ESjJaWEpwWm5sMk1IZHBkR2d3TURBd01EQXdNREF3TURBd01EQXdBQT09In19", "x402ServerAmount": "1000", "x402ServerCurrency": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", "x402ServerFeePayer": "J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf", @@ -1151,8 +1713,7 @@ "provenance": "generated", "requirements": [ "X402TX-24efe57db3", - "X402TX-10b3fe2ef3", - "X402TX-d188782061" + "X402TX-10b3fe2ef3" ], "role": "server", "spec": { @@ -1163,14 +1724,12 @@ "tier": "offline" }, { - "bugType": "auth-bypass", - "description": "A sponsor with the default accepted set [0] receives the same valid version-1 transaction: rejected with unsupported_transaction_version before any instruction is inspected. Pair: x402-verify-v1-accept.", + "bugType": "wire", + "description": "Version-1 static layout whose Memo nonce is 1300 hex characters: about 1.6 KB serialized, over version 0's 1232 bytes but within version 1's 4096. Accepted. Mutation: memo #0 replaced with 1300 hex characters.", "expect": { - "outcome": "reject", - "rejectCode": "unsupported-version", - "rejectReason": "unsupported_transaction_version" + "outcome": "accept" }, - "id": "x402-verify-v1-not-accepted-reject", + "id": "x402-verify-v1-over-1232-accept", "input": { "rpcFixtures": { "mints": { @@ -1181,7 +1740,7 @@ }, "recentBlockhash": "11111111111111111111111111111111" }, - "x402PaymentHeader": "eyJ4NDAyVmVyc2lvbiI6MiwiYWNjZXB0ZWQiOnsic2NoZW1lIjoiZXhhY3QiLCJuZXR3b3JrIjoic29sYW5hOkV0V1RSQUJaYVlxNmlNZmVZS291UnUxNjZWVTJ4cWExIiwiYW1vdW50IjoiMTAwMCIsImFzc2V0IjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJwYXlUbyI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwibWF4VGltZW91dFNlY29uZHMiOjMwMCwiZXh0cmEiOnsiZmVlUGF5ZXIiOiJKMnhjY1J0dUc0M2RyRVNMWXpuSGhMaFFrTFRkZmVwY0tZYmlROUJzSlZhZiJ9fSwicGF5bG9hZCI6eyJ0cmFuc2FjdGlvbiI6ImdRSUJBdzhBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUlIL1Jja09GcWd4MXRrKzNqTllDK2gyWkg5Ni9kckU4V08xd0xxeURYcDloanFTbXhqNHB4U0NyNzFVSHNUTHNYNWxVZDJycjYrZTVKQ0h1cHBGRWJTTEFYUy8xbFc2VnVHUTZ4QWYyMjFicTRtT1hTUVhSQWo1eDJqM2xNbzRjcGJhNFQrVkFXWmtLYnFJd2pjWlloVnJaV0taUjRVVnlZajkvclRrOXV3RSt3RlNsTmFtU2toQmswazZIRmcyamg4ZkRXMTNieVN1NEhrSDZoQVFRVkVqUWJkOXVIWFphR1QyY3ZoUnM3cmVhd2N0SVh0WDFzM2tUcU05WVYrL3dDcE8wUXNzNUVoVi9FNmt6MEJOQ2d0QXl0Zi9zMEJvdHZ4dDNrR0NOOEFMcWNCQUFBQUFBQUFBRUFOQXdBQUFBQUVCUVFLQUFRQUlBQURCZ0lCRE9nREFBQUFBQUFBQm5nME1ESjJaWEpwWm5sMk1XNXZkR0V3TURBd01EQXdNREF3TURBd01EQXdBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBSjNMaXQ5ZllJazQ4bTNqZTlRcURHMjAvczF5dTJZNEhJUTNwWUVDUTlpc2Vubnc0YlNHV2kxV3dmdWxUVTJsWklOdkdTUGVKN1JjNVJ3Qmt3TlBvUU09In19", + "x402PaymentHeader": "eyJ4NDAyVmVyc2lvbiI6MiwiYWNjZXB0ZWQiOnsic2NoZW1lIjoiZXhhY3QiLCJuZXR3b3JrIjoic29sYW5hOkV0V1RSQUJaYVlxNmlNZmVZS291UnUxNjZWVTJ4cWExIiwiYW1vdW50IjoiMTAwMCIsImFzc2V0IjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJwYXlUbyI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwibWF4VGltZW91dFNlY29uZHMiOjMwMCwiZXh0cmEiOnsiZmVlUGF5ZXIiOiJKMnhjY1J0dUc0M2RyRVNMWXpuSGhMaFFrTFRkZmVwY0tZYmlROUJzSlZhZiIsInRyYW5zYWN0aW9uVmVyc2lvbnMiOlswLDFdfX0sInBheWxvYWQiOnsidHJhbnNhY3Rpb24iOiJnUUlCQXc4QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFJSC9SY2tPRnFneDF0ayszak5ZQytoMlpIOTYvZHJFOFdPMXdMcXlEWHA5aGpxU214ajRweFNDcjcxVUhzVExzWDVsVWQycnI2K2U1SkNIdXBwRkViU0xBWFMvMWxXNlZ1R1E2eEFmMjIxYnE0bU9YU1FYUkFqNXgyajNsTW80Y3BiYTRUK1ZBV1prS2JxSXdqY1pZaFZyWldLWlI0VVZ5WWo5L3JUazl1d0Urd0ZTbE5hbVNraEJrMGs2SEZnMmpoOGZEVzEzYnlTdTRIa0g2aEFRUVZFalFiZDl1SFhaYUdUMmN2aFJzN3JlYXdjdElYdFgxczNrVHFNOVlWKy93Q3BPMFFzczVFaFYvRTZrejBCTkNndEF5dGYvczBCb3R2eHQza0dDTjhBTHFjQkFBQUFBQUFBQUVBTkF3QUFBQUFFQlFRS0FBUUFGQVVEQmdJQkRPZ0RBQUFBQUFBQUJqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak1BQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBb0dVMDVHSWZyb2tET2tvd1FaRzYxOWgzYjZsZmdibEJlNEFVV2htelRaTVlEbXIxazNIQk9CT2swZkQvYk5VT09PRWd1Q3hNcERwN2wxOElFR2hNREE9PSJ9fQ==", "x402ServerAmount": "1000", "x402ServerCurrency": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", "x402ServerFeePayer": "J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf", @@ -1252,32 +1811,36 @@ 24 ], "x402ServerNetwork": "devnet", - "x402ServerRecipient": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY" + "x402ServerRecipient": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "x402ServerTransactionVersions": [ + 0, + 1 + ] }, "intent": "x402-exact", "mode": "verify-transaction", "provenance": "generated", "requirements": [ - "X402TX-24efe57db3", - "X402TX-10b3fe2ef3" + "X402TX-dc7b0f3305", + "X402TX-4c2fd60e66" ], "role": "server", "spec": { "doc": "x402-txv1/specs/schemes/exact/scheme_exact_svm.md", - "quote": "The sponsor MUST reject a message whose version is outside the set it accepts, before inspecting any instruction, with unsupported_transaction_version.", + "quote": "A legacy or version-0 transaction MUST NOT exceed 1232 serialized bytes; a version-1 transaction MUST NOT exceed 4096 serialized bytes.", "section": "1.5 Transaction Versions (MUST)" }, "tier": "offline" }, { - "bugType": "auth-bypass", - "description": "A sponsor configured with [0] explicitly receives a version-1 transaction.", + "bugType": "wire", + "description": "The same 1300-character Memo in a version-0 static layout: over 1232 bytes, rejected whatever else the sponsor accepts. Pair: x402-verify-v1-over-1232-accept. Mutation: memo #0 replaced with 1300 hex characters.", "expect": { "outcome": "reject", - "rejectCode": "unsupported-version", - "rejectReason": "unsupported_transaction_version" + "rejectCode": "invalid-payload", + "rejectReason": "a version-0 transaction over 1232 bytes" }, - "id": "x402-verify-v1-explicit-v0-sponsor-reject", + "id": "x402-verify-v0-over-1232-reject", "input": { "rpcFixtures": { "mints": { @@ -1288,7 +1851,7 @@ }, "recentBlockhash": "11111111111111111111111111111111" }, - "x402PaymentHeader": "eyJ4NDAyVmVyc2lvbiI6MiwiYWNjZXB0ZWQiOnsic2NoZW1lIjoiZXhhY3QiLCJuZXR3b3JrIjoic29sYW5hOkV0V1RSQUJaYVlxNmlNZmVZS291UnUxNjZWVTJ4cWExIiwiYW1vdW50IjoiMTAwMCIsImFzc2V0IjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJwYXlUbyI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwibWF4VGltZW91dFNlY29uZHMiOjMwMCwiZXh0cmEiOnsiZmVlUGF5ZXIiOiJKMnhjY1J0dUc0M2RyRVNMWXpuSGhMaFFrTFRkZmVwY0tZYmlROUJzSlZhZiJ9fSwicGF5bG9hZCI6eyJ0cmFuc2FjdGlvbiI6ImdRSUJBdzhBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUlIL1Jja09GcWd4MXRrKzNqTllDK2gyWkg5Ni9kckU4V08xd0xxeURYcDloanFTbXhqNHB4U0NyNzFVSHNUTHNYNWxVZDJycjYrZTVKQ0h1cHBGRWJTTEFYUy8xbFc2VnVHUTZ4QWYyMjFicTRtT1hTUVhSQWo1eDJqM2xNbzRjcGJhNFQrVkFXWmtLYnFJd2pjWlloVnJaV0taUjRVVnlZajkvclRrOXV3RSt3RlNsTmFtU2toQmswazZIRmcyamg4ZkRXMTNieVN1NEhrSDZoQVFRVkVqUWJkOXVIWFphR1QyY3ZoUnM3cmVhd2N0SVh0WDFzM2tUcU05WVYrL3dDcE8wUXNzNUVoVi9FNmt6MEJOQ2d0QXl0Zi9zMEJvdHZ4dDNrR0NOOEFMcWNCQUFBQUFBQUFBRUFOQXdBQUFBQUVCUVFLQUFRQUlBQURCZ0lCRE9nREFBQUFBQUFBQm5nME1ESjJaWEpwWm5sMk1XVjRjR3d3TURBd01EQXdNREF3TURBd01EQXdBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT0NuRUZxNjFvR0ppWFhiWEZhSW9PTzR6S01RY09rY051Ukd0cTA2dDUyZVVJdzFQaW9wb0lIaEdRTVZkM0FVZC9EeEc2WEVZQnUrUWhPaUxac1c0QUE9In19", + "x402PaymentHeader": "eyJ4NDAyVmVyc2lvbiI6MiwiYWNjZXB0ZWQiOnsic2NoZW1lIjoiZXhhY3QiLCJuZXR3b3JrIjoic29sYW5hOkV0V1RSQUJaYVlxNmlNZmVZS291UnUxNjZWVTJ4cWExIiwiYW1vdW50IjoiMTAwMCIsImFzc2V0IjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJwYXlUbyI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwibWF4VGltZW91dFNlY29uZHMiOjMwMCwiZXh0cmEiOnsiZmVlUGF5ZXIiOiJKMnhjY1J0dUc0M2RyRVNMWXpuSGhMaFFrTFRkZmVwY0tZYmlROUJzSlZhZiIsInRyYW5zYWN0aW9uVmVyc2lvbnMiOlswLDFdfX0sInBheWxvYWQiOnsidHJhbnNhY3Rpb24iOiJBZ0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUNNaUV1QlpUallKVERVQytuTHhqNjlBUTZjaDR5YjFpbXZQTmJ5TSs3aHFWT0lIZXFWSWVXcjhzUEYxaEx0RmZGZnhoMWJsYzJUYVF2c2crcFNFUXNMZ0FJQkJBajlGeVE0V3FESFcyVDdlTTFnTDZIWmtmM3I5MnNUeFk3WEF1cklOZW4yR09wS2JHUGluRklLdnZWUWV4TXV4Zm1WUjNhdXZyNTdra0llNm1rVVJ0SXNCZEwvV1ZicFc0WkRyRUIvYmJWdXJpWTVkSkJkRUNQbkhhUGVVeWpoeWx0cmhQNVVCWm1RcHVvakNOeGxpRld0bFlwbEhoUlhKaVAzK3RPVDI3QVQ3QU1HUm0vbElSY3kvK3l0dW5MRG0rZThqT1c3eGZjU2F5eERtenBBQUFBQUJVcFRXcGtwSVFaTkpPaHhZTm80Zkh3MXRkMjhrcnVCNUIrb1FFRUZSSTBHM2ZiaDEyV2hrOW5MNFViTzYzbXNITFNGN1Y5Yk41RTZqUFdGZnY4QXFUdEVMTE9SSVZmeE9wTTlBVFFvTFFNclgvN05BYUxiOGJkNUJnamZBQzZuQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUVCQUFGQWtBTkF3QUVBQWtEQVFBQUFBQUFBQUFHQkFNSEFnRUtET2dEQUFBQUFBQUFCZ1VBbEFvd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpBQT09In19", "x402ServerAmount": "1000", "x402ServerCurrency": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", "x402ServerFeePayer": "J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf", @@ -1361,30 +1924,33 @@ "x402ServerNetwork": "devnet", "x402ServerRecipient": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", "x402ServerTransactionVersions": [ - 0 + 0, + 1 ] }, "intent": "x402-exact", "mode": "verify-transaction", - "provenance": "generated", + "provenance": "authored", "requirements": [ - "X402TX-24efe57db3" + "X402TX-dc7b0f3305" ], "role": "server", "spec": { "doc": "x402-txv1/specs/schemes/exact/scheme_exact_svm.md", - "quote": "The sponsor MUST reject a message whose version is outside the set it accepts, before inspecting any instruction, with unsupported_transaction_version.", + "quote": "A legacy or version-0 transaction MUST NOT exceed 1232 serialized bytes; a version-1 transaction MUST NOT exceed 4096 serialized bytes.", "section": "1.5 Transaction Versions (MUST)" }, "tier": "offline" }, { "bugType": "wire", - "description": "A sponsor accepting [0, 1] still accepts the version-0 static layout, with extra.transactionVersions [0, 1] echoed in accepted.", + "description": "Version-1 static layout with a 4000-character Memo: over the 4096-byte version-1 limit. Pair: x402-verify-v1-over-1232-accept. Mutation: memo #0 replaced with 4000 hex characters.", "expect": { - "outcome": "accept" + "outcome": "reject", + "rejectCode": "invalid-payload", + "rejectReason": "a version-1 transaction over 4096 bytes" }, - "id": "x402-verify-v0-with-v1-sponsor-accept", + "id": "x402-verify-v1-over-4096-reject", "input": { "rpcFixtures": { "mints": { @@ -1395,7 +1961,7 @@ }, "recentBlockhash": "11111111111111111111111111111111" }, - "x402PaymentHeader": "eyJ4NDAyVmVyc2lvbiI6MiwiYWNjZXB0ZWQiOnsic2NoZW1lIjoiZXhhY3QiLCJuZXR3b3JrIjoic29sYW5hOkV0V1RSQUJaYVlxNmlNZmVZS291UnUxNjZWVTJ4cWExIiwiYW1vdW50IjoiMTAwMCIsImFzc2V0IjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJwYXlUbyI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwibWF4VGltZW91dFNlY29uZHMiOjMwMCwiZXh0cmEiOnsiZmVlUGF5ZXIiOiJKMnhjY1J0dUc0M2RyRVNMWXpuSGhMaFFrTFRkZmVwY0tZYmlROUJzSlZhZiIsInRyYW5zYWN0aW9uVmVyc2lvbnMiOlswLDFdfX0sInBheWxvYWQiOnsidHJhbnNhY3Rpb24iOiJBZ0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUQxVGtXVTByUnl0dzQ4bDI1NHltdGVwSjVPbGlzOE40cmRhN3V5WExCMGIveURRQ3NSUXFzemVvUU5NY2IwN1pzOTR5bi91V0VVRjhwcjRpQW9kTzhBZ0FJQkJBajlGeVE0V3FESFcyVDdlTTFnTDZIWmtmM3I5MnNUeFk3WEF1cklOZW4yR09wS2JHUGluRklLdnZWUWV4TXV4Zm1WUjNhdXZyNTdra0llNm1rVVJ0SXNCZEwvV1ZicFc0WkRyRUIvYmJWdXJpWTVkSkJkRUNQbkhhUGVVeWpoeWx0cmhQNVVCWm1RcHVvakNOeGxpRld0bFlwbEhoUlhKaVAzK3RPVDI3QVQ3QU1HUm0vbElSY3kvK3l0dW5MRG0rZThqT1c3eGZjU2F5eERtenBBQUFBQUJVcFRXcGtwSVFaTkpPaHhZTm80Zkh3MXRkMjhrcnVCNUIrb1FFRUZSSTBHM2ZiaDEyV2hrOW5MNFViTzYzbXNITFNGN1Y5Yk41RTZqUFdGZnY4QXFUdEVMTE9SSVZmeE9wTTlBVFFvTFFNclgvN05BYUxiOGJkNUJnamZBQzZuQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUVCQUFGQWtBTkF3QUVBQWtEQVFBQUFBQUFBQUFHQkFNSEFnRUtET2dEQUFBQUFBQUFCZ1VBSUhnME1ESjJaWEpwWm5sMk1IZHBkR2d3TURBd01EQXdNREF3TURBd01EQXdBQT09In19", + "x402PaymentHeader": "eyJ4NDAyVmVyc2lvbiI6MiwiYWNjZXB0ZWQiOnsic2NoZW1lIjoiZXhhY3QiLCJuZXR3b3JrIjoic29sYW5hOkV0V1RSQUJaYVlxNmlNZmVZS291UnUxNjZWVTJ4cWExIiwiYW1vdW50IjoiMTAwMCIsImFzc2V0IjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJwYXlUbyI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwibWF4VGltZW91dFNlY29uZHMiOjMwMCwiZXh0cmEiOnsiZmVlUGF5ZXIiOiJKMnhjY1J0dUc0M2RyRVNMWXpuSGhMaFFrTFRkZmVwY0tZYmlROUJzSlZhZiIsInRyYW5zYWN0aW9uVmVyc2lvbnMiOlswLDFdfX0sInBheWxvYWQiOnsidHJhbnNhY3Rpb24iOiJnUUlCQXc4QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFJSC9SY2tPRnFneDF0ayszak5ZQytoMlpIOTYvZHJFOFdPMXdMcXlEWHA5aGpxU214ajRweFNDcjcxVUhzVExzWDVsVWQycnI2K2U1SkNIdXBwRkViU0xBWFMvMWxXNlZ1R1E2eEFmMjIxYnE0bU9YU1FYUkFqNXgyajNsTW80Y3BiYTRUK1ZBV1prS2JxSXdqY1pZaFZyWldLWlI0VVZ5WWo5L3JUazl1d0Urd0ZTbE5hbVNraEJrMGs2SEZnMmpoOGZEVzEzYnlTdTRIa0g2aEFRUVZFalFiZDl1SFhaYUdUMmN2aFJzN3JlYXdjdElYdFgxczNrVHFNOVlWKy93Q3BPMFFzczVFaFYvRTZrejBCTkNndEF5dGYvczBCb3R2eHQza0dDTjhBTHFjQkFBQUFBQUFBQUVBTkF3QUFBQUFFQlFRS0FBUUFvQThEQmdJQkRPZ0RBQUFBQUFBQUJqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1lBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBNWJMdW81T2t6Zy9MS2pwejBMeDluZ3JkV0lyZWliVFlPSnA2MkV0UmQ2T05aYmFmVUtDek1RM0NkMmZNcGFsWUJ2SXpMTmxvZ3F3WHVDdEtWemkyQUE9PSJ9fQ==", "x402ServerAmount": "1000", "x402ServerCurrency": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", "x402ServerFeePayer": "J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf", @@ -1474,26 +2040,26 @@ }, "intent": "x402-exact", "mode": "verify-transaction", - "provenance": "generated", + "provenance": "authored", "requirements": [ - "X402TX-24efe57db3", - "X402TX-10b3fe2ef3" + "X402TX-dc7b0f3305" ], "role": "server", "spec": { "doc": "x402-txv1/specs/schemes/exact/scheme_exact_svm.md", - "quote": "The sponsor MUST reject a message whose version is outside the set it accepts, before inspecting any instruction, with unsupported_transaction_version.", + "quote": "A legacy or version-0 transaction MUST NOT exceed 1232 serialized bytes; a version-1 transaction MUST NOT exceed 4096 serialized bytes.", "section": "1.5 Transaction Versions (MUST)" }, "tier": "offline" }, { - "bugType": "wire", - "description": "Version-1 static layout whose Memo nonce is 1300 hex characters: about 1.6 KB serialized, over version 0's 1232 bytes but within version 1's 4096. Accepted. Mutation: memo #0 replaced with 1300 hex characters.", + "bugType": "settlement", + "description": "Version-1 static layout preceded by a SetComputeUnitLimit instruction: the runtime ignores it under version 1, so a sponsor bounding it bounds nothing. Pair: x402-verify-v1-accept. Mutation: ComputeBudget instruction with data [2, 64, 13, 3, 0] added.", "expect": { - "outcome": "accept" + "outcome": "reject", + "rejectCode": "invalid-payload" }, - "id": "x402-verify-v1-over-1232-accept", + "id": "x402-verify-v1-compute-budget-instruction-reject", "input": { "rpcFixtures": { "mints": { @@ -1504,7 +2070,7 @@ }, "recentBlockhash": "11111111111111111111111111111111" }, - "x402PaymentHeader": "eyJ4NDAyVmVyc2lvbiI6MiwiYWNjZXB0ZWQiOnsic2NoZW1lIjoiZXhhY3QiLCJuZXR3b3JrIjoic29sYW5hOkV0V1RSQUJaYVlxNmlNZmVZS291UnUxNjZWVTJ4cWExIiwiYW1vdW50IjoiMTAwMCIsImFzc2V0IjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJwYXlUbyI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwibWF4VGltZW91dFNlY29uZHMiOjMwMCwiZXh0cmEiOnsiZmVlUGF5ZXIiOiJKMnhjY1J0dUc0M2RyRVNMWXpuSGhMaFFrTFRkZmVwY0tZYmlROUJzSlZhZiIsInRyYW5zYWN0aW9uVmVyc2lvbnMiOlswLDFdfX0sInBheWxvYWQiOnsidHJhbnNhY3Rpb24iOiJnUUlCQXc4QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFJSC9SY2tPRnFneDF0ayszak5ZQytoMlpIOTYvZHJFOFdPMXdMcXlEWHA5aGpxU214ajRweFNDcjcxVUhzVExzWDVsVWQycnI2K2U1SkNIdXBwRkViU0xBWFMvMWxXNlZ1R1E2eEFmMjIxYnE0bU9YU1FYUkFqNXgyajNsTW80Y3BiYTRUK1ZBV1prS2JxSXdqY1pZaFZyWldLWlI0VVZ5WWo5L3JUazl1d0Urd0ZTbE5hbVNraEJrMGs2SEZnMmpoOGZEVzEzYnlTdTRIa0g2aEFRUVZFalFiZDl1SFhaYUdUMmN2aFJzN3JlYXdjdElYdFgxczNrVHFNOVlWKy93Q3BPMFFzczVFaFYvRTZrejBCTkNndEF5dGYvczBCb3R2eHQza0dDTjhBTHFjQkFBQUFBQUFBQUVBTkF3QUFBQUFFQlFRS0FBUUFGQVVEQmdJQkRPZ0RBQUFBQUFBQUJqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak1BQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBb0dVMDVHSWZyb2tET2tvd1FaRzYxOWgzYjZsZmdibEJlNEFVV2htelRaTVlEbXIxazNIQk9CT2swZkQvYk5VT09PRWd1Q3hNcERwN2wxOElFR2hNREE9PSJ9fQ==", + "x402PaymentHeader": "eyJ4NDAyVmVyc2lvbiI6MiwiYWNjZXB0ZWQiOnsic2NoZW1lIjoiZXhhY3QiLCJuZXR3b3JrIjoic29sYW5hOkV0V1RSQUJaYVlxNmlNZmVZS291UnUxNjZWVTJ4cWExIiwiYW1vdW50IjoiMTAwMCIsImFzc2V0IjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJwYXlUbyI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwibWF4VGltZW91dFNlY29uZHMiOjMwMCwiZXh0cmEiOnsiZmVlUGF5ZXIiOiJKMnhjY1J0dUc0M2RyRVNMWXpuSGhMaFFrTFRkZmVwY0tZYmlROUJzSlZhZiIsInRyYW5zYWN0aW9uVmVyc2lvbnMiOlswLDFdfX0sInBheWxvYWQiOnsidHJhbnNhY3Rpb24iOiJnUUlCQkE4QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFNSS9SY2tPRnFneDF0ayszak5ZQytoMlpIOTYvZHJFOFdPMXdMcXlEWHA5aGpxU214ajRweFNDcjcxVUhzVExzWDVsVWQycnI2K2U1SkNIdXBwRkViU0xBWFMvMWxXNlZ1R1E2eEFmMjIxYnE0bU9YU1FYUkFqNXgyajNsTW80Y3BiYTRUK1ZBV1prS2JxSXdqY1pZaFZyWldLWlI0VVZ5WWo5L3JUazl1d0Urd0RCa1p2NVNFWE12L3NyYnB5dzV2bnZJemx1OFgzRW1zc1E1czZRQUFBQUFWS1UxcVpLU0VHVFNUb2NXRGFPSHg4TmJYZHZKSzdnZVFmcUVCQkJVU05CdDMyNGRkbG9aUFp5K0ZHenV0NXJCeTBoZTFmV3plUk9vejFoWDcvQUtrN1JDeXprU0ZYOFRxVFBRRTBLQzBESzEvK3pRR2kyL0czZVFZSTN3QXVwd0VBQUFBQUFBQUFRQTBEQUFBQUFBUUVBQVVBQmdRS0FBVUFJQUFDUUEwREFBTUhBZ0VNNkFNQUFBQUFBQUFHZURRd01uWmxjbWxtZVhZeFkyOXRjREF3TURBd01EQXdNREF3TURBd01EQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFpY1hLSkJhQXorcW94VFhpQ01pREdxZEpUZk1JakxCelZrMVY0VEZMM0VDTmxDNVQ5N3QrNkVVUkRldU9uQmVXcUI3TDJBSzU1eVNKcU9CK0x6dmhEUT09In19", "x402ServerAmount": "1000", "x402ServerCurrency": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", "x402ServerFeePayer": "J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf", @@ -1585,26 +2151,26 @@ "mode": "verify-transaction", "provenance": "generated", "requirements": [ - "X402TX-dc7b0f3305", - "X402TX-d188782061" + "X402TX-915632f040", + "X402TX-4cd70365fd", + "X402TX-f9bcc1a14a" ], "role": "server", "spec": { "doc": "x402-txv1/specs/schemes/exact/scheme_exact_svm.md", - "quote": "A legacy or version-0 transaction MUST NOT exceed 1232 serialized bytes; a version-1 transaction MUST NOT exceed 4096 serialized bytes.", - "section": "1.5 Transaction Versions (MUST)" + "quote": "A version-1 transaction that contains a Compute Budget instruction MUST be rejected (an x402 sponsor rule; the runtime treats such instructions as no-ops).", + "section": "2.2.1 Compute Budget Controls (SHOULD)" }, "tier": "offline" }, { - "bugType": "wire", - "description": "The same 1300-character Memo in a version-0 static layout: over 1232 bytes, rejected whatever else the sponsor accepts. Pair: x402-verify-v1-over-1232-accept. Mutation: memo #0 replaced with 1300 hex characters.", + "bugType": "settlement", + "description": "Version-1 header without computeUnitLimit (budgeted zero compute units; it cannot execute after the sponsor pays the fee). Pair: x402-verify-v1-accept. Mutation: version-1 header computeUnitLimit removed.", "expect": { "outcome": "reject", - "rejectCode": "invalid-payload", - "rejectReason": "a version-0 transaction over 1232 bytes" + "rejectCode": "invalid-payload" }, - "id": "x402-verify-v0-over-1232-reject", + "id": "x402-verify-v1-missing-compute-unit-limit-reject", "input": { "rpcFixtures": { "mints": { @@ -1615,7 +2181,7 @@ }, "recentBlockhash": "11111111111111111111111111111111" }, - "x402PaymentHeader": "eyJ4NDAyVmVyc2lvbiI6MiwiYWNjZXB0ZWQiOnsic2NoZW1lIjoiZXhhY3QiLCJuZXR3b3JrIjoic29sYW5hOkV0V1RSQUJaYVlxNmlNZmVZS291UnUxNjZWVTJ4cWExIiwiYW1vdW50IjoiMTAwMCIsImFzc2V0IjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJwYXlUbyI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwibWF4VGltZW91dFNlY29uZHMiOjMwMCwiZXh0cmEiOnsiZmVlUGF5ZXIiOiJKMnhjY1J0dUc0M2RyRVNMWXpuSGhMaFFrTFRkZmVwY0tZYmlROUJzSlZhZiIsInRyYW5zYWN0aW9uVmVyc2lvbnMiOlswLDFdfX0sInBheWxvYWQiOnsidHJhbnNhY3Rpb24iOiJBZ0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUNNaUV1QlpUallKVERVQytuTHhqNjlBUTZjaDR5YjFpbXZQTmJ5TSs3aHFWT0lIZXFWSWVXcjhzUEYxaEx0RmZGZnhoMWJsYzJUYVF2c2crcFNFUXNMZ0FJQkJBajlGeVE0V3FESFcyVDdlTTFnTDZIWmtmM3I5MnNUeFk3WEF1cklOZW4yR09wS2JHUGluRklLdnZWUWV4TXV4Zm1WUjNhdXZyNTdra0llNm1rVVJ0SXNCZEwvV1ZicFc0WkRyRUIvYmJWdXJpWTVkSkJkRUNQbkhhUGVVeWpoeWx0cmhQNVVCWm1RcHVvakNOeGxpRld0bFlwbEhoUlhKaVAzK3RPVDI3QVQ3QU1HUm0vbElSY3kvK3l0dW5MRG0rZThqT1c3eGZjU2F5eERtenBBQUFBQUJVcFRXcGtwSVFaTkpPaHhZTm80Zkh3MXRkMjhrcnVCNUIrb1FFRUZSSTBHM2ZiaDEyV2hrOW5MNFViTzYzbXNITFNGN1Y5Yk41RTZqUFdGZnY4QXFUdEVMTE9SSVZmeE9wTTlBVFFvTFFNclgvN05BYUxiOGJkNUJnamZBQzZuQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUVCQUFGQWtBTkF3QUVBQWtEQVFBQUFBQUFBQUFHQkFNSEFnRUtET2dEQUFBQUFBQUFCZ1VBbEFvd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpBQT09In19", + "x402PaymentHeader": "eyJ4NDAyVmVyc2lvbiI6MiwiYWNjZXB0ZWQiOnsic2NoZW1lIjoiZXhhY3QiLCJuZXR3b3JrIjoic29sYW5hOkV0V1RSQUJaYVlxNmlNZmVZS291UnUxNjZWVTJ4cWExIiwiYW1vdW50IjoiMTAwMCIsImFzc2V0IjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJwYXlUbyI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwibWF4VGltZW91dFNlY29uZHMiOjMwMCwiZXh0cmEiOnsiZmVlUGF5ZXIiOiJKMnhjY1J0dUc0M2RyRVNMWXpuSGhMaFFrTFRkZmVwY0tZYmlROUJzSlZhZiIsInRyYW5zYWN0aW9uVmVyc2lvbnMiOlswLDFdfX0sInBheWxvYWQiOnsidHJhbnNhY3Rpb24iOiJnUUlCQXdzQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFJSC9SY2tPRnFneDF0ayszak5ZQytoMlpIOTYvZHJFOFdPMXdMcXlEWHA5aGpxU214ajRweFNDcjcxVUhzVExzWDVsVWQycnI2K2U1SkNIdXBwRkViU0xBWFMvMWxXNlZ1R1E2eEFmMjIxYnE0bU9YU1FYUkFqNXgyajNsTW80Y3BiYTRUK1ZBV1prS2JxSXdqY1pZaFZyWldLWlI0VVZ5WWo5L3JUazl1d0Urd0ZTbE5hbVNraEJrMGs2SEZnMmpoOGZEVzEzYnlTdTRIa0g2aEFRUVZFalFiZDl1SFhaYUdUMmN2aFJzN3JlYXdjdElYdFgxczNrVHFNOVlWKy93Q3BPMFFzczVFaFYvRTZrejBCTkNndEF5dGYvczBCb3R2eHQza0dDTjhBTHFjQkFBQUFBQUFBQUFBQUFBUUZCQW9BQkFBZ0FBTUdBZ0VNNkFNQUFBQUFBQUFHZURRd01uWmxjbWxtZVhZeGJXbHpjekF3TURBd01EQXdNREF3TURBd01EQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUE4WHJ6UmNqTjlzSkx5WGVBR09KVVIvTTc2azJTVjNTNzRKUzVMRitJRmUralhLSzJZN0FDSC90SngxbVlwaUVodU04UTd2WXVmWmxEWkg5TUdZajZEUT09In19", "x402ServerAmount": "1000", "x402ServerCurrency": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", "x402ServerFeePayer": "J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf", @@ -1694,27 +2260,27 @@ }, "intent": "x402-exact", "mode": "verify-transaction", - "provenance": "authored", + "provenance": "generated", "requirements": [ - "X402TX-dc7b0f3305" + "X402TX-997feeb51d", + "X402TX-f9bcc1a14a" ], "role": "server", "spec": { "doc": "x402-txv1/specs/schemes/exact/scheme_exact_svm.md", - "quote": "A legacy or version-0 transaction MUST NOT exceed 1232 serialized bytes; a version-1 transaction MUST NOT exceed 4096 serialized bytes.", - "section": "1.5 Transaction Versions (MUST)" + "quote": "In a version-1 transaction the same caps apply to the message config values instead (§1.5): computeUnitLimit (bit 2) MUST be set and MUST NOT exceed the configured maximum, loadedAccountsDataSizeLimit (bit 3) MUST be set, and priorityFee (bits 0 and 1, total lamports) MUST satisfy", + "section": "2.2.1 Compute Budget Controls (SHOULD)" }, "tier": "offline" }, { - "bugType": "wire", - "description": "Version-1 static layout with a 4000-character Memo: over the 4096-byte version-1 limit. Pair: x402-verify-v1-over-1232-accept. Mutation: memo #0 replaced with 4000 hex characters.", + "bugType": "settlement", + "description": "Version-1 header without loadedAccountsDataSizeLimit (budgeted zero bytes; it fails at load time after the sponsor pays the fee). Pair: x402-verify-v1-accept. Mutation: version-1 header loadedAccountsDataSizeLimit removed.", "expect": { "outcome": "reject", - "rejectCode": "invalid-payload", - "rejectReason": "a version-1 transaction over 4096 bytes" + "rejectCode": "invalid-payload" }, - "id": "x402-verify-v1-over-4096-reject", + "id": "x402-verify-v1-missing-loaded-data-limit-reject", "input": { "rpcFixtures": { "mints": { @@ -1725,7 +2291,7 @@ }, "recentBlockhash": "11111111111111111111111111111111" }, - "x402PaymentHeader": "eyJ4NDAyVmVyc2lvbiI6MiwiYWNjZXB0ZWQiOnsic2NoZW1lIjoiZXhhY3QiLCJuZXR3b3JrIjoic29sYW5hOkV0V1RSQUJaYVlxNmlNZmVZS291UnUxNjZWVTJ4cWExIiwiYW1vdW50IjoiMTAwMCIsImFzc2V0IjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJwYXlUbyI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwibWF4VGltZW91dFNlY29uZHMiOjMwMCwiZXh0cmEiOnsiZmVlUGF5ZXIiOiJKMnhjY1J0dUc0M2RyRVNMWXpuSGhMaFFrTFRkZmVwY0tZYmlROUJzSlZhZiIsInRyYW5zYWN0aW9uVmVyc2lvbnMiOlswLDFdfX0sInBheWxvYWQiOnsidHJhbnNhY3Rpb24iOiJnUUlCQXc4QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFJSC9SY2tPRnFneDF0ayszak5ZQytoMlpIOTYvZHJFOFdPMXdMcXlEWHA5aGpxU214ajRweFNDcjcxVUhzVExzWDVsVWQycnI2K2U1SkNIdXBwRkViU0xBWFMvMWxXNlZ1R1E2eEFmMjIxYnE0bU9YU1FYUkFqNXgyajNsTW80Y3BiYTRUK1ZBV1prS2JxSXdqY1pZaFZyWldLWlI0VVZ5WWo5L3JUazl1d0Urd0ZTbE5hbVNraEJrMGs2SEZnMmpoOGZEVzEzYnlTdTRIa0g2aEFRUVZFalFiZDl1SFhaYUdUMmN2aFJzN3JlYXdjdElYdFgxczNrVHFNOVlWKy93Q3BPMFFzczVFaFYvRTZrejBCTkNndEF5dGYvczBCb3R2eHQza0dDTjhBTHFjQkFBQUFBQUFBQUVBTkF3QUFBQUFFQlFRS0FBUUFvQThEQmdJQkRPZ0RBQUFBQUFBQUJqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1l3TVRJek5EVTJOemc1WVdKalpHVm1NREV5TXpRMU5qYzRPV0ZpWTJSbFpqQXhNak0wTlRZM09EbGhZbU5rWldZd01USXpORFUyTnpnNVlXSmpaR1ZtTURFeU16UTFOamM0T1dGaVkyUmxaakF4TWpNME5UWTNPRGxoWW1Oa1pXWXdNVEl6TkRVMk56ZzVZV0pqWkdWbU1ERXlNelExTmpjNE9XRmlZMlJsWmpBeE1qTTBOVFkzT0RsaFltTmtaV1lBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBNWJMdW81T2t6Zy9MS2pwejBMeDluZ3JkV0lyZWliVFlPSnA2MkV0UmQ2T05aYmFmVUtDek1RM0NkMmZNcGFsWUJ2SXpMTmxvZ3F3WHVDdEtWemkyQUE9PSJ9fQ==", + "x402PaymentHeader": "eyJ4NDAyVmVyc2lvbiI6MiwiYWNjZXB0ZWQiOnsic2NoZW1lIjoiZXhhY3QiLCJuZXR3b3JrIjoic29sYW5hOkV0V1RSQUJaYVlxNmlNZmVZS291UnUxNjZWVTJ4cWExIiwiYW1vdW50IjoiMTAwMCIsImFzc2V0IjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJwYXlUbyI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwibWF4VGltZW91dFNlY29uZHMiOjMwMCwiZXh0cmEiOnsiZmVlUGF5ZXIiOiJKMnhjY1J0dUc0M2RyRVNMWXpuSGhMaFFrTFRkZmVwY0tZYmlROUJzSlZhZiIsInRyYW5zYWN0aW9uVmVyc2lvbnMiOlswLDFdfX0sInBheWxvYWQiOnsidHJhbnNhY3Rpb24iOiJnUUlCQXdjQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFJSC9SY2tPRnFneDF0ayszak5ZQytoMlpIOTYvZHJFOFdPMXdMcXlEWHA5aGpxU214ajRweFNDcjcxVUhzVExzWDVsVWQycnI2K2U1SkNIdXBwRkViU0xBWFMvMWxXNlZ1R1E2eEFmMjIxYnE0bU9YU1FYUkFqNXgyajNsTW80Y3BiYTRUK1ZBV1prS2JxSXdqY1pZaFZyWldLWlI0VVZ5WWo5L3JUazl1d0Urd0ZTbE5hbVNraEJrMGs2SEZnMmpoOGZEVzEzYnlTdTRIa0g2aEFRUVZFalFiZDl1SFhaYUdUMmN2aFJzN3JlYXdjdElYdFgxczNrVHFNOVlWKy93Q3BPMFFzczVFaFYvRTZrejBCTkNndEF5dGYvczBCb3R2eHQza0dDTjhBTHFjQkFBQUFBQUFBQUVBTkF3QUZCQW9BQkFBZ0FBTUdBZ0VNNkFNQUFBQUFBQUFHZURRd01uWmxjbWxtZVhZeGJXbHpjekF3TURBd01EQXdNREF3TURBd01EQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFoNTJZenN1MFJwamhaSWJQUG1sUGV0OFVBa3NEY0JNUWs3d2pOZ2EvU3padUVjdjFnQkxOM25HS3hBTGVZU3pkSVliUXZ5OC9ucHFRNDI2Z1ZlRmJCdz09In19", "x402ServerAmount": "1000", "x402ServerCurrency": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", "x402ServerFeePayer": "J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf", @@ -1806,24 +2372,24 @@ "mode": "verify-transaction", "provenance": "authored", "requirements": [ - "X402TX-dc7b0f3305" + "X402TX-997feeb51d", + "X402TX-f9bcc1a14a" ], "role": "server", "spec": { "doc": "x402-txv1/specs/schemes/exact/scheme_exact_svm.md", - "quote": "A legacy or version-0 transaction MUST NOT exceed 1232 serialized bytes; a version-1 transaction MUST NOT exceed 4096 serialized bytes.", - "section": "1.5 Transaction Versions (MUST)" + "quote": "In a version-1 transaction the same caps apply to the message config values instead (§1.5): computeUnitLimit (bit 2) MUST be set and MUST NOT exceed the configured maximum, loadedAccountsDataSizeLimit (bit 3) MUST be set, and priorityFee (bits 0 and 1, total lamports) MUST satisfy", + "section": "2.2.1 Compute Budget Controls (SHOULD)" }, "tier": "offline" }, { "bugType": "settlement", - "description": "Version-1 static layout preceded by a SetComputeUnitLimit instruction: the runtime ignores it under version 1, so a sponsor bounding it bounds nothing. Pair: x402-verify-v1-accept. Mutation: ComputeBudget instruction with data [2, 64, 13, 3, 0] added.", + "description": "Version-1 header loadedAccountsDataSizeLimit 4194304 (4 MiB), what the TypeScript, Go and Python x402 clients request: the spec requires the limit to be set, not to be the runtime maximum, so a sponsor that demands 64 MiB refuses every reference client. Pair: x402-verify-v1-missing-loaded-data-limit-reject. Mutation: version-1 header loadedAccountsDataSizeLimit set to 4194304.", "expect": { - "outcome": "reject", - "rejectCode": "invalid-payload" + "outcome": "accept" }, - "id": "x402-verify-v1-compute-budget-instruction-reject", + "id": "x402-verify-v1-loaded-data-limit-4mib-accept", "input": { "rpcFixtures": { "mints": { @@ -1834,7 +2400,7 @@ }, "recentBlockhash": "11111111111111111111111111111111" }, - "x402PaymentHeader": "eyJ4NDAyVmVyc2lvbiI6MiwiYWNjZXB0ZWQiOnsic2NoZW1lIjoiZXhhY3QiLCJuZXR3b3JrIjoic29sYW5hOkV0V1RSQUJaYVlxNmlNZmVZS291UnUxNjZWVTJ4cWExIiwiYW1vdW50IjoiMTAwMCIsImFzc2V0IjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJwYXlUbyI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwibWF4VGltZW91dFNlY29uZHMiOjMwMCwiZXh0cmEiOnsiZmVlUGF5ZXIiOiJKMnhjY1J0dUc0M2RyRVNMWXpuSGhMaFFrTFRkZmVwY0tZYmlROUJzSlZhZiIsInRyYW5zYWN0aW9uVmVyc2lvbnMiOlswLDFdfX0sInBheWxvYWQiOnsidHJhbnNhY3Rpb24iOiJnUUlCQkE4QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFNSS9SY2tPRnFneDF0ayszak5ZQytoMlpIOTYvZHJFOFdPMXdMcXlEWHA5aGpxU214ajRweFNDcjcxVUhzVExzWDVsVWQycnI2K2U1SkNIdXBwRkViU0xBWFMvMWxXNlZ1R1E2eEFmMjIxYnE0bU9YU1FYUkFqNXgyajNsTW80Y3BiYTRUK1ZBV1prS2JxSXdqY1pZaFZyWldLWlI0VVZ5WWo5L3JUazl1d0Urd0RCa1p2NVNFWE12L3NyYnB5dzV2bnZJemx1OFgzRW1zc1E1czZRQUFBQUFWS1UxcVpLU0VHVFNUb2NXRGFPSHg4TmJYZHZKSzdnZVFmcUVCQkJVU05CdDMyNGRkbG9aUFp5K0ZHenV0NXJCeTBoZTFmV3plUk9vejFoWDcvQUtrN1JDeXprU0ZYOFRxVFBRRTBLQzBESzEvK3pRR2kyL0czZVFZSTN3QXVwd0VBQUFBQUFBQUFRQTBEQUFBQUFBUUVBQVVBQmdRS0FBVUFJQUFDUUEwREFBTUhBZ0VNNkFNQUFBQUFBQUFHZURRd01uWmxjbWxtZVhZeFkyOXRjREF3TURBd01EQXdNREF3TURBd01EQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFpY1hLSkJhQXorcW94VFhpQ01pREdxZEpUZk1JakxCelZrMVY0VEZMM0VDTmxDNVQ5N3QrNkVVUkRldU9uQmVXcUI3TDJBSzU1eVNKcU9CK0x6dmhEUT09In19", + "x402PaymentHeader": "eyJ4NDAyVmVyc2lvbiI6MiwiYWNjZXB0ZWQiOnsic2NoZW1lIjoiZXhhY3QiLCJuZXR3b3JrIjoic29sYW5hOkV0V1RSQUJaYVlxNmlNZmVZS291UnUxNjZWVTJ4cWExIiwiYW1vdW50IjoiMTAwMCIsImFzc2V0IjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJwYXlUbyI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwibWF4VGltZW91dFNlY29uZHMiOjMwMCwiZXh0cmEiOnsiZmVlUGF5ZXIiOiJKMnhjY1J0dUc0M2RyRVNMWXpuSGhMaFFrTFRkZmVwY0tZYmlROUJzSlZhZiIsInRyYW5zYWN0aW9uVmVyc2lvbnMiOlswLDFdfX0sInBheWxvYWQiOnsidHJhbnNhY3Rpb24iOiJnUUlCQXc4QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFJSC9SY2tPRnFneDF0ayszak5ZQytoMlpIOTYvZHJFOFdPMXdMcXlEWHA5aGpxU214ajRweFNDcjcxVUhzVExzWDVsVWQycnI2K2U1SkNIdXBwRkViU0xBWFMvMWxXNlZ1R1E2eEFmMjIxYnE0bU9YU1FYUkFqNXgyajNsTW80Y3BiYTRUK1ZBV1prS2JxSXdqY1pZaFZyWldLWlI0VVZ5WWo5L3JUazl1d0Urd0ZTbE5hbVNraEJrMGs2SEZnMmpoOGZEVzEzYnlTdTRIa0g2aEFRUVZFalFiZDl1SFhaYUdUMmN2aFJzN3JlYXdjdElYdFgxczNrVHFNOVlWKy93Q3BPMFFzczVFaFYvRTZrejBCTkNndEF5dGYvczBCb3R2eHQza0dDTjhBTHFjQkFBQUFBQUFBQUVBTkF3QUFBRUFBQlFRS0FBUUFJQUFEQmdJQkRPZ0RBQUFBQUFBQUJuZzBNREoyWlhKcFpubDJNV3h2WVdRd01EQXdNREF3TURBd01EQXdNREF3QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQU9SQ29lQ2o0R0FCSjZNR0xYN2daVGhpQlp0OElQRS9Ib3BPQkZqYUdFY2s2eVBIQ29EcjZVd0ZsMll4cEsyN1lzbkhWc0t4bDVmU2I5bTVNUm50SWdBPSJ9fQ==", "x402ServerAmount": "1000", "x402ServerCurrency": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", "x402ServerFeePayer": "J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf", @@ -1915,25 +2481,24 @@ "mode": "verify-transaction", "provenance": "generated", "requirements": [ - "X402TX-936b492daa", - "X402TX-644919eb3b" + "X402TX-997feeb51d", + "X402TX-f9bcc1a14a" ], "role": "server", "spec": { "doc": "x402-txv1/specs/schemes/exact/scheme_exact_svm.md", - "quote": "A version-1 transaction that contains a Compute Budget instruction MUST be rejected.", + "quote": "In a version-1 transaction the same caps apply to the message config values instead (§1.5): computeUnitLimit (bit 2) MUST be set and MUST NOT exceed the configured maximum, loadedAccountsDataSizeLimit (bit 3) MUST be set, and priorityFee (bits 0 and 1, total lamports) MUST satisfy", "section": "2.2.1 Compute Budget Controls (SHOULD)" }, "tier": "offline" }, { "bugType": "settlement", - "description": "Version-1 header without computeUnitLimit (budgeted zero compute units; it cannot execute after the sponsor pays the fee). Pair: x402-verify-v1-accept. Mutation: version-1 header computeUnitLimit removed.", + "description": "Version-1 header loadedAccountsDataSizeLimit 32768 (32 KiB), set but small: accepted at verification. A budget too small to load the payment's programs fails at simulation, which this offline vector does not run. Mutation: version-1 header loadedAccountsDataSizeLimit set to 32768.", "expect": { - "outcome": "reject", - "rejectCode": "invalid-payload" + "outcome": "accept" }, - "id": "x402-verify-v1-missing-compute-unit-limit-reject", + "id": "x402-verify-v1-loaded-data-limit-small-accept", "input": { "rpcFixtures": { "mints": { @@ -1944,7 +2509,7 @@ }, "recentBlockhash": "11111111111111111111111111111111" }, - "x402PaymentHeader": "eyJ4NDAyVmVyc2lvbiI6MiwiYWNjZXB0ZWQiOnsic2NoZW1lIjoiZXhhY3QiLCJuZXR3b3JrIjoic29sYW5hOkV0V1RSQUJaYVlxNmlNZmVZS291UnUxNjZWVTJ4cWExIiwiYW1vdW50IjoiMTAwMCIsImFzc2V0IjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJwYXlUbyI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwibWF4VGltZW91dFNlY29uZHMiOjMwMCwiZXh0cmEiOnsiZmVlUGF5ZXIiOiJKMnhjY1J0dUc0M2RyRVNMWXpuSGhMaFFrTFRkZmVwY0tZYmlROUJzSlZhZiIsInRyYW5zYWN0aW9uVmVyc2lvbnMiOlswLDFdfX0sInBheWxvYWQiOnsidHJhbnNhY3Rpb24iOiJnUUlCQXdzQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFJSC9SY2tPRnFneDF0ayszak5ZQytoMlpIOTYvZHJFOFdPMXdMcXlEWHA5aGpxU214ajRweFNDcjcxVUhzVExzWDVsVWQycnI2K2U1SkNIdXBwRkViU0xBWFMvMWxXNlZ1R1E2eEFmMjIxYnE0bU9YU1FYUkFqNXgyajNsTW80Y3BiYTRUK1ZBV1prS2JxSXdqY1pZaFZyWldLWlI0VVZ5WWo5L3JUazl1d0Urd0ZTbE5hbVNraEJrMGs2SEZnMmpoOGZEVzEzYnlTdTRIa0g2aEFRUVZFalFiZDl1SFhaYUdUMmN2aFJzN3JlYXdjdElYdFgxczNrVHFNOVlWKy93Q3BPMFFzczVFaFYvRTZrejBCTkNndEF5dGYvczBCb3R2eHQza0dDTjhBTHFjQkFBQUFBQUFBQUFBQUFBUUZCQW9BQkFBZ0FBTUdBZ0VNNkFNQUFBQUFBQUFHZURRd01uWmxjbWxtZVhZeGJXbHpjekF3TURBd01EQXdNREF3TURBd01EQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUE4WHJ6UmNqTjlzSkx5WGVBR09KVVIvTTc2azJTVjNTNzRKUzVMRitJRmUralhLSzJZN0FDSC90SngxbVlwaUVodU04UTd2WXVmWmxEWkg5TUdZajZEUT09In19", + "x402PaymentHeader": "eyJ4NDAyVmVyc2lvbiI6MiwiYWNjZXB0ZWQiOnsic2NoZW1lIjoiZXhhY3QiLCJuZXR3b3JrIjoic29sYW5hOkV0V1RSQUJaYVlxNmlNZmVZS291UnUxNjZWVTJ4cWExIiwiYW1vdW50IjoiMTAwMCIsImFzc2V0IjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJwYXlUbyI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwibWF4VGltZW91dFNlY29uZHMiOjMwMCwiZXh0cmEiOnsiZmVlUGF5ZXIiOiJKMnhjY1J0dUc0M2RyRVNMWXpuSGhMaFFrTFRkZmVwY0tZYmlROUJzSlZhZiIsInRyYW5zYWN0aW9uVmVyc2lvbnMiOlswLDFdfX0sInBheWxvYWQiOnsidHJhbnNhY3Rpb24iOiJnUUlCQXc4QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFJSC9SY2tPRnFneDF0ayszak5ZQytoMlpIOTYvZHJFOFdPMXdMcXlEWHA5aGpxU214ajRweFNDcjcxVUhzVExzWDVsVWQycnI2K2U1SkNIdXBwRkViU0xBWFMvMWxXNlZ1R1E2eEFmMjIxYnE0bU9YU1FYUkFqNXgyajNsTW80Y3BiYTRUK1ZBV1prS2JxSXdqY1pZaFZyWldLWlI0VVZ5WWo5L3JUazl1d0Urd0ZTbE5hbVNraEJrMGs2SEZnMmpoOGZEVzEzYnlTdTRIa0g2aEFRUVZFalFiZDl1SFhaYUdUMmN2aFJzN3JlYXdjdElYdFgxczNrVHFNOVlWKy93Q3BPMFFzczVFaFYvRTZrejBCTkNndEF5dGYvczBCb3R2eHQza0dDTjhBTHFjQkFBQUFBQUFBQUVBTkF3QUFnQUFBQlFRS0FBUUFJQUFEQmdJQkRPZ0RBQUFBQUFBQUJuZzBNREoyWlhKcFpubDJNV3h2WVdRd01EQXdNREF3TURBd01EQXdNREF3QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQVBLTmIvcWJvcFdzQnBETTNrTUV4TGVKK0hobGJBSk9yd1Q5dll4UTlJRkduZ1E5b0xzZlBGZkpCcjIxd1NNb1QrTTV5REx2MjFCeFAyOENObmVkOVE4PSJ9fQ==", "x402ServerAmount": "1000", "x402ServerCurrency": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", "x402ServerFeePayer": "J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf", @@ -2025,25 +2590,24 @@ "mode": "verify-transaction", "provenance": "generated", "requirements": [ - "X402TX-eb681e1701", - "X402TX-644919eb3b" + "X402TX-997feeb51d" ], "role": "server", "spec": { "doc": "x402-txv1/specs/schemes/exact/scheme_exact_svm.md", - "quote": "In a version-1 transaction the same caps apply to the message TransactionConfig instead: computeUnitLimit MUST be present and MUST NOT exceed the configured maximum, loadedAccountsDataSizeLimit MUST be present, and priorityFee (total lamports) MUST satisfy priorityFee 1000000 <= maxPriorityFeeMicroLamports computeUnitLimit.", + "quote": "In a version-1 transaction the same caps apply to the message config values instead (§1.5): computeUnitLimit (bit 2) MUST be set and MUST NOT exceed the configured maximum, loadedAccountsDataSizeLimit (bit 3) MUST be set, and priorityFee (bits 0 and 1, total lamports) MUST satisfy", "section": "2.2.1 Compute Budget Controls (SHOULD)" }, "tier": "offline" }, { "bugType": "settlement", - "description": "Version-1 header without loadedAccountsDataSizeLimit (budgeted zero bytes; it fails at load time after the sponsor pays the fee). Pair: x402-verify-v1-accept. Mutation: version-1 header loadedAccountsDataSizeLimit removed.", + "description": "Version-1 header requesting a 64 KiB heap (TransactionConfigMask bit 4), the header form of RequestHeapFrame that a sponsor refuses on version 0 (x402-exact-verify-compute-heap-frame-reject). Pair: x402-verify-v1-accept. Mutation: version-1 header heapSize set to 65536.", "expect": { "outcome": "reject", "rejectCode": "invalid-payload" }, - "id": "x402-verify-v1-missing-loaded-data-limit-reject", + "id": "x402-verify-v1-heap-size-reject", "input": { "rpcFixtures": { "mints": { @@ -2054,7 +2618,7 @@ }, "recentBlockhash": "11111111111111111111111111111111" }, - "x402PaymentHeader": "eyJ4NDAyVmVyc2lvbiI6MiwiYWNjZXB0ZWQiOnsic2NoZW1lIjoiZXhhY3QiLCJuZXR3b3JrIjoic29sYW5hOkV0V1RSQUJaYVlxNmlNZmVZS291UnUxNjZWVTJ4cWExIiwiYW1vdW50IjoiMTAwMCIsImFzc2V0IjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJwYXlUbyI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwibWF4VGltZW91dFNlY29uZHMiOjMwMCwiZXh0cmEiOnsiZmVlUGF5ZXIiOiJKMnhjY1J0dUc0M2RyRVNMWXpuSGhMaFFrTFRkZmVwY0tZYmlROUJzSlZhZiIsInRyYW5zYWN0aW9uVmVyc2lvbnMiOlswLDFdfX0sInBheWxvYWQiOnsidHJhbnNhY3Rpb24iOiJnUUlCQXdjQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFJSC9SY2tPRnFneDF0ayszak5ZQytoMlpIOTYvZHJFOFdPMXdMcXlEWHA5aGpxU214ajRweFNDcjcxVUhzVExzWDVsVWQycnI2K2U1SkNIdXBwRkViU0xBWFMvMWxXNlZ1R1E2eEFmMjIxYnE0bU9YU1FYUkFqNXgyajNsTW80Y3BiYTRUK1ZBV1prS2JxSXdqY1pZaFZyWldLWlI0VVZ5WWo5L3JUazl1d0Urd0ZTbE5hbVNraEJrMGs2SEZnMmpoOGZEVzEzYnlTdTRIa0g2aEFRUVZFalFiZDl1SFhaYUdUMmN2aFJzN3JlYXdjdElYdFgxczNrVHFNOVlWKy93Q3BPMFFzczVFaFYvRTZrejBCTkNndEF5dGYvczBCb3R2eHQza0dDTjhBTHFjQkFBQUFBQUFBQUVBTkF3QUZCQW9BQkFBZ0FBTUdBZ0VNNkFNQUFBQUFBQUFHZURRd01uWmxjbWxtZVhZeGJXbHpjekF3TURBd01EQXdNREF3TURBd01EQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFoNTJZenN1MFJwamhaSWJQUG1sUGV0OFVBa3NEY0JNUWs3d2pOZ2EvU3padUVjdjFnQkxOM25HS3hBTGVZU3pkSVliUXZ5OC9ucHFRNDI2Z1ZlRmJCdz09In19", + "x402PaymentHeader": "eyJ4NDAyVmVyc2lvbiI6MiwiYWNjZXB0ZWQiOnsic2NoZW1lIjoiZXhhY3QiLCJuZXR3b3JrIjoic29sYW5hOkV0V1RSQUJaYVlxNmlNZmVZS291UnUxNjZWVTJ4cWExIiwiYW1vdW50IjoiMTAwMCIsImFzc2V0IjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJwYXlUbyI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwibWF4VGltZW91dFNlY29uZHMiOjMwMCwiZXh0cmEiOnsiZmVlUGF5ZXIiOiJKMnhjY1J0dUc0M2RyRVNMWXpuSGhMaFFrTFRkZmVwY0tZYmlROUJzSlZhZiIsInRyYW5zYWN0aW9uVmVyc2lvbnMiOlswLDFdfX0sInBheWxvYWQiOnsidHJhbnNhY3Rpb24iOiJnUUlCQXg4QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFJSC9SY2tPRnFneDF0ayszak5ZQytoMlpIOTYvZHJFOFdPMXdMcXlEWHA5aGpxU214ajRweFNDcjcxVUhzVExzWDVsVWQycnI2K2U1SkNIdXBwRkViU0xBWFMvMWxXNlZ1R1E2eEFmMjIxYnE0bU9YU1FYUkFqNXgyajNsTW80Y3BiYTRUK1ZBV1prS2JxSXdqY1pZaFZyWldLWlI0VVZ5WWo5L3JUazl1d0Urd0ZTbE5hbVNraEJrMGs2SEZnMmpoOGZEVzEzYnlTdTRIa0g2aEFRUVZFalFiZDl1SFhaYUdUMmN2aFJzN3JlYXdjdElYdFgxczNrVHFNOVlWKy93Q3BPMFFzczVFaFYvRTZrejBCTkNndEF5dGYvczBCb3R2eHQza0dDTjhBTHFjQkFBQUFBQUFBQUVBTkF3QUFBQUFFQUFBQkFBVUVDZ0FFQUNBQUF3WUNBUXpvQXdBQUFBQUFBQVo0TkRBeWRtVnlhV1o1ZGpGb1pXRndNREF3TURBd01EQXdNREF3TURBd01BQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQ1ZtdFZjSWswVC9kTmR6cE0vQUltaDJWUGVoQVVmbko1OHhpVVllRUl6Rmd0RGZsZnFsSzJOaVdESWczUTA0STZ2RjlmNTQzUWlKWU5PVFRBUXRub0oifX0=", "x402ServerAmount": "1000", "x402ServerCurrency": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", "x402ServerFeePayer": "J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf", @@ -2133,22 +2697,21 @@ }, "intent": "x402-exact", "mode": "verify-transaction", - "provenance": "authored", + "provenance": "generated", "requirements": [ - "X402TX-eb681e1701", - "X402TX-644919eb3b" + "X402TX-997feeb51d" ], "role": "server", "spec": { "doc": "x402-txv1/specs/schemes/exact/scheme_exact_svm.md", - "quote": "In a version-1 transaction the same caps apply to the message TransactionConfig instead: computeUnitLimit MUST be present and MUST NOT exceed the configured maximum, loadedAccountsDataSizeLimit MUST be present, and priorityFee (total lamports) MUST satisfy priorityFee 1000000 <= maxPriorityFeeMicroLamports computeUnitLimit.", + "quote": "Only SetComputeUnitLimit (discriminator 2) and SetComputeUnitPrice (discriminator 3) SHOULD be accepted; other ComputeBudget instruction types expand execution surface without being necessary for payment verification and SHOULD be rejected.", "section": "2.2.1 Compute Budget Controls (SHOULD)" }, "tier": "offline" }, { "bugType": "settlement", - "description": "Version-1 header computeUnitLimit at the configured maximum (200000): accepted (the base layout already sits at the cap; this pins it explicitly next to its over-cap pair). Mutation: version-1 header computeUnitLimit set to 200000.", + "description": "Version-1 header computeUnitLimit at the reference default maximum (400000, scheme_exact_svm.md §2.2.1): accepted, pinned next to its over-cap pair. Mutation: version-1 header computeUnitLimit set to 400000.", "expect": { "outcome": "accept" }, @@ -2163,7 +2726,7 @@ }, "recentBlockhash": "11111111111111111111111111111111" }, - "x402PaymentHeader": "eyJ4NDAyVmVyc2lvbiI6MiwiYWNjZXB0ZWQiOnsic2NoZW1lIjoiZXhhY3QiLCJuZXR3b3JrIjoic29sYW5hOkV0V1RSQUJaYVlxNmlNZmVZS291UnUxNjZWVTJ4cWExIiwiYW1vdW50IjoiMTAwMCIsImFzc2V0IjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJwYXlUbyI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwibWF4VGltZW91dFNlY29uZHMiOjMwMCwiZXh0cmEiOnsiZmVlUGF5ZXIiOiJKMnhjY1J0dUc0M2RyRVNMWXpuSGhMaFFrTFRkZmVwY0tZYmlROUJzSlZhZiIsInRyYW5zYWN0aW9uVmVyc2lvbnMiOlswLDFdfX0sInBheWxvYWQiOnsidHJhbnNhY3Rpb24iOiJnUUlCQXc4QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFJSC9SY2tPRnFneDF0ayszak5ZQytoMlpIOTYvZHJFOFdPMXdMcXlEWHA5aGpxU214ajRweFNDcjcxVUhzVExzWDVsVWQycnI2K2U1SkNIdXBwRkViU0xBWFMvMWxXNlZ1R1E2eEFmMjIxYnE0bU9YU1FYUkFqNXgyajNsTW80Y3BiYTRUK1ZBV1prS2JxSXdqY1pZaFZyWldLWlI0VVZ5WWo5L3JUazl1d0Urd0ZTbE5hbVNraEJrMGs2SEZnMmpoOGZEVzEzYnlTdTRIa0g2aEFRUVZFalFiZDl1SFhaYUdUMmN2aFJzN3JlYXdjdElYdFgxczNrVHFNOVlWKy93Q3BPMFFzczVFaFYvRTZrejBCTkNndEF5dGYvczBCb3R2eHQza0dDTjhBTHFjQkFBQUFBQUFBQUVBTkF3QUFBQUFFQlFRS0FBUUFJQUFEQmdJQkRPZ0RBQUFBQUFBQUJuZzBNREoyWlhKcFpubDJNV052YlhBd01EQXdNREF3TURBd01EQXdNREF3QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUo0YVpzdnVqbXNkSzZveU5nYk5pcXkvM0R3WGFzYnE3a2RJNWt5cVQ4VUtpVXV2Zkt5aHVnUUM2S203SlJKenZicnZUY3BQUWVGTVI0clpOUnBUVkE4PSJ9fQ==", + "x402PaymentHeader": "eyJ4NDAyVmVyc2lvbiI6MiwiYWNjZXB0ZWQiOnsic2NoZW1lIjoiZXhhY3QiLCJuZXR3b3JrIjoic29sYW5hOkV0V1RSQUJaYVlxNmlNZmVZS291UnUxNjZWVTJ4cWExIiwiYW1vdW50IjoiMTAwMCIsImFzc2V0IjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJwYXlUbyI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwibWF4VGltZW91dFNlY29uZHMiOjMwMCwiZXh0cmEiOnsiZmVlUGF5ZXIiOiJKMnhjY1J0dUc0M2RyRVNMWXpuSGhMaFFrTFRkZmVwY0tZYmlROUJzSlZhZiIsInRyYW5zYWN0aW9uVmVyc2lvbnMiOlswLDFdfX0sInBheWxvYWQiOnsidHJhbnNhY3Rpb24iOiJnUUlCQXc4QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFJSC9SY2tPRnFneDF0ayszak5ZQytoMlpIOTYvZHJFOFdPMXdMcXlEWHA5aGpxU214ajRweFNDcjcxVUhzVExzWDVsVWQycnI2K2U1SkNIdXBwRkViU0xBWFMvMWxXNlZ1R1E2eEFmMjIxYnE0bU9YU1FYUkFqNXgyajNsTW80Y3BiYTRUK1ZBV1prS2JxSXdqY1pZaFZyWldLWlI0VVZ5WWo5L3JUazl1d0Urd0ZTbE5hbVNraEJrMGs2SEZnMmpoOGZEVzEzYnlTdTRIa0g2aEFRUVZFalFiZDl1SFhaYUdUMmN2aFJzN3JlYXdjdElYdFgxczNrVHFNOVlWKy93Q3BPMFFzczVFaFYvRTZrejBCTkNndEF5dGYvczBCb3R2eHQza0dDTjhBTHFjQkFBQUFBQUFBQUlBYUJnQUFBQUFFQlFRS0FBUUFJQUFEQmdJQkRPZ0RBQUFBQUFBQUJuZzBNREoyWlhKcFpubDJNV052YlhBd01EQXdNREF3TURBd01EQXdNREF3QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUljTGJvTVlIbDU3RXMwRXNqZGh0NE16Z3QvOW1iaTVuNkY0cHluR20xU2pJbEl1ZHRFQVRaWDM3Szlmbi9uY0JZU2hFMG5pTjRFa3ByWDBsRjVsMlFrPSJ9fQ==", "x402ServerAmount": "1000", "x402ServerCurrency": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", "x402ServerFeePayer": "J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf", @@ -2244,19 +2807,19 @@ "mode": "verify-transaction", "provenance": "generated", "requirements": [ - "X402TX-eb681e1701" + "X402TX-997feeb51d" ], "role": "server", "spec": { "doc": "x402-txv1/specs/schemes/exact/scheme_exact_svm.md", - "quote": "In a version-1 transaction the same caps apply to the message TransactionConfig instead: computeUnitLimit MUST be present and MUST NOT exceed the configured maximum, loadedAccountsDataSizeLimit MUST be present, and priorityFee (total lamports) MUST satisfy priorityFee 1000000 <= maxPriorityFeeMicroLamports computeUnitLimit.", + "quote": "In a version-1 transaction the same caps apply to the message config values instead (§1.5): computeUnitLimit (bit 2) MUST be set and MUST NOT exceed the configured maximum, loadedAccountsDataSizeLimit (bit 3) MUST be set, and priorityFee (bits 0 and 1, total lamports) MUST satisfy", "section": "2.2.1 Compute Budget Controls (SHOULD)" }, "tier": "offline" }, { "bugType": "settlement", - "description": "Version-1 header computeUnitLimit 200001, one unit over the configured maximum. Mutation: version-1 header computeUnitLimit set to 200001.", + "description": "Version-1 header computeUnitLimit 400001, one unit over the reference default maximum (scheme_exact_svm.md §2.2.1: 400,000). Mutation: version-1 header computeUnitLimit set to 400001.", "expect": { "outcome": "reject", "rejectCode": "compute-limit-over-cap" @@ -2272,7 +2835,7 @@ }, "recentBlockhash": "11111111111111111111111111111111" }, - "x402PaymentHeader": "eyJ4NDAyVmVyc2lvbiI6MiwiYWNjZXB0ZWQiOnsic2NoZW1lIjoiZXhhY3QiLCJuZXR3b3JrIjoic29sYW5hOkV0V1RSQUJaYVlxNmlNZmVZS291UnUxNjZWVTJ4cWExIiwiYW1vdW50IjoiMTAwMCIsImFzc2V0IjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJwYXlUbyI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwibWF4VGltZW91dFNlY29uZHMiOjMwMCwiZXh0cmEiOnsiZmVlUGF5ZXIiOiJKMnhjY1J0dUc0M2RyRVNMWXpuSGhMaFFrTFRkZmVwY0tZYmlROUJzSlZhZiIsInRyYW5zYWN0aW9uVmVyc2lvbnMiOlswLDFdfX0sInBheWxvYWQiOnsidHJhbnNhY3Rpb24iOiJnUUlCQXc4QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFJSC9SY2tPRnFneDF0ayszak5ZQytoMlpIOTYvZHJFOFdPMXdMcXlEWHA5aGpxU214ajRweFNDcjcxVUhzVExzWDVsVWQycnI2K2U1SkNIdXBwRkViU0xBWFMvMWxXNlZ1R1E2eEFmMjIxYnE0bU9YU1FYUkFqNXgyajNsTW80Y3BiYTRUK1ZBV1prS2JxSXdqY1pZaFZyWldLWlI0VVZ5WWo5L3JUazl1d0Urd0ZTbE5hbVNraEJrMGs2SEZnMmpoOGZEVzEzYnlTdTRIa0g2aEFRUVZFalFiZDl1SFhaYUdUMmN2aFJzN3JlYXdjdElYdFgxczNrVHFNOVlWKy93Q3BPMFFzczVFaFYvRTZrejBCTkNndEF5dGYvczBCb3R2eHQza0dDTjhBTHFjQkFBQUFBQUFBQUVFTkF3QUFBQUFFQlFRS0FBUUFJQUFEQmdJQkRPZ0RBQUFBQUFBQUJuZzBNREoyWlhKcFpubDJNV052YlhBd01EQXdNREF3TURBd01EQXdNREF3QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUhiYkFXVExNVmNOc3NvelRYSFNDZ0ltcmYxblk0Vi9nTStGdEhNd0ZreGU5Nm4rWVhkd0pwZFI3NmlwQTliWTcxSWFsTHB1UGg2OU0xd3V0VHVyWUFrPSJ9fQ==", + "x402PaymentHeader": "eyJ4NDAyVmVyc2lvbiI6MiwiYWNjZXB0ZWQiOnsic2NoZW1lIjoiZXhhY3QiLCJuZXR3b3JrIjoic29sYW5hOkV0V1RSQUJaYVlxNmlNZmVZS291UnUxNjZWVTJ4cWExIiwiYW1vdW50IjoiMTAwMCIsImFzc2V0IjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJwYXlUbyI6IkNYaHJGWkpMS3Fqem1QM3NqWUxjRjRkVGVYV0tDeTllMlNYWFoyWW82TVBZIiwibWF4VGltZW91dFNlY29uZHMiOjMwMCwiZXh0cmEiOnsiZmVlUGF5ZXIiOiJKMnhjY1J0dUc0M2RyRVNMWXpuSGhMaFFrTFRkZmVwY0tZYmlROUJzSlZhZiIsInRyYW5zYWN0aW9uVmVyc2lvbnMiOlswLDFdfX0sInBheWxvYWQiOnsidHJhbnNhY3Rpb24iOiJnUUlCQXc4QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFJSC9SY2tPRnFneDF0ayszak5ZQytoMlpIOTYvZHJFOFdPMXdMcXlEWHA5aGpxU214ajRweFNDcjcxVUhzVExzWDVsVWQycnI2K2U1SkNIdXBwRkViU0xBWFMvMWxXNlZ1R1E2eEFmMjIxYnE0bU9YU1FYUkFqNXgyajNsTW80Y3BiYTRUK1ZBV1prS2JxSXdqY1pZaFZyWldLWlI0VVZ5WWo5L3JUazl1d0Urd0ZTbE5hbVNraEJrMGs2SEZnMmpoOGZEVzEzYnlTdTRIa0g2aEFRUVZFalFiZDl1SFhaYUdUMmN2aFJzN3JlYXdjdElYdFgxczNrVHFNOVlWKy93Q3BPMFFzczVFaFYvRTZrejBCTkNndEF5dGYvczBCb3R2eHQza0dDTjhBTHFjQkFBQUFBQUFBQUlFYUJnQUFBQUFFQlFRS0FBUUFJQUFEQmdJQkRPZ0RBQUFBQUFBQUJuZzBNREoyWlhKcFpubDJNV052YlhBd01EQXdNREF3TURBd01EQXdNREF3QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUtQMEZFcHpNYlBVQW55NEJmVi9zRFcxWHhqaE1TcHpKSFovZ0RCcWo2clorZXVZSUhETHRtNEM3d2M0VCtwTHNJcDBSQUV3STRlM3paVGZac0RKb3drPSJ9fQ==", "x402ServerAmount": "1000", "x402ServerCurrency": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", "x402ServerFeePayer": "J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf", @@ -2353,12 +2916,12 @@ "mode": "verify-transaction", "provenance": "generated", "requirements": [ - "X402TX-eb681e1701" + "X402TX-997feeb51d" ], "role": "server", "spec": { "doc": "x402-txv1/specs/schemes/exact/scheme_exact_svm.md", - "quote": "In a version-1 transaction the same caps apply to the message TransactionConfig instead: computeUnitLimit MUST be present and MUST NOT exceed the configured maximum, loadedAccountsDataSizeLimit MUST be present, and priorityFee (total lamports) MUST satisfy priorityFee 1000000 <= maxPriorityFeeMicroLamports computeUnitLimit.", + "quote": "In a version-1 transaction the same caps apply to the message config values instead (§1.5): computeUnitLimit (bit 2) MUST be set and MUST NOT exceed the configured maximum, loadedAccountsDataSizeLimit (bit 3) MUST be set, and priorityFee (bits 0 and 1, total lamports) MUST satisfy", "section": "2.2.1 Compute Budget Controls (SHOULD)" }, "tier": "offline" @@ -2461,13 +3024,13 @@ "mode": "verify-transaction", "provenance": "generated", "requirements": [ - "X402TX-2ad7a3f326", - "X402TX-eb681e1701" + "X402TX-655bb4a79a", + "X402TX-997feeb51d" ], "role": "server", "spec": { "doc": "x402-txv1/specs/schemes/exact/scheme_exact_svm.md", - "quote": "The legacy/version-0 Compute Budget price and the version-1 total priority fee MUST each be no greater than 5 lamports/CU on this path, using the normalization in §1.5 for version 1.", + "quote": "The legacy/version-0 Compute Budget price and the version-1 total priority fee MUST each be no greater than maxPriorityFeeMicroLamports (default 5 lamports/CU) on this path, using the normalization in §1.5 for version 1.", "section": "3.1 Path 1 — Static Layout Verification (standard wallets)" }, "tier": "offline" @@ -2571,13 +3134,14 @@ "mode": "verify-transaction", "provenance": "generated", "requirements": [ - "X402TX-2ad7a3f326", - "X402TX-eb681e1701" + "X402TX-655bb4a79a", + "X402TX-997feeb51d", + "X402TX-74fb884aa9" ], "role": "server", "spec": { "doc": "x402-txv1/specs/schemes/exact/scheme_exact_svm.md", - "quote": "The legacy/version-0 Compute Budget price and the version-1 total priority fee MUST each be no greater than 5 lamports/CU on this path, using the normalization in §1.5 for version 1.", + "quote": "The legacy/version-0 Compute Budget price and the version-1 total priority fee MUST each be no greater than maxPriorityFeeMicroLamports (default 5 lamports/CU) on this path, using the normalization in §1.5 for version 1.", "section": "3.1 Path 1 — Static Layout Verification (standard wallets)" }, "tier": "offline" @@ -2681,12 +3245,12 @@ "mode": "verify-transaction", "provenance": "generated", "requirements": [ - "X402TX-d188782061" + "X402TX-4c2fd60e66" ], "role": "server", "spec": { "doc": "x402-txv1/specs/schemes/exact/scheme_exact_svm.md", - "quote": "A version-1 transaction MUST contain 1 to 5 instructions in this order:", + "quote": "For a single-payee charge, a version-1 transaction MUST contain 1 to 5 instructions in this order:", "section": "3.1 Path 1 — Static Layout Verification (standard wallets)" }, "tier": "offline" @@ -3024,6 +3588,12 @@ "bugType": "settlement", "description": "Version-1 TransferChecked declaring 9 decimals for a 6-decimal mint. The transaction is the version-1 static layout (budget in the header, no ComputeBudget instructions), so the rule is checked independently of the message version. Mutation: transfer #0 TransferChecked decimals set to 9.", "expect": { + "alsoConformant": [ + { + "outcome": "accept" + } + ], + "alsoConformantReason": "§1.4 matches a transfer by mint, destination ATA and amount (“correct mint, correct destination ATA, amount >= required”) and the scheme never names the TransferChecked decimals; the token program fails a TransferChecked whose decimals differ from the mint's, which the sponsor's simulation catches (§2.2.3, not run by offline vectors), so a static verifier that leaves it to simulation is conformant.", "outcome": "reject", "rejectCode": "decimals-mismatch" }, diff --git a/harness/vectors/x402-upto-open-policy.json b/harness/vectors/x402-upto-open-policy.json index 87ea32579..29212ccec 100644 --- a/harness/vectors/x402-upto-open-policy.json +++ b/harness/vectors/x402-upto-open-policy.json @@ -700,19 +700,19 @@ "mode": "verify-transaction", "provenance": "generated", "requirements": [ - "X402-c1174b72d8" + "X402-4de59a1f27" ], "role": "server", "spec": { "doc": "x402/specs/schemes/upto/scheme_upto_svm.md", - "quote": "The message MAY be legacy or version 0, but it MUST NOT contain Address Lookup Table lookups.", + "quote": "The message version MUST be one advertised in extra.transactionVersions (0 when the field is absent; see [Transaction versions](#transaction-versions)), and the message MUST NOT contain Address Lookup Table lookups.", "section": "Message and signer rules" }, "tier": "offline" }, { "bugType": "auth-bypass", - "description": "SetComputeUnitLimit 400000 and SetComputeUnitPrice 5000000 sit exactly at the absolute ceilings and are accepted. Verify is the read-only preflight of the deposit settle (Phase 3): every static check before co-signing, at the vector's clock (nowSeconds).", + "description": "SetComputeUnitLimit 400000 sits exactly at the absolute ceiling and SetComputeUnitPrice 5000 makes a 2000 lamport priority fee, exactly the sponsor's cap on the fee it pays (RULINGS S6): accepted. Verify is the read-only preflight of the deposit settle (Phase 3): every static check before co-signing, at the vector's clock (nowSeconds).", "expect": { "outcome": "accept" }, @@ -729,7 +729,7 @@ "recentBlockhash": "11111111111111111111111111111111", "slot": 400000000 }, - "x402PaymentHeader": "eyJhY2NlcHRlZCI6eyJhbW91bnQiOiIxMDAwMDAwIiwiYXNzZXQiOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsImV4dHJhIjp7ImZlZVBheWVyIjoiN3Y1NE5XZEJ0a2p1QUZKckxHc1MyU1hudWs4bkthbTgxbVpKZWVZeFZGaTkiLCJyZWNlaXZlckF1dGhvcml6ZXIiOiJBb1ZzR2FqOE1TSjZ4d0t4ZkZ4bzlpWldIM2VuQzhSUlRYS0gyZngyRjhvcyIsInJlY2VudEJsb2NraGFzaCI6IjExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExIiwicmVjZW50U2xvdCI6IjQwMDAwMDAwMCIsInRva2VuUHJvZ3JhbSI6IlRva2Vua2VnUWZlWnlpTndBSmJOYkdLUEZYQ1d1QnZmOVNzNjIzVlE1REEiLCJ3aXRoZHJhd0RlbGF5Ijo5MDB9LCJtYXhUaW1lb3V0U2Vjb25kcyI6MzAwLCJuZXR3b3JrIjoic29sYW5hOkV0V1RSQUJaYVlxNmlNZmVZS291UnUxNjZWVTJ4cWExIiwicGF5VG8iOiJDWGhyRlpKTEtxanptUDNzallMY0Y0ZFRlWFdLQ3k5ZTJTWFhaMllvNk1QWSIsInNjaGVtZSI6InVwdG8ifSwicGF5bG9hZCI6eyJhdXRob3JpemVkU2lnbmVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJjaGFubmVsSWQiOiIzR210QTdUQ3Axclo1ZkNZbXc2aUcySHFCQlhtTE1ETkdDYVhnU1VhYkJiMyIsImRlcG9zaXQiOiIxMDAwMDAwIiwiZXhwaXJlc0F0IjoxODAwMDAwMzAwLCJmcm9tIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJtYXhBbW91bnQiOiIxMDAwMDAwIiwibm9uY2UiOiI0MjQyIiwib3BlblNsb3QiOiI0MDAwMDAwMDAiLCJvcGVuVHJhbnNhY3Rpb24iOiJBZ0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUJBOGFGdFpILzgvR1RyRUFFN0haWTZvNUJoYzZTcXZsakxvVHFGc21XVTM4TkI1TDkwVFVJU0ttaXhXUWlFYlZMZkoyOURyMVpXQnNpYjVSMUdJQ0FPZ0FJQUNnOW12bjR6TEhwRk16SzluUXAvZmJCVjljWHZHZ2F0cG0yWXM1KzJnUXhIT3VwS2JHUGluRklLdnZWUWV4TXV4Zm1WUjNhdXZyNTdra0llNm1rVVJ0SXNJY0hWa1Z4RG1Xa1lpN1NMM0c2NGVwZEtacTV4TklCdVF6MlZLUjZJdlI1cmhQNVVCWm1RcHVvakNOeGxpRld0bFlwbEhoUlhKaVAzK3RPVDI3QVQ3TnMxOXgrZmNhMzdibTVvNC9oazRYRHVZLzhPeHluTGNYb3l1ZWExam52ekFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFEQmtadjVTRVhNdi9zcmJweXc1dm52SXpsdThYM0Vtc3NRNXM2UUFBQUFBVktVMXFaS1NFR1RTVG9jV0RhT0h4OE5iWGR2Sks3Z2VRZnFFQkJCVVNOQnFmVkZ4a3NYRkVoak1sTVBVcnhmMWphN2dpYm9mMUU0OXZaaWdBQUFBQUczZmJoMTJXaGs5bkw0VWJPNjNtc0hMU0Y3VjliTjVFNmpQV0ZmdjhBcVR0RUxMT1JJVmZ4T3BNOUFUUW9MUU1yWC83TkFhTGI4YmQ1QmdqZkFDNm5XbFFOZTJzZUt5dTFGMUlaeWFQd1lCQ1NRY3FNVHhjTXdjb3RTTzdxK2RDTWx5V1BUaVNKOGJzOUVDa1VqZzJEQzFvVG1kci9FSVFFam52WTIrbjRXWkdpaWd0ME9CV1RwTmxHbFhrZ2lTYXZ5SzJDeUlPYmRrUTFtNTY2bWtzNnA2SDdwT3NyQ1FtVDk5TGYxaXVKNHJoeUIzcGpuOWZYUjZqcG4yUFVGYTRBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBUUdBQVVDZ0JvR0FBWUFDUU5BUzB3QUFBQUFBQTRPQVFBQUNnMENBd1FKQlFnTUN3NURBWklRQUFBQUFBQUFRRUlQQUFBQUFBQ0VBd0FBQUlUWEZ3QUFBQUFCQUFBQXEwNHJNeDVMVHpvVlFycmcrVlhkWFRNRFNjZE9vY2NLa2dYc0JsVUpJak1RSndjQUlEVm1NMk01WVRGbE4ySXlaRFJqTm1VNFpqQmhNV0l5WXpOa05HVTFaall3QUE9PSIsInZhbGlkQWZ0ZXIiOjE4MDAwMDAwMDB9LCJ4NDAyVmVyc2lvbiI6Mn0=", + "x402PaymentHeader": "eyJhY2NlcHRlZCI6eyJhbW91bnQiOiIxMDAwMDAwIiwiYXNzZXQiOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsImV4dHJhIjp7ImZlZVBheWVyIjoiN3Y1NE5XZEJ0a2p1QUZKckxHc1MyU1hudWs4bkthbTgxbVpKZWVZeFZGaTkiLCJyZWNlaXZlckF1dGhvcml6ZXIiOiJBb1ZzR2FqOE1TSjZ4d0t4ZkZ4bzlpWldIM2VuQzhSUlRYS0gyZngyRjhvcyIsInJlY2VudEJsb2NraGFzaCI6IjExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExIiwicmVjZW50U2xvdCI6IjQwMDAwMDAwMCIsInRva2VuUHJvZ3JhbSI6IlRva2Vua2VnUWZlWnlpTndBSmJOYkdLUEZYQ1d1QnZmOVNzNjIzVlE1REEiLCJ3aXRoZHJhd0RlbGF5Ijo5MDB9LCJtYXhUaW1lb3V0U2Vjb25kcyI6MzAwLCJuZXR3b3JrIjoic29sYW5hOkV0V1RSQUJaYVlxNmlNZmVZS291UnUxNjZWVTJ4cWExIiwicGF5VG8iOiJDWGhyRlpKTEtxanptUDNzallMY0Y0ZFRlWFdLQ3k5ZTJTWFhaMllvNk1QWSIsInNjaGVtZSI6InVwdG8ifSwicGF5bG9hZCI6eyJhdXRob3JpemVkU2lnbmVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJjaGFubmVsSWQiOiIzR210QTdUQ3Axclo1ZkNZbXc2aUcySHFCQlhtTE1ETkdDYVhnU1VhYkJiMyIsImRlcG9zaXQiOiIxMDAwMDAwIiwiZXhwaXJlc0F0IjoxODAwMDAwMzAwLCJmcm9tIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJtYXhBbW91bnQiOiIxMDAwMDAwIiwibm9uY2UiOiI0MjQyIiwib3BlblNsb3QiOiI0MDAwMDAwMDAiLCJvcGVuVHJhbnNhY3Rpb24iOiJBZ0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUN5d2cvR1hKdURqaUJaUU9pNzlScUVNMGFIWVRlNHMxWWNubzZlZVpYU0EreEpmL1AwSVB4ekl5ZkFjUStWTENEUk83RVdhci9NeVRkNC9JcHp5UXNMZ0FJQUNnOW12bjR6TEhwRk16SzluUXAvZmJCVjljWHZHZ2F0cG0yWXM1KzJnUXhIT3VwS2JHUGluRklLdnZWUWV4TXV4Zm1WUjNhdXZyNTdra0llNm1rVVJ0SXNJY0hWa1Z4RG1Xa1lpN1NMM0c2NGVwZEtacTV4TklCdVF6MlZLUjZJdlI1cmhQNVVCWm1RcHVvakNOeGxpRld0bFlwbEhoUlhKaVAzK3RPVDI3QVQ3TnMxOXgrZmNhMzdibTVvNC9oazRYRHVZLzhPeHluTGNYb3l1ZWExam52ekFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFEQmtadjVTRVhNdi9zcmJweXc1dm52SXpsdThYM0Vtc3NRNXM2UUFBQUFBVktVMXFaS1NFR1RTVG9jV0RhT0h4OE5iWGR2Sks3Z2VRZnFFQkJCVVNOQnFmVkZ4a3NYRkVoak1sTVBVcnhmMWphN2dpYm9mMUU0OXZaaWdBQUFBQUczZmJoMTJXaGs5bkw0VWJPNjNtc0hMU0Y3VjliTjVFNmpQV0ZmdjhBcVR0RUxMT1JJVmZ4T3BNOUFUUW9MUU1yWC83TkFhTGI4YmQ1QmdqZkFDNm5XbFFOZTJzZUt5dTFGMUlaeWFQd1lCQ1NRY3FNVHhjTXdjb3RTTzdxK2RDTWx5V1BUaVNKOGJzOUVDa1VqZzJEQzFvVG1kci9FSVFFam52WTIrbjRXWkdpaWd0ME9CV1RwTmxHbFhrZ2lTYXZ5SzJDeUlPYmRrUTFtNTY2bWtzNnA2SDdwT3NyQ1FtVDk5TGYxaXVKNHJoeUIzcGpuOWZYUjZqcG4yUFVGYTRBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBUUdBQVVDZ0JvR0FBWUFDUU9JRXdBQUFBQUFBQTRPQVFBQUNnMENBd1FKQlFnTUN3NURBWklRQUFBQUFBQUFRRUlQQUFBQUFBQ0VBd0FBQUlUWEZ3QUFBQUFCQUFBQXEwNHJNeDVMVHpvVlFycmcrVlhkWFRNRFNjZE9vY2NLa2dYc0JsVUpJak1RSndjQUlEVm1NMk01WVRGbE4ySXlaRFJqTm1VNFpqQmhNV0l5WXpOa05HVTFaall3QUE9PSIsInZhbGlkQWZ0ZXIiOjE4MDAwMDAwMDB9LCJ4NDAyVmVyc2lvbiI6Mn0=", "x402ServerAmount": "1000000", "x402ServerCurrency": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", "x402ServerFeePayer": "7v54NWdBtkjuAFJrLGsS2SXnuk8nKam81mZJeeYxVFi9", @@ -889,6 +889,185 @@ }, "tier": "offline" }, + { + "bugType": "auth-bypass", + "description": "SetComputeUnitPrice 5000 with no SetComputeUnitLimit: the runtime budgets 200000 units for each of the open and the memo, a 2000 lamport priority fee, exactly the sponsor's cap (RULINGS S6): accepted. Pair: x402-upto-verify-implicit-limit-priority-fee-over-cap-reject. Verify is the read-only preflight of the deposit settle (Phase 3): every static check before co-signing, at the vector's clock (nowSeconds).", + "expect": { + "outcome": "accept" + }, + "id": "x402-upto-verify-implicit-limit-at-fee-cap-accept", + "input": { + "nowSeconds": 1800000000, + "rpcFixtures": { + "mints": { + "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU": { + "decimals": 6, + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + } + }, + "recentBlockhash": "11111111111111111111111111111111", + "slot": 400000000 + }, + "x402PaymentHeader": "eyJhY2NlcHRlZCI6eyJhbW91bnQiOiIxMDAwMDAwIiwiYXNzZXQiOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsImV4dHJhIjp7ImZlZVBheWVyIjoiN3Y1NE5XZEJ0a2p1QUZKckxHc1MyU1hudWs4bkthbTgxbVpKZWVZeFZGaTkiLCJyZWNlaXZlckF1dGhvcml6ZXIiOiJBb1ZzR2FqOE1TSjZ4d0t4ZkZ4bzlpWldIM2VuQzhSUlRYS0gyZngyRjhvcyIsInJlY2VudEJsb2NraGFzaCI6IjExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExIiwicmVjZW50U2xvdCI6IjQwMDAwMDAwMCIsInRva2VuUHJvZ3JhbSI6IlRva2Vua2VnUWZlWnlpTndBSmJOYkdLUEZYQ1d1QnZmOVNzNjIzVlE1REEiLCJ3aXRoZHJhd0RlbGF5Ijo5MDB9LCJtYXhUaW1lb3V0U2Vjb25kcyI6MzAwLCJuZXR3b3JrIjoic29sYW5hOkV0V1RSQUJaYVlxNmlNZmVZS291UnUxNjZWVTJ4cWExIiwicGF5VG8iOiJDWGhyRlpKTEtxanptUDNzallMY0Y0ZFRlWFdLQ3k5ZTJTWFhaMllvNk1QWSIsInNjaGVtZSI6InVwdG8ifSwicGF5bG9hZCI6eyJhdXRob3JpemVkU2lnbmVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJjaGFubmVsSWQiOiIzR210QTdUQ3Axclo1ZkNZbXc2aUcySHFCQlhtTE1ETkdDYVhnU1VhYkJiMyIsImRlcG9zaXQiOiIxMDAwMDAwIiwiZXhwaXJlc0F0IjoxODAwMDAwMzAwLCJmcm9tIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJtYXhBbW91bnQiOiIxMDAwMDAwIiwibm9uY2UiOiI0MjQyIiwib3BlblNsb3QiOiI0MDAwMDAwMDAiLCJvcGVuVHJhbnNhY3Rpb24iOiJBZ0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUJCeDJzd250THpaWjVSN3R1OGc1cEdmN2poajJpbm0yN2NrazZLV2lqVXpyNTQ3OENRdjV3TVArcCtiWlJlVmZsSUFSdHdRdWpKc0hxZzVHb2dGN0lIZ0FJQUNnOW12bjR6TEhwRk16SzluUXAvZmJCVjljWHZHZ2F0cG0yWXM1KzJnUXhIT3VwS2JHUGluRklLdnZWUWV4TXV4Zm1WUjNhdXZyNTdra0llNm1rVVJ0SXNJY0hWa1Z4RG1Xa1lpN1NMM0c2NGVwZEtacTV4TklCdVF6MlZLUjZJdlI1cmhQNVVCWm1RcHVvakNOeGxpRld0bFlwbEhoUlhKaVAzK3RPVDI3QVQ3TnMxOXgrZmNhMzdibTVvNC9oazRYRHVZLzhPeHluTGNYb3l1ZWExam52ekFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFEQmtadjVTRVhNdi9zcmJweXc1dm52SXpsdThYM0Vtc3NRNXM2UUFBQUFBVktVMXFaS1NFR1RTVG9jV0RhT0h4OE5iWGR2Sks3Z2VRZnFFQkJCVVNOQnFmVkZ4a3NYRkVoak1sTVBVcnhmMWphN2dpYm9mMUU0OXZaaWdBQUFBQUczZmJoMTJXaGs5bkw0VWJPNjNtc0hMU0Y3VjliTjVFNmpQV0ZmdjhBcVR0RUxMT1JJVmZ4T3BNOUFUUW9MUU1yWC83TkFhTGI4YmQ1QmdqZkFDNm5XbFFOZTJzZUt5dTFGMUlaeWFQd1lCQ1NRY3FNVHhjTXdjb3RTTzdxK2RDTWx5V1BUaVNKOGJzOUVDa1VqZzJEQzFvVG1kci9FSVFFam52WTIrbjRXWkdpaWd0ME9CV1RwTmxHbFhrZ2lTYXZ5SzJDeUlPYmRrUTFtNTY2bWtzNnA2SDdwT3NyQ1FtVDk5TGYxaXVKNHJoeUIzcGpuOWZYUjZqcG4yUFVGYTRBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBTUdBQWtEaUJNQUFBQUFBQUFPRGdFQUFBb05BZ01FQ1FVSURBc09Rd0dTRUFBQUFBQUFBRUJDRHdBQUFBQUFoQU1BQUFDRTF4Y0FBQUFBQVFBQUFLdE9Lek1lUzA4NkZVSzY0UGxWM1YwekEwbkhUcUhIQ3BJRjdBWlZDU0l6RUNjSEFDQTFaak5qT1dFeFpUZGlNbVEwWXpabE9HWXdZVEZpTW1NelpEUmxOV1kyTUFBPSIsInZhbGlkQWZ0ZXIiOjE4MDAwMDAwMDB9LCJ4NDAyVmVyc2lvbiI6Mn0=", + "x402ServerAmount": "1000000", + "x402ServerCurrency": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "x402ServerFeePayer": "7v54NWdBtkjuAFJrLGsS2SXnuk8nKam81mZJeeYxVFi9", + "x402ServerFeePayerSecretKey": [ + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 102, + 190, + 126, + 51, + 44, + 122, + 69, + 51, + 50, + 189, + 157, + 10, + 127, + 125, + 176, + 85, + 245, + 197, + 239, + 26, + 6, + 173, + 166, + 109, + 152, + 179, + 159, + 182, + 129, + 12, + 71, + 58 + ], + "x402ServerMaxChannelLifetimeSeconds": 3600, + "x402ServerMaxTimeoutSeconds": 300, + "x402ServerNetwork": "devnet", + "x402ServerReceiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "x402ServerReceiverAuthorizerSecretKey": [ + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 145, + 162, + 138, + 11, + 116, + 56, + 21, + 147, + 164, + 217, + 70, + 149, + 121, + 32, + 137, + 38, + 175, + 200, + 173, + 130, + 200, + 131, + 155, + 118, + 68, + 53, + 155, + 158, + 186, + 154, + 75, + 58 + ], + "x402ServerRecipient": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "x402ServerTokenProgram": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "x402ServerWithdrawDelay": 900 + }, + "intent": "x402-upto", + "mode": "verify-transaction", + "provenance": "generated", + "requirements": [ + "X402-233dcf8a3e", + "X402-443a167ea1", + "X402-3b5914a7c5" + ], + "role": "server", + "spec": { + "doc": "x402/specs/schemes/upto/scheme_upto_svm.md", + "quote": "A sponsor MAY apply a stricter local policy for compute-unit limit, compute-unit price, and required-signature count (operator-configurable caps), but MUST NOT admit a compute-unit limit above 400000 or a compute-unit price above 5000000 microlamports.", + "section": "Top-level instruction layout" + }, + "tier": "offline" + }, { "bugType": "defaults", "description": "The route declares no extra.memo, so the suffix is only bounded at four Lighthouse/Memo instructions; two memos are allowed. Verify is the read-only preflight of the deposit settle (Phase 3): every static check before co-signing, at the vector's clock (nowSeconds).", @@ -1234,12 +1413,12 @@ "mode": "verify-transaction", "provenance": "generated", "requirements": [ - "X402-c1174b72d8" + "X402-4de59a1f27" ], "role": "server", "spec": { "doc": "x402/specs/schemes/upto/scheme_upto_svm.md", - "quote": "The message MAY be legacy or version 0, but it MUST NOT contain Address Lookup Table lookups.", + "quote": "The message version MUST be one advertised in extra.transactionVersions (0 when the field is absent; see [Transaction versions](#transaction-versions)), and the message MUST NOT contain Address Lookup Table lookups.", "section": "Message and signer rules" }, "tier": "offline" @@ -4641,6 +4820,377 @@ }, "tier": "offline" }, + { + "bugType": "auth-bypass", + "description": "SetComputeUnitLimit 400000 and SetComputeUnitPrice 5000000: each at its absolute ceiling, but the sponsor would pay a 2000000 lamport priority fee. The sponsor bounds the fee it pays as limit times price (RULINGS S6): rejected as compute-price-over-cap. Pair: x402-upto-verify-compute-at-caps-accept. Verify is the read-only preflight of the deposit settle (Phase 3): every static check before co-signing, at the vector's clock (nowSeconds).", + "expect": { + "alsoConformant": [ + { + "outcome": "accept" + } + ], + "alsoConformantReason": "the upto and batch-settlement schemes cap the compute unit limit at 400,000 and the unit price at 5,000,000 micro-lamports (or a version-1 priorityFee at 5 lamports per unit) and this transaction is within them; the 2,000 lamport cap on the total fee is pay-kit's stricter local policy, which the schemes allow but do not require (upto: “A sponsor MAY apply a stricter local policy for compute-unit limit, compute-unit price, and required-signature count”; batch-settlement: “A sponsor MAY apply stricter local compute-unit, priority-fee, or required-signature caps”), so a sponsor without it accepts (RULINGS S6).", + "outcome": "reject", + "rejectCode": "compute-price-over-cap" + }, + "id": "x402-upto-verify-priority-fee-over-cap-reject", + "input": { + "nowSeconds": 1800000000, + "rpcFixtures": { + "mints": { + "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU": { + "decimals": 6, + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + } + }, + "recentBlockhash": "11111111111111111111111111111111", + "slot": 400000000 + }, + "x402PaymentHeader": "eyJhY2NlcHRlZCI6eyJhbW91bnQiOiIxMDAwMDAwIiwiYXNzZXQiOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsImV4dHJhIjp7ImZlZVBheWVyIjoiN3Y1NE5XZEJ0a2p1QUZKckxHc1MyU1hudWs4bkthbTgxbVpKZWVZeFZGaTkiLCJyZWNlaXZlckF1dGhvcml6ZXIiOiJBb1ZzR2FqOE1TSjZ4d0t4ZkZ4bzlpWldIM2VuQzhSUlRYS0gyZngyRjhvcyIsInJlY2VudEJsb2NraGFzaCI6IjExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExIiwicmVjZW50U2xvdCI6IjQwMDAwMDAwMCIsInRva2VuUHJvZ3JhbSI6IlRva2Vua2VnUWZlWnlpTndBSmJOYkdLUEZYQ1d1QnZmOVNzNjIzVlE1REEiLCJ3aXRoZHJhd0RlbGF5Ijo5MDB9LCJtYXhUaW1lb3V0U2Vjb25kcyI6MzAwLCJuZXR3b3JrIjoic29sYW5hOkV0V1RSQUJaYVlxNmlNZmVZS291UnUxNjZWVTJ4cWExIiwicGF5VG8iOiJDWGhyRlpKTEtxanptUDNzallMY0Y0ZFRlWFdLQ3k5ZTJTWFhaMllvNk1QWSIsInNjaGVtZSI6InVwdG8ifSwicGF5bG9hZCI6eyJhdXRob3JpemVkU2lnbmVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJjaGFubmVsSWQiOiIzR210QTdUQ3Axclo1ZkNZbXc2aUcySHFCQlhtTE1ETkdDYVhnU1VhYkJiMyIsImRlcG9zaXQiOiIxMDAwMDAwIiwiZXhwaXJlc0F0IjoxODAwMDAwMzAwLCJmcm9tIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJtYXhBbW91bnQiOiIxMDAwMDAwIiwibm9uY2UiOiI0MjQyIiwib3BlblNsb3QiOiI0MDAwMDAwMDAiLCJvcGVuVHJhbnNhY3Rpb24iOiJBZ0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUJBOGFGdFpILzgvR1RyRUFFN0haWTZvNUJoYzZTcXZsakxvVHFGc21XVTM4TkI1TDkwVFVJU0ttaXhXUWlFYlZMZkoyOURyMVpXQnNpYjVSMUdJQ0FPZ0FJQUNnOW12bjR6TEhwRk16SzluUXAvZmJCVjljWHZHZ2F0cG0yWXM1KzJnUXhIT3VwS2JHUGluRklLdnZWUWV4TXV4Zm1WUjNhdXZyNTdra0llNm1rVVJ0SXNJY0hWa1Z4RG1Xa1lpN1NMM0c2NGVwZEtacTV4TklCdVF6MlZLUjZJdlI1cmhQNVVCWm1RcHVvakNOeGxpRld0bFlwbEhoUlhKaVAzK3RPVDI3QVQ3TnMxOXgrZmNhMzdibTVvNC9oazRYRHVZLzhPeHluTGNYb3l1ZWExam52ekFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFEQmtadjVTRVhNdi9zcmJweXc1dm52SXpsdThYM0Vtc3NRNXM2UUFBQUFBVktVMXFaS1NFR1RTVG9jV0RhT0h4OE5iWGR2Sks3Z2VRZnFFQkJCVVNOQnFmVkZ4a3NYRkVoak1sTVBVcnhmMWphN2dpYm9mMUU0OXZaaWdBQUFBQUczZmJoMTJXaGs5bkw0VWJPNjNtc0hMU0Y3VjliTjVFNmpQV0ZmdjhBcVR0RUxMT1JJVmZ4T3BNOUFUUW9MUU1yWC83TkFhTGI4YmQ1QmdqZkFDNm5XbFFOZTJzZUt5dTFGMUlaeWFQd1lCQ1NRY3FNVHhjTXdjb3RTTzdxK2RDTWx5V1BUaVNKOGJzOUVDa1VqZzJEQzFvVG1kci9FSVFFam52WTIrbjRXWkdpaWd0ME9CV1RwTmxHbFhrZ2lTYXZ5SzJDeUlPYmRrUTFtNTY2bWtzNnA2SDdwT3NyQ1FtVDk5TGYxaXVKNHJoeUIzcGpuOWZYUjZqcG4yUFVGYTRBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBUUdBQVVDZ0JvR0FBWUFDUU5BUzB3QUFBQUFBQTRPQVFBQUNnMENBd1FKQlFnTUN3NURBWklRQUFBQUFBQUFRRUlQQUFBQUFBQ0VBd0FBQUlUWEZ3QUFBQUFCQUFBQXEwNHJNeDVMVHpvVlFycmcrVlhkWFRNRFNjZE9vY2NLa2dYc0JsVUpJak1RSndjQUlEVm1NMk01WVRGbE4ySXlaRFJqTm1VNFpqQmhNV0l5WXpOa05HVTFaall3QUE9PSIsInZhbGlkQWZ0ZXIiOjE4MDAwMDAwMDB9LCJ4NDAyVmVyc2lvbiI6Mn0=", + "x402ServerAmount": "1000000", + "x402ServerCurrency": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "x402ServerFeePayer": "7v54NWdBtkjuAFJrLGsS2SXnuk8nKam81mZJeeYxVFi9", + "x402ServerFeePayerSecretKey": [ + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 102, + 190, + 126, + 51, + 44, + 122, + 69, + 51, + 50, + 189, + 157, + 10, + 127, + 125, + 176, + 85, + 245, + 197, + 239, + 26, + 6, + 173, + 166, + 109, + 152, + 179, + 159, + 182, + 129, + 12, + 71, + 58 + ], + "x402ServerMaxChannelLifetimeSeconds": 3600, + "x402ServerMaxTimeoutSeconds": 300, + "x402ServerNetwork": "devnet", + "x402ServerReceiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "x402ServerReceiverAuthorizerSecretKey": [ + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 145, + 162, + 138, + 11, + 116, + 56, + 21, + 147, + 164, + 217, + 70, + 149, + 121, + 32, + 137, + 38, + 175, + 200, + 173, + 130, + 200, + 131, + 155, + 118, + 68, + 53, + 155, + 158, + 186, + 154, + 75, + 58 + ], + "x402ServerRecipient": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "x402ServerTokenProgram": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "x402ServerWithdrawDelay": 900 + }, + "intent": "x402-upto", + "mode": "verify-transaction", + "provenance": "generated", + "requirements": [ + "X402-b4167aad45", + "X402-233dcf8a3e", + "X402-3b5914a7c5" + ], + "role": "server", + "spec": { + "doc": "x402/specs/schemes/upto/scheme_upto_svm.md", + "quote": "A sponsor MAY apply a stricter local policy for compute-unit limit, compute-unit price, and required-signature count (operator-configurable caps), but MUST NOT admit a compute-unit limit above 400000 or a compute-unit price above 5000000 microlamports.", + "section": "Top-level instruction layout" + }, + "tier": "offline" + }, + { + "bugType": "auth-bypass", + "description": "SetComputeUnitPrice 5001 with no SetComputeUnitLimit: the runtime budgets 200000 units for each of the open and the memo, so the sponsor would pay 2001 lamports, one over its cap (RULINGS S6). A verifier that bounds only declared limits accepts it: rejected as compute-price-over-cap. Pair: x402-upto-verify-implicit-limit-at-fee-cap-accept. Verify is the read-only preflight of the deposit settle (Phase 3): every static check before co-signing, at the vector's clock (nowSeconds).", + "expect": { + "alsoConformant": [ + { + "outcome": "accept" + } + ], + "alsoConformantReason": "the upto and batch-settlement schemes cap the compute unit limit at 400,000 and the unit price at 5,000,000 micro-lamports (or a version-1 priorityFee at 5 lamports per unit) and this transaction is within them; the 2,000 lamport cap on the total fee is pay-kit's stricter local policy, which the schemes allow but do not require (upto: “A sponsor MAY apply a stricter local policy for compute-unit limit, compute-unit price, and required-signature count”; batch-settlement: “A sponsor MAY apply stricter local compute-unit, priority-fee, or required-signature caps”), so a sponsor without it accepts (RULINGS S6).", + "outcome": "reject", + "rejectCode": "compute-price-over-cap" + }, + "id": "x402-upto-verify-implicit-limit-priority-fee-over-cap-reject", + "input": { + "nowSeconds": 1800000000, + "rpcFixtures": { + "mints": { + "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU": { + "decimals": 6, + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + } + }, + "recentBlockhash": "11111111111111111111111111111111", + "slot": 400000000 + }, + "x402PaymentHeader": "eyJhY2NlcHRlZCI6eyJhbW91bnQiOiIxMDAwMDAwIiwiYXNzZXQiOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsImV4dHJhIjp7ImZlZVBheWVyIjoiN3Y1NE5XZEJ0a2p1QUZKckxHc1MyU1hudWs4bkthbTgxbVpKZWVZeFZGaTkiLCJyZWNlaXZlckF1dGhvcml6ZXIiOiJBb1ZzR2FqOE1TSjZ4d0t4ZkZ4bzlpWldIM2VuQzhSUlRYS0gyZngyRjhvcyIsInJlY2VudEJsb2NraGFzaCI6IjExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExIiwicmVjZW50U2xvdCI6IjQwMDAwMDAwMCIsInRva2VuUHJvZ3JhbSI6IlRva2Vua2VnUWZlWnlpTndBSmJOYkdLUEZYQ1d1QnZmOVNzNjIzVlE1REEiLCJ3aXRoZHJhd0RlbGF5Ijo5MDB9LCJtYXhUaW1lb3V0U2Vjb25kcyI6MzAwLCJuZXR3b3JrIjoic29sYW5hOkV0V1RSQUJaYVlxNmlNZmVZS291UnUxNjZWVTJ4cWExIiwicGF5VG8iOiJDWGhyRlpKTEtxanptUDNzallMY0Y0ZFRlWFdLQ3k5ZTJTWFhaMllvNk1QWSIsInNjaGVtZSI6InVwdG8ifSwicGF5bG9hZCI6eyJhdXRob3JpemVkU2lnbmVyIjoiQW9Wc0dhajhNU0o2eHdLeGZGeG85aVpXSDNlbkM4UlJUWEtIMmZ4MkY4b3MiLCJjaGFubmVsSWQiOiIzR210QTdUQ3Axclo1ZkNZbXc2aUcySHFCQlhtTE1ETkdDYVhnU1VhYkJiMyIsImRlcG9zaXQiOiIxMDAwMDAwIiwiZXhwaXJlc0F0IjoxODAwMDAwMzAwLCJmcm9tIjoiR21hRHJwcEJDN1A1QVJLVjhnM2RqaXdQODl2ejFqTEsyM1YyR0JqdUFFR0IiLCJtYXhBbW91bnQiOiIxMDAwMDAwIiwibm9uY2UiOiI0MjQyIiwib3BlblNsb3QiOiI0MDAwMDAwMDAiLCJvcGVuVHJhbnNhY3Rpb24iOiJBZ0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFDNTArWXhxVEJrdlhuNEh2a3hEL2poUEt1aDNQNzB2d1lSeXpHS3BCK2IzUSt6Z2ZEREQ4cVlieXFMR1AvSGI5b2JIdU5CZ2dVTVEwYnIyT2VUK3NBZ0FJQUNnOW12bjR6TEhwRk16SzluUXAvZmJCVjljWHZHZ2F0cG0yWXM1KzJnUXhIT3VwS2JHUGluRklLdnZWUWV4TXV4Zm1WUjNhdXZyNTdra0llNm1rVVJ0SXNJY0hWa1Z4RG1Xa1lpN1NMM0c2NGVwZEtacTV4TklCdVF6MlZLUjZJdlI1cmhQNVVCWm1RcHVvakNOeGxpRld0bFlwbEhoUlhKaVAzK3RPVDI3QVQ3TnMxOXgrZmNhMzdibTVvNC9oazRYRHVZLzhPeHluTGNYb3l1ZWExam52ekFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFEQmtadjVTRVhNdi9zcmJweXc1dm52SXpsdThYM0Vtc3NRNXM2UUFBQUFBVktVMXFaS1NFR1RTVG9jV0RhT0h4OE5iWGR2Sks3Z2VRZnFFQkJCVVNOQnFmVkZ4a3NYRkVoak1sTVBVcnhmMWphN2dpYm9mMUU0OXZaaWdBQUFBQUczZmJoMTJXaGs5bkw0VWJPNjNtc0hMU0Y3VjliTjVFNmpQV0ZmdjhBcVR0RUxMT1JJVmZ4T3BNOUFUUW9MUU1yWC83TkFhTGI4YmQ1QmdqZkFDNm5XbFFOZTJzZUt5dTFGMUlaeWFQd1lCQ1NRY3FNVHhjTXdjb3RTTzdxK2RDTWx5V1BUaVNKOGJzOUVDa1VqZzJEQzFvVG1kci9FSVFFam52WTIrbjRXWkdpaWd0ME9CV1RwTmxHbFhrZ2lTYXZ5SzJDeUlPYmRrUTFtNTY2bWtzNnA2SDdwT3NyQ1FtVDk5TGYxaXVKNHJoeUIzcGpuOWZYUjZqcG4yUFVGYTRBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBTUdBQWtEaVJNQUFBQUFBQUFPRGdFQUFBb05BZ01FQ1FVSURBc09Rd0dTRUFBQUFBQUFBRUJDRHdBQUFBQUFoQU1BQUFDRTF4Y0FBQUFBQVFBQUFLdE9Lek1lUzA4NkZVSzY0UGxWM1YwekEwbkhUcUhIQ3BJRjdBWlZDU0l6RUNjSEFDQTFaak5qT1dFeFpUZGlNbVEwWXpabE9HWXdZVEZpTW1NelpEUmxOV1kyTUFBPSIsInZhbGlkQWZ0ZXIiOjE4MDAwMDAwMDB9LCJ4NDAyVmVyc2lvbiI6Mn0=", + "x402ServerAmount": "1000000", + "x402ServerCurrency": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "x402ServerFeePayer": "7v54NWdBtkjuAFJrLGsS2SXnuk8nKam81mZJeeYxVFi9", + "x402ServerFeePayerSecretKey": [ + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 102, + 190, + 126, + 51, + 44, + 122, + 69, + 51, + 50, + 189, + 157, + 10, + 127, + 125, + 176, + 85, + 245, + 197, + 239, + 26, + 6, + 173, + 166, + 109, + 152, + 179, + 159, + 182, + 129, + 12, + 71, + 58 + ], + "x402ServerMaxChannelLifetimeSeconds": 3600, + "x402ServerMaxTimeoutSeconds": 300, + "x402ServerNetwork": "devnet", + "x402ServerReceiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "x402ServerReceiverAuthorizerSecretKey": [ + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 145, + 162, + 138, + 11, + 116, + 56, + 21, + 147, + 164, + 217, + 70, + 149, + 121, + 32, + 137, + 38, + 175, + 200, + 173, + 130, + 200, + 131, + 155, + 118, + 68, + 53, + 155, + 158, + 186, + 154, + 75, + 58 + ], + "x402ServerRecipient": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "x402ServerTokenProgram": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "x402ServerWithdrawDelay": 900 + }, + "intent": "x402-upto", + "mode": "verify-transaction", + "provenance": "generated", + "requirements": [ + "X402-233dcf8a3e", + "X402-3b5914a7c5" + ], + "role": "server", + "spec": { + "doc": "x402/specs/schemes/upto/scheme_upto_svm.md", + "quote": "A sponsor MAY apply a stricter local policy for compute-unit limit, compute-unit price, and required-signature count (operator-configurable caps), but MUST NOT admit a compute-unit limit above 400000 or a compute-unit price above 5000000 microlamports.", + "section": "Top-level instruction layout" + }, + "tier": "offline" + }, { "bugType": "auth-bypass", "description": "ComputeBudget prefix replaced (2 instructions): rejected as compute-limit-over-cap. Verify is the read-only preflight of the deposit settle (Phase 3): every static check before co-signing, at the vector's clock (nowSeconds).", @@ -5171,7 +5721,7 @@ "role": "server", "spec": { "doc": "x402/specs/schemes/upto/scheme_upto_svm.md", - "quote": "An optional Compute Budget prefix containing at most one SetComputeUnitLimit instruction and at most one SetComputeUnitPrice instruction.", + "quote": "In a legacy or version-0 transaction, an optional Compute Budget prefix containing at most one SetComputeUnitLimit instruction and at most one SetComputeUnitPrice instruction.", "section": "Top-level instruction layout" }, "tier": "offline" @@ -5349,7 +5899,7 @@ "role": "server", "spec": { "doc": "x402/specs/schemes/upto/scheme_upto_svm.md", - "quote": "An optional Compute Budget prefix containing at most one SetComputeUnitLimit instruction and at most one SetComputeUnitPrice instruction.", + "quote": "In a legacy or version-0 transaction, an optional Compute Budget prefix containing at most one SetComputeUnitLimit instruction and at most one SetComputeUnitPrice instruction.", "section": "Top-level instruction layout" }, "tier": "offline" diff --git a/harness/vectors/x402-upto-txv1.json b/harness/vectors/x402-upto-txv1.json index 437c03517..71f34595c 100644 --- a/harness/vectors/x402-upto-txv1.json +++ b/harness/vectors/x402-upto-txv1.json @@ -238,7 +238,7 @@ "provenance": "generated", "requirements": [ "X402TX-61c735c7a9", - "X402TX-644919eb3b", + "X402TX-f9bcc1a14a", "X402TX-d444d01b9e" ], "role": "client", @@ -843,6 +843,9 @@ ], "x402ServerRecipient": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", "x402ServerTokenProgram": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "x402ServerTransactionVersions": [ + 0 + ], "x402ServerWithdrawDelay": 900 }, "intent": "x402-upto", @@ -1022,6 +1025,9 @@ ], "x402ServerRecipient": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", "x402ServerTokenProgram": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "x402ServerTransactionVersions": [ + 0 + ], "x402ServerWithdrawDelay": 900 }, "intent": "x402-upto", @@ -1210,13 +1216,13 @@ "mode": "verify-transaction", "provenance": "generated", "requirements": [ - "X402TX-936b492daa", + "X402TX-915632f040", "X402TX-125d312b26" ], "role": "server", "spec": { "doc": "x402-txv1/specs/schemes/upto/scheme_upto_svm.md", - "quote": "A version-1 transaction that contains a Compute Budget instruction MUST be rejected.", + "quote": "A version-1 transaction that contains a Compute Budget instruction MUST be rejected (an x402 sponsor rule; the runtime treats such instructions as no-ops).", "section": "Top-level instruction layout" }, "tier": "offline" @@ -1393,19 +1399,19 @@ "mode": "verify-transaction", "provenance": "generated", "requirements": [ - "X402TX-0f874a9c63" + "X402TX-703c03cfb5" ], "role": "server", "spec": { "doc": "x402-txv1/specs/schemes/upto/scheme_upto_svm.md", - "quote": "In a version-1 transaction the same caps apply to the message TransactionConfig instead: computeUnitLimit MUST be present and MUST NOT exceed 400000, loadedAccountsDataSizeLimit MUST be present, and priorityFee (total lamports) MUST satisfy priorityFee 1000000 <= 5000000 computeUnitLimit.", + "quote": "computeUnitLimit (bit 2) MUST be set and MUST NOT exceed 400000, loadedAccountsDataSizeLimit (bit 3) MUST be set, and priorityFee (bits 0 and 1, total lamports) MUST satisfy priorityFee * 1000000 <= 5000000 * computeUnitLimit, evaluated without overflow.", "section": "Top-level instruction layout" }, "tier": "offline" }, { "bugType": "auth-bypass", - "description": "A version-1 open at 200000 units with priorityFee 1000001 lamports (priorityFee * 1000000 > 5000000 * computeUnitLimit): rejected as compute-price-over-cap. Verify is the read-only preflight of the deposit settle (Phase 3): every static check before co-signing, at the vector's clock (nowSeconds).", + "description": "A version-1 open at 300 units with priorityFee 1501 lamports (priorityFee * 1000000 > 5000000 * computeUnitLimit), still under the 2000 lamport cap on the total fee, so only the per-unit rule rejects it: rejected as compute-price-over-cap. Verify is the read-only preflight of the deposit settle (Phase 3): every static check before co-signing, at the vector's clock (nowSeconds).", "expect": { "outcome": "reject", "rejectCode": "compute-price-over-cap" @@ -1423,7 +1429,7 @@ "recentBlockhash": "11111111111111111111111111111111", "slot": 400000000 }, - "x402PaymentHeader": "eyJhY2NlcHRlZCI6eyJhbW91bnQiOiIxMDAwMDAwIiwiYXNzZXQiOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsImV4dHJhIjp7ImZlZVBheWVyIjoiN3Y1NE5XZEJ0a2p1QUZKckxHc1MyU1hudWs4bkthbTgxbVpKZWVZeFZGaTkiLCJyZWNlaXZlckF1dGhvcml6ZXIiOiJBb1ZzR2FqOE1TSjZ4d0t4ZkZ4bzlpWldIM2VuQzhSUlRYS0gyZngyRjhvcyIsInJlY2VudEJsb2NraGFzaCI6IjExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExIiwicmVjZW50U2xvdCI6IjQwMDAwMDAwMCIsInRva2VuUHJvZ3JhbSI6IlRva2Vua2VnUWZlWnlpTndBSmJOYkdLUEZYQ1d1QnZmOVNzNjIzVlE1REEiLCJ0cmFuc2FjdGlvblZlcnNpb25zIjpbMCwxXSwid2l0aGRyYXdEZWxheSI6OTAwfSwibWF4VGltZW91dFNlY29uZHMiOjMwMCwibmV0d29yayI6InNvbGFuYTpFdFdUUkFCWmFZcTZpTWZlWUtvdVJ1MTY2VlUyeHFhMSIsInBheVRvIjoiQ1hockZaSkxLcWp6bVAzc2pZTGNGNGRUZVhXS0N5OWUyU1hYWjJZbzZNUFkiLCJzY2hlbWUiOiJ1cHRvIn0sInBheWxvYWQiOnsiYXV0aG9yaXplZFNpZ25lciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwiY2hhbm5lbElkIjoiM0dtdEE3VENwMXJaNWZDWW13NmlHMkhxQkJYbUxNRE5HQ2FYZ1NVYWJCYjMiLCJkZXBvc2l0IjoiMTAwMDAwMCIsImV4cGlyZXNBdCI6MTgwMDAwMDMwMCwiZnJvbSI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwibWF4QW1vdW50IjoiMTAwMDAwMCIsIm5vbmNlIjoiNDI0MiIsIm9wZW5TbG90IjoiNDAwMDAwMDAwIiwib3BlblRyYW5zYWN0aW9uIjoiZ1FJQUNROEFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBSU9acjUrTXl4NlJUTXl2WjBLZjMyd1ZmWEY3eG9HcmFadG1MT2Z0b0VNUnpycVNteGo0cHhTQ3I3MVVIc1RMc1g1bFVkMnJyNitlNUpDSHVwcEZFYlNMQ0hCMVpGY1E1bHBHSXUwaTl4dXVIcVhTbWF1Y1RTQWJrTTlsU2tlaUwwZWE0VCtWQVdaa0ticUl3amNaWWhWclpXS1pSNFVWeVlqOS9yVGs5dXdFK3piTmZjZm4zR3QrMjV1YU9QNFpPRnc3bVAvRHNjcHkzRjZNcm5tdFk1Nzh3QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQlVwVFdwa3BJUVpOSk9oeFlObzRmSHcxdGQyOGtydUI1QitvUUVFRlJJMEdwOVVYR1N4Y1VTR015VXc5U3ZGL1dOcnVDSnVoL1VUajI5bUtBQUFBQUFiZDl1SFhaYUdUMmN2aFJzN3JlYXdjdElYdFgxczNrVHFNOVlWKy93Q3BPMFFzczVFaFYvRTZrejBCTkNndEF5dGYvczBCb3R2eHQza0dDTjhBTHFkYVZBMTdheDRySzdVWFVobkpvL0JnRUpKQnlveFBGd3pCeWkxSTd1cjUwSXlYSlk5T0pJbnh1ejBRS1JTT0RZTUxXaE9aMnY4UWhBU09lOWpiNmZoWmthS0tDM1E0RlpPazJVYVZlU0NKSnEvSXJZTElnNXQyUkRXYm5ycWFTenFub2Z1azZ5c0pDWlAzMHQvV0s0bml1SElIZW1PZjE5ZEhxT21mWTlRVnJrRkNEd0FBQUFBQVFBMERBQUFBQUFRTkRrTUFCZ0FnQUFFQUFBa01BZ01FQ0FVSEN3b05BWklRQUFBQUFBQUFRRUlQQUFBQUFBQ0VBd0FBQUlUWEZ3QUFBQUFCQUFBQXEwNHJNeDVMVHpvVlFycmcrVlhkWFRNRFNjZE9vY2NLa2dYc0JsVUpJak1RSnpWbU0yTTVZVEZsTjJJeVpEUmpObVU0WmpCaE1XSXlZek5rTkdVMVpqWXdBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBSjRUMDQySmRLRHBoNW9VYlp6QmNUN1RCNXA0WVY4TVBvZFdLRktaQk5nN29WVEFxSzlmWFNDNjdrUGpSeVdmVjhFOFdWSXJYU0R5U2MyRnlGYzB6UTA9IiwidmFsaWRBZnRlciI6MTgwMDAwMDAwMH0sIng0MDJWZXJzaW9uIjoyfQ==", + "x402PaymentHeader": "eyJhY2NlcHRlZCI6eyJhbW91bnQiOiIxMDAwMDAwIiwiYXNzZXQiOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsImV4dHJhIjp7ImZlZVBheWVyIjoiN3Y1NE5XZEJ0a2p1QUZKckxHc1MyU1hudWs4bkthbTgxbVpKZWVZeFZGaTkiLCJyZWNlaXZlckF1dGhvcml6ZXIiOiJBb1ZzR2FqOE1TSjZ4d0t4ZkZ4bzlpWldIM2VuQzhSUlRYS0gyZngyRjhvcyIsInJlY2VudEJsb2NraGFzaCI6IjExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExIiwicmVjZW50U2xvdCI6IjQwMDAwMDAwMCIsInRva2VuUHJvZ3JhbSI6IlRva2Vua2VnUWZlWnlpTndBSmJOYkdLUEZYQ1d1QnZmOVNzNjIzVlE1REEiLCJ0cmFuc2FjdGlvblZlcnNpb25zIjpbMCwxXSwid2l0aGRyYXdEZWxheSI6OTAwfSwibWF4VGltZW91dFNlY29uZHMiOjMwMCwibmV0d29yayI6InNvbGFuYTpFdFdUUkFCWmFZcTZpTWZlWUtvdVJ1MTY2VlUyeHFhMSIsInBheVRvIjoiQ1hockZaSkxLcWp6bVAzc2pZTGNGNGRUZVhXS0N5OWUyU1hYWjJZbzZNUFkiLCJzY2hlbWUiOiJ1cHRvIn0sInBheWxvYWQiOnsiYXV0aG9yaXplZFNpZ25lciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwiY2hhbm5lbElkIjoiM0dtdEE3VENwMXJaNWZDWW13NmlHMkhxQkJYbUxNRE5HQ2FYZ1NVYWJCYjMiLCJkZXBvc2l0IjoiMTAwMDAwMCIsImV4cGlyZXNBdCI6MTgwMDAwMDMwMCwiZnJvbSI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwibWF4QW1vdW50IjoiMTAwMDAwMCIsIm5vbmNlIjoiNDI0MiIsIm9wZW5TbG90IjoiNDAwMDAwMDAwIiwib3BlblRyYW5zYWN0aW9uIjoiZ1FJQUNROEFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBSU9acjUrTXl4NlJUTXl2WjBLZjMyd1ZmWEY3eG9HcmFadG1MT2Z0b0VNUnpycVNteGo0cHhTQ3I3MVVIc1RMc1g1bFVkMnJyNitlNUpDSHVwcEZFYlNMQ0hCMVpGY1E1bHBHSXUwaTl4dXVIcVhTbWF1Y1RTQWJrTTlsU2tlaUwwZWE0VCtWQVdaa0ticUl3amNaWWhWclpXS1pSNFVWeVlqOS9yVGs5dXdFK3piTmZjZm4zR3QrMjV1YU9QNFpPRnc3bVAvRHNjcHkzRjZNcm5tdFk1Nzh3QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQlVwVFdwa3BJUVpOSk9oeFlObzRmSHcxdGQyOGtydUI1QitvUUVFRlJJMEdwOVVYR1N4Y1VTR015VXc5U3ZGL1dOcnVDSnVoL1VUajI5bUtBQUFBQUFiZDl1SFhaYUdUMmN2aFJzN3JlYXdjdElYdFgxczNrVHFNOVlWKy93Q3BPMFFzczVFaFYvRTZrejBCTkNndEF5dGYvczBCb3R2eHQza0dDTjhBTHFkYVZBMTdheDRySzdVWFVobkpvL0JnRUpKQnlveFBGd3pCeWkxSTd1cjUwSXlYSlk5T0pJbnh1ejBRS1JTT0RZTUxXaE9aMnY4UWhBU09lOWpiNmZoWmthS0tDM1E0RlpPazJVYVZlU0NKSnEvSXJZTElnNXQyUkRXYm5ycWFTenFub2Z1azZ5c0pDWlAzMHQvV0s0bml1SElIZW1PZjE5ZEhxT21mWTlRVnJ0MEZBQUFBQUFBQUxBRUFBQUFBQUFRTkRrTUFCZ0FnQUFFQUFBa01BZ01FQ0FVSEN3b05BWklRQUFBQUFBQUFRRUlQQUFBQUFBQ0VBd0FBQUlUWEZ3QUFBQUFCQUFBQXEwNHJNeDVMVHpvVlFycmcrVlhkWFRNRFNjZE9vY2NLa2dYc0JsVUpJak1RSnpWbU0yTTVZVEZsTjJJeVpEUmpObVU0WmpCaE1XSXlZek5rTkdVMVpqWXdBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBTGdEdnR1U0lmYm0yRHN1OWZIN01pMStJV3ZPUHFnNVRLQUdrU1Q5M2VGYWU1SWZ5dzlXR0ZtekJ5RFVFUDBzaXh4SWJnQitBM0luN3hZVE9UbUZLUWc9IiwidmFsaWRBZnRlciI6MTgwMDAwMDAwMH0sIng0MDJWZXJzaW9uIjoyfQ==", "x402ServerAmount": "1000000", "x402ServerCurrency": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", "x402ServerFeePayer": "7v54NWdBtkjuAFJrLGsS2SXnuk8nKam81mZJeeYxVFi9", @@ -1575,19 +1581,19 @@ "mode": "verify-transaction", "provenance": "generated", "requirements": [ - "X402TX-0f874a9c63" + "X402TX-703c03cfb5" ], "role": "server", "spec": { "doc": "x402-txv1/specs/schemes/upto/scheme_upto_svm.md", - "quote": "In a version-1 transaction the same caps apply to the message TransactionConfig instead: computeUnitLimit MUST be present and MUST NOT exceed 400000, loadedAccountsDataSizeLimit MUST be present, and priorityFee (total lamports) MUST satisfy priorityFee 1000000 <= 5000000 computeUnitLimit.", + "quote": "computeUnitLimit (bit 2) MUST be set and MUST NOT exceed 400000, loadedAccountsDataSizeLimit (bit 3) MUST be set, and priorityFee (bits 0 and 1, total lamports) MUST satisfy priorityFee * 1000000 <= 5000000 * computeUnitLimit, evaluated without overflow.", "section": "Top-level instruction layout" }, "tier": "offline" }, { "bugType": "auth-bypass", - "description": "A version-1 open at 200000 units with priorityFee 1000000 lamports: exactly 5000000 micro-lamports per unit, accepted. Verify is the read-only preflight of the deposit settle (Phase 3): every static check before co-signing, at the vector's clock (nowSeconds).", + "description": "A version-1 open at 300 units with priorityFee 1500 lamports: exactly 5000000 micro-lamports per unit and under the 2000 lamport cap a sponsor puts on the total fee (RULINGS S6), accepted. Verify is the read-only preflight of the deposit settle (Phase 3): every static check before co-signing, at the vector's clock (nowSeconds).", "expect": { "outcome": "accept" }, @@ -1604,7 +1610,195 @@ "recentBlockhash": "11111111111111111111111111111111", "slot": 400000000 }, - "x402PaymentHeader": "eyJhY2NlcHRlZCI6eyJhbW91bnQiOiIxMDAwMDAwIiwiYXNzZXQiOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsImV4dHJhIjp7ImZlZVBheWVyIjoiN3Y1NE5XZEJ0a2p1QUZKckxHc1MyU1hudWs4bkthbTgxbVpKZWVZeFZGaTkiLCJyZWNlaXZlckF1dGhvcml6ZXIiOiJBb1ZzR2FqOE1TSjZ4d0t4ZkZ4bzlpWldIM2VuQzhSUlRYS0gyZngyRjhvcyIsInJlY2VudEJsb2NraGFzaCI6IjExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExIiwicmVjZW50U2xvdCI6IjQwMDAwMDAwMCIsInRva2VuUHJvZ3JhbSI6IlRva2Vua2VnUWZlWnlpTndBSmJOYkdLUEZYQ1d1QnZmOVNzNjIzVlE1REEiLCJ0cmFuc2FjdGlvblZlcnNpb25zIjpbMCwxXSwid2l0aGRyYXdEZWxheSI6OTAwfSwibWF4VGltZW91dFNlY29uZHMiOjMwMCwibmV0d29yayI6InNvbGFuYTpFdFdUUkFCWmFZcTZpTWZlWUtvdVJ1MTY2VlUyeHFhMSIsInBheVRvIjoiQ1hockZaSkxLcWp6bVAzc2pZTGNGNGRUZVhXS0N5OWUyU1hYWjJZbzZNUFkiLCJzY2hlbWUiOiJ1cHRvIn0sInBheWxvYWQiOnsiYXV0aG9yaXplZFNpZ25lciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwiY2hhbm5lbElkIjoiM0dtdEE3VENwMXJaNWZDWW13NmlHMkhxQkJYbUxNRE5HQ2FYZ1NVYWJCYjMiLCJkZXBvc2l0IjoiMTAwMDAwMCIsImV4cGlyZXNBdCI6MTgwMDAwMDMwMCwiZnJvbSI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwibWF4QW1vdW50IjoiMTAwMDAwMCIsIm5vbmNlIjoiNDI0MiIsIm9wZW5TbG90IjoiNDAwMDAwMDAwIiwib3BlblRyYW5zYWN0aW9uIjoiZ1FJQUNROEFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBSU9acjUrTXl4NlJUTXl2WjBLZjMyd1ZmWEY3eG9HcmFadG1MT2Z0b0VNUnpycVNteGo0cHhTQ3I3MVVIc1RMc1g1bFVkMnJyNitlNUpDSHVwcEZFYlNMQ0hCMVpGY1E1bHBHSXUwaTl4dXVIcVhTbWF1Y1RTQWJrTTlsU2tlaUwwZWE0VCtWQVdaa0ticUl3amNaWWhWclpXS1pSNFVWeVlqOS9yVGs5dXdFK3piTmZjZm4zR3QrMjV1YU9QNFpPRnc3bVAvRHNjcHkzRjZNcm5tdFk1Nzh3QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQlVwVFdwa3BJUVpOSk9oeFlObzRmSHcxdGQyOGtydUI1QitvUUVFRlJJMEdwOVVYR1N4Y1VTR015VXc5U3ZGL1dOcnVDSnVoL1VUajI5bUtBQUFBQUFiZDl1SFhaYUdUMmN2aFJzN3JlYXdjdElYdFgxczNrVHFNOVlWKy93Q3BPMFFzczVFaFYvRTZrejBCTkNndEF5dGYvczBCb3R2eHQza0dDTjhBTHFkYVZBMTdheDRySzdVWFVobkpvL0JnRUpKQnlveFBGd3pCeWkxSTd1cjUwSXlYSlk5T0pJbnh1ejBRS1JTT0RZTUxXaE9aMnY4UWhBU09lOWpiNmZoWmthS0tDM1E0RlpPazJVYVZlU0NKSnEvSXJZTElnNXQyUkRXYm5ycWFTenFub2Z1azZ5c0pDWlAzMHQvV0s0bml1SElIZW1PZjE5ZEhxT21mWTlRVnJrQkNEd0FBQUFBQVFBMERBQUFBQUFRTkRrTUFCZ0FnQUFFQUFBa01BZ01FQ0FVSEN3b05BWklRQUFBQUFBQUFRRUlQQUFBQUFBQ0VBd0FBQUlUWEZ3QUFBQUFCQUFBQXEwNHJNeDVMVHpvVlFycmcrVlhkWFRNRFNjZE9vY2NLa2dYc0JsVUpJak1RSnpWbU0yTTVZVEZsTjJJeVpEUmpObVU0WmpCaE1XSXlZek5rTkdVMVpqWXdBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBS3hiRmNxdUxsSlNQVmMxSWNkN2tHVDA1K2d3MFAzZlhMTjZMVWZ2QnBteTVhZ0kvWHgvVEZUWGlRQkM3YXlQSDVkdUQxOEhocjFjRzVvdGovckM0d009IiwidmFsaWRBZnRlciI6MTgwMDAwMDAwMH0sIng0MDJWZXJzaW9uIjoyfQ==", + "x402PaymentHeader": "eyJhY2NlcHRlZCI6eyJhbW91bnQiOiIxMDAwMDAwIiwiYXNzZXQiOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsImV4dHJhIjp7ImZlZVBheWVyIjoiN3Y1NE5XZEJ0a2p1QUZKckxHc1MyU1hudWs4bkthbTgxbVpKZWVZeFZGaTkiLCJyZWNlaXZlckF1dGhvcml6ZXIiOiJBb1ZzR2FqOE1TSjZ4d0t4ZkZ4bzlpWldIM2VuQzhSUlRYS0gyZngyRjhvcyIsInJlY2VudEJsb2NraGFzaCI6IjExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExIiwicmVjZW50U2xvdCI6IjQwMDAwMDAwMCIsInRva2VuUHJvZ3JhbSI6IlRva2Vua2VnUWZlWnlpTndBSmJOYkdLUEZYQ1d1QnZmOVNzNjIzVlE1REEiLCJ0cmFuc2FjdGlvblZlcnNpb25zIjpbMCwxXSwid2l0aGRyYXdEZWxheSI6OTAwfSwibWF4VGltZW91dFNlY29uZHMiOjMwMCwibmV0d29yayI6InNvbGFuYTpFdFdUUkFCWmFZcTZpTWZlWUtvdVJ1MTY2VlUyeHFhMSIsInBheVRvIjoiQ1hockZaSkxLcWp6bVAzc2pZTGNGNGRUZVhXS0N5OWUyU1hYWjJZbzZNUFkiLCJzY2hlbWUiOiJ1cHRvIn0sInBheWxvYWQiOnsiYXV0aG9yaXplZFNpZ25lciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwiY2hhbm5lbElkIjoiM0dtdEE3VENwMXJaNWZDWW13NmlHMkhxQkJYbUxNRE5HQ2FYZ1NVYWJCYjMiLCJkZXBvc2l0IjoiMTAwMDAwMCIsImV4cGlyZXNBdCI6MTgwMDAwMDMwMCwiZnJvbSI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwibWF4QW1vdW50IjoiMTAwMDAwMCIsIm5vbmNlIjoiNDI0MiIsIm9wZW5TbG90IjoiNDAwMDAwMDAwIiwib3BlblRyYW5zYWN0aW9uIjoiZ1FJQUNROEFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBSU9acjUrTXl4NlJUTXl2WjBLZjMyd1ZmWEY3eG9HcmFadG1MT2Z0b0VNUnpycVNteGo0cHhTQ3I3MVVIc1RMc1g1bFVkMnJyNitlNUpDSHVwcEZFYlNMQ0hCMVpGY1E1bHBHSXUwaTl4dXVIcVhTbWF1Y1RTQWJrTTlsU2tlaUwwZWE0VCtWQVdaa0ticUl3amNaWWhWclpXS1pSNFVWeVlqOS9yVGs5dXdFK3piTmZjZm4zR3QrMjV1YU9QNFpPRnc3bVAvRHNjcHkzRjZNcm5tdFk1Nzh3QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQlVwVFdwa3BJUVpOSk9oeFlObzRmSHcxdGQyOGtydUI1QitvUUVFRlJJMEdwOVVYR1N4Y1VTR015VXc5U3ZGL1dOcnVDSnVoL1VUajI5bUtBQUFBQUFiZDl1SFhaYUdUMmN2aFJzN3JlYXdjdElYdFgxczNrVHFNOVlWKy93Q3BPMFFzczVFaFYvRTZrejBCTkNndEF5dGYvczBCb3R2eHQza0dDTjhBTHFkYVZBMTdheDRySzdVWFVobkpvL0JnRUpKQnlveFBGd3pCeWkxSTd1cjUwSXlYSlk5T0pJbnh1ejBRS1JTT0RZTUxXaE9aMnY4UWhBU09lOWpiNmZoWmthS0tDM1E0RlpPazJVYVZlU0NKSnEvSXJZTElnNXQyUkRXYm5ycWFTenFub2Z1azZ5c0pDWlAzMHQvV0s0bml1SElIZW1PZjE5ZEhxT21mWTlRVnJ0d0ZBQUFBQUFBQUxBRUFBQUFBQUFRTkRrTUFCZ0FnQUFFQUFBa01BZ01FQ0FVSEN3b05BWklRQUFBQUFBQUFRRUlQQUFBQUFBQ0VBd0FBQUlUWEZ3QUFBQUFCQUFBQXEwNHJNeDVMVHpvVlFycmcrVlhkWFRNRFNjZE9vY2NLa2dYc0JsVUpJak1RSnpWbU0yTTVZVEZsTjJJeVpEUmpObVU0WmpCaE1XSXlZek5rTkdVMVpqWXdBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT2JRWDM3bzFNaUEvRTd0RGdzcjN2Z3pSczM1TVRDMXJuTktIVFNNN1ZRazhXTXE5dS9jc0hDV3pHNFZTd0Q2QWpVcHl2c3ZCSTVnRGlzVEZMKzdjZ289IiwidmFsaWRBZnRlciI6MTgwMDAwMDAwMH0sIng0MDJWZXJzaW9uIjoyfQ==", + "x402ServerAmount": "1000000", + "x402ServerCurrency": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "x402ServerFeePayer": "7v54NWdBtkjuAFJrLGsS2SXnuk8nKam81mZJeeYxVFi9", + "x402ServerFeePayerSecretKey": [ + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 102, + 190, + 126, + 51, + 44, + 122, + 69, + 51, + 50, + 189, + 157, + 10, + 127, + 125, + 176, + 85, + 245, + 197, + 239, + 26, + 6, + 173, + 166, + 109, + 152, + 179, + 159, + 182, + 129, + 12, + 71, + 58 + ], + "x402ServerMaxChannelLifetimeSeconds": 3600, + "x402ServerMaxTimeoutSeconds": 300, + "x402ServerNetwork": "devnet", + "x402ServerReceiverAuthorizer": "AoVsGaj8MSJ6xwKxfFxo9iZWH3enC8RRTXKH2fx2F8os", + "x402ServerReceiverAuthorizerSecretKey": [ + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 145, + 162, + 138, + 11, + 116, + 56, + 21, + 147, + 164, + 217, + 70, + 149, + 121, + 32, + 137, + 38, + 175, + 200, + 173, + 130, + 200, + 131, + 155, + 118, + 68, + 53, + 155, + 158, + 186, + 154, + 75, + 58 + ], + "x402ServerRecipient": "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY", + "x402ServerTokenProgram": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "x402ServerTransactionVersions": [ + 0, + 1 + ], + "x402ServerWithdrawDelay": 900 + }, + "intent": "x402-upto", + "mode": "verify-transaction", + "provenance": "generated", + "requirements": [ + "X402TX-703c03cfb5" + ], + "role": "server", + "spec": { + "doc": "x402-txv1/specs/schemes/upto/scheme_upto_svm.md", + "quote": "computeUnitLimit (bit 2) MUST be set and MUST NOT exceed 400000, loadedAccountsDataSizeLimit (bit 3) MUST be set, and priorityFee (bits 0 and 1, total lamports) MUST satisfy priorityFee * 1000000 <= 5000000 * computeUnitLimit, evaluated without overflow.", + "section": "Top-level instruction layout" + }, + "tier": "offline" + }, + { + "bugType": "auth-bypass", + "description": "A version-1 open at 200000 units with priorityFee 2001 lamports: far under 5000000 micro-lamports per unit, but one lamport over the cap the sponsor puts on the total fee it pays (RULINGS S6): rejected as compute-price-over-cap. Verify is the read-only preflight of the deposit settle (Phase 3): every static check before co-signing, at the vector's clock (nowSeconds).", + "expect": { + "alsoConformant": [ + { + "outcome": "accept" + } + ], + "alsoConformantReason": "the upto and batch-settlement schemes cap the compute unit limit at 400,000 and the unit price at 5,000,000 micro-lamports (or a version-1 priorityFee at 5 lamports per unit) and this transaction is within them; the 2,000 lamport cap on the total fee is pay-kit's stricter local policy, which the schemes allow but do not require (upto: “A sponsor MAY apply a stricter local policy for compute-unit limit, compute-unit price, and required-signature count”; batch-settlement: “A sponsor MAY apply stricter local compute-unit, priority-fee, or required-signature caps”), so a sponsor without it accepts (RULINGS S6).", + "outcome": "reject", + "rejectCode": "compute-price-over-cap" + }, + "id": "x402-upto-verify-v1-priority-fee-over-sponsor-cap-reject", + "input": { + "nowSeconds": 1800000000, + "rpcFixtures": { + "mints": { + "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU": { + "decimals": 6, + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + } + }, + "recentBlockhash": "11111111111111111111111111111111", + "slot": 400000000 + }, + "x402PaymentHeader": "eyJhY2NlcHRlZCI6eyJhbW91bnQiOiIxMDAwMDAwIiwiYXNzZXQiOiI0ek1NQzlzcnQ1Umk1WDE0R0FnWGhhSGlpM0duUEFFRVJZUEpnWkpEbmNEVSIsImV4dHJhIjp7ImZlZVBheWVyIjoiN3Y1NE5XZEJ0a2p1QUZKckxHc1MyU1hudWs4bkthbTgxbVpKZWVZeFZGaTkiLCJyZWNlaXZlckF1dGhvcml6ZXIiOiJBb1ZzR2FqOE1TSjZ4d0t4ZkZ4bzlpWldIM2VuQzhSUlRYS0gyZngyRjhvcyIsInJlY2VudEJsb2NraGFzaCI6IjExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExIiwicmVjZW50U2xvdCI6IjQwMDAwMDAwMCIsInRva2VuUHJvZ3JhbSI6IlRva2Vua2VnUWZlWnlpTndBSmJOYkdLUEZYQ1d1QnZmOVNzNjIzVlE1REEiLCJ0cmFuc2FjdGlvblZlcnNpb25zIjpbMCwxXSwid2l0aGRyYXdEZWxheSI6OTAwfSwibWF4VGltZW91dFNlY29uZHMiOjMwMCwibmV0d29yayI6InNvbGFuYTpFdFdUUkFCWmFZcTZpTWZlWUtvdVJ1MTY2VlUyeHFhMSIsInBheVRvIjoiQ1hockZaSkxLcWp6bVAzc2pZTGNGNGRUZVhXS0N5OWUyU1hYWjJZbzZNUFkiLCJzY2hlbWUiOiJ1cHRvIn0sInBheWxvYWQiOnsiYXV0aG9yaXplZFNpZ25lciI6IkFvVnNHYWo4TVNKNnh3S3hmRnhvOWlaV0gzZW5DOFJSVFhLSDJmeDJGOG9zIiwiY2hhbm5lbElkIjoiM0dtdEE3VENwMXJaNWZDWW13NmlHMkhxQkJYbUxNRE5HQ2FYZ1NVYWJCYjMiLCJkZXBvc2l0IjoiMTAwMDAwMCIsImV4cGlyZXNBdCI6MTgwMDAwMDMwMCwiZnJvbSI6IkdtYURycHBCQzdQNUFSS1Y4ZzNkaml3UDg5dnoxakxLMjNWMkdCanVBRUdCIiwibWF4QW1vdW50IjoiMTAwMDAwMCIsIm5vbmNlIjoiNDI0MiIsIm9wZW5TbG90IjoiNDAwMDAwMDAwIiwib3BlblRyYW5zYWN0aW9uIjoiZ1FJQUNROEFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBSU9acjUrTXl4NlJUTXl2WjBLZjMyd1ZmWEY3eG9HcmFadG1MT2Z0b0VNUnpycVNteGo0cHhTQ3I3MVVIc1RMc1g1bFVkMnJyNitlNUpDSHVwcEZFYlNMQ0hCMVpGY1E1bHBHSXUwaTl4dXVIcVhTbWF1Y1RTQWJrTTlsU2tlaUwwZWE0VCtWQVdaa0ticUl3amNaWWhWclpXS1pSNFVWeVlqOS9yVGs5dXdFK3piTmZjZm4zR3QrMjV1YU9QNFpPRnc3bVAvRHNjcHkzRjZNcm5tdFk1Nzh3QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQlVwVFdwa3BJUVpOSk9oeFlObzRmSHcxdGQyOGtydUI1QitvUUVFRlJJMEdwOVVYR1N4Y1VTR015VXc5U3ZGL1dOcnVDSnVoL1VUajI5bUtBQUFBQUFiZDl1SFhaYUdUMmN2aFJzN3JlYXdjdElYdFgxczNrVHFNOVlWKy93Q3BPMFFzczVFaFYvRTZrejBCTkNndEF5dGYvczBCb3R2eHQza0dDTjhBTHFkYVZBMTdheDRySzdVWFVobkpvL0JnRUpKQnlveFBGd3pCeWkxSTd1cjUwSXlYSlk5T0pJbnh1ejBRS1JTT0RZTUxXaE9aMnY4UWhBU09lOWpiNmZoWmthS0tDM1E0RlpPazJVYVZlU0NKSnEvSXJZTElnNXQyUkRXYm5ycWFTenFub2Z1azZ5c0pDWlAzMHQvV0s0bml1SElIZW1PZjE5ZEhxT21mWTlRVnJ0RUhBQUFBQUFBQVFBMERBQUFBQUFRTkRrTUFCZ0FnQUFFQUFBa01BZ01FQ0FVSEN3b05BWklRQUFBQUFBQUFRRUlQQUFBQUFBQ0VBd0FBQUlUWEZ3QUFBQUFCQUFBQXEwNHJNeDVMVHpvVlFycmcrVlhkWFRNRFNjZE9vY2NLa2dYc0JsVUpJak1RSnpWbU0yTTVZVEZsTjJJeVpEUmpObVU0WmpCaE1XSXlZek5rTkdVMVpqWXdBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBSEt1ZlVyOU1hMW9KSFc1ODgzbVdkUjN3MjVkNDh1elVQZVhQd3NXaE1UdTJQTzZzTjM0bHFZUElkWlJmYXNwY0RvK2hBeG5lM3phSUZVYUFnR1k5QTg9IiwidmFsaWRBZnRlciI6MTgwMDAwMDAwMH0sIng0MDJWZXJzaW9uIjoyfQ==", "x402ServerAmount": "1000000", "x402ServerCurrency": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", "x402ServerFeePayer": "7v54NWdBtkjuAFJrLGsS2SXnuk8nKam81mZJeeYxVFi9", @@ -1756,12 +1950,12 @@ "mode": "verify-transaction", "provenance": "generated", "requirements": [ - "X402TX-0f874a9c63" + "X402TX-703c03cfb5" ], "role": "server", "spec": { "doc": "x402-txv1/specs/schemes/upto/scheme_upto_svm.md", - "quote": "In a version-1 transaction the same caps apply to the message TransactionConfig instead: computeUnitLimit MUST be present and MUST NOT exceed 400000, loadedAccountsDataSizeLimit MUST be present, and priorityFee (total lamports) MUST satisfy priorityFee 1000000 <= 5000000 computeUnitLimit.", + "quote": "computeUnitLimit (bit 2) MUST be set and MUST NOT exceed 400000, loadedAccountsDataSizeLimit (bit 3) MUST be set, and priorityFee (bits 0 and 1, total lamports) MUST satisfy priorityFee * 1000000 <= 5000000 * computeUnitLimit, evaluated without overflow.", "section": "Top-level instruction layout" }, "tier": "offline" @@ -1938,13 +2132,13 @@ "mode": "verify-transaction", "provenance": "generated", "requirements": [ - "X402TX-0f874a9c63", - "X402TX-644919eb3b" + "X402TX-703c03cfb5", + "X402TX-f9bcc1a14a" ], "role": "server", "spec": { "doc": "x402-txv1/specs/schemes/upto/scheme_upto_svm.md", - "quote": "In a version-1 transaction the same caps apply to the message TransactionConfig instead: computeUnitLimit MUST be present and MUST NOT exceed 400000, loadedAccountsDataSizeLimit MUST be present, and priorityFee (total lamports) MUST satisfy priorityFee 1000000 <= 5000000 computeUnitLimit.", + "quote": "computeUnitLimit (bit 2) MUST be set and MUST NOT exceed 400000, loadedAccountsDataSizeLimit (bit 3) MUST be set, and priorityFee (bits 0 and 1, total lamports) MUST satisfy priorityFee * 1000000 <= 5000000 * computeUnitLimit, evaluated without overflow.", "section": "Top-level instruction layout" }, "tier": "offline" @@ -2121,13 +2315,13 @@ "mode": "verify-transaction", "provenance": "generated", "requirements": [ - "X402TX-0f874a9c63", - "X402TX-644919eb3b" + "X402TX-703c03cfb5", + "X402TX-f9bcc1a14a" ], "role": "server", "spec": { "doc": "x402-txv1/specs/schemes/upto/scheme_upto_svm.md", - "quote": "In a version-1 transaction the same caps apply to the message TransactionConfig instead: computeUnitLimit MUST be present and MUST NOT exceed 400000, loadedAccountsDataSizeLimit MUST be present, and priorityFee (total lamports) MUST satisfy priorityFee 1000000 <= 5000000 computeUnitLimit.", + "quote": "computeUnitLimit (bit 2) MUST be set and MUST NOT exceed 400000, loadedAccountsDataSizeLimit (bit 3) MUST be set, and priorityFee (bits 0 and 1, total lamports) MUST satisfy priorityFee * 1000000 <= 5000000 * computeUnitLimit, evaluated without overflow.", "section": "Top-level instruction layout" }, "tier": "offline" @@ -2303,12 +2497,12 @@ "mode": "verify-transaction", "provenance": "generated", "requirements": [ - "X402TX-0f874a9c63" + "X402TX-703c03cfb5" ], "role": "server", "spec": { "doc": "x402-txv1/specs/schemes/upto/scheme_upto_svm.md", - "quote": "In a version-1 transaction the same caps apply to the message TransactionConfig instead: computeUnitLimit MUST be present and MUST NOT exceed 400000, loadedAccountsDataSizeLimit MUST be present, and priorityFee (total lamports) MUST satisfy priorityFee 1000000 <= 5000000 computeUnitLimit.", + "quote": "computeUnitLimit (bit 2) MUST be set and MUST NOT exceed 400000, loadedAccountsDataSizeLimit (bit 3) MUST be set, and priorityFee (bits 0 and 1, total lamports) MUST satisfy priorityFee * 1000000 <= 5000000 * computeUnitLimit, evaluated without overflow.", "section": "Top-level instruction layout" }, "tier": "offline" diff --git a/harness/vectors/x402-verify-mutations.json b/harness/vectors/x402-verify-mutations.json index ea22fd640..52dddc0e8 100644 --- a/harness/vectors/x402-verify-mutations.json +++ b/harness/vectors/x402-verify-mutations.json @@ -859,6 +859,13 @@ "bugType": "settlement", "description": "The transfer pays one base unit more than the route amount; §1.4 tolerates overpayment. See RULINGS S5: default verifiers accept overpayment. Mutation: transfer #0 pays 1 base units more than required.", "expect": { + "alsoConformant": [ + { + "outcome": "reject", + "rejectCode": "amount-mismatch" + } + ], + "alsoConformantReason": "§1.4 tolerates overpayment, but §3.1 also reads “Fee payer isolation, destination ATA derivation, and exact amount match are enforced on both layouts” and §2.3 lets a sponsor's policy refuse a scheme-valid transaction (“A transaction MAY be valid under the `exact` scheme while being rejected by a sponsor's policy.”), so a sponsor that requires the exact amount is conformant too (RULINGS S5).", "outcome": "accept", "x402EnvelopeShape": { "hasAccepted": true, diff --git a/harness/vectors/x402-verify-policy.json b/harness/vectors/x402-verify-policy.json index 6d0f839a0..40c597669 100644 --- a/harness/vectors/x402-verify-policy.json +++ b/harness/vectors/x402-verify-policy.json @@ -104,7 +104,7 @@ "provenance": "generated", "requirements": [ "X402-a1cf65b0f0", - "X402-a8bd75d71b" + "X402-05c2aacafc" ], "role": "server", "spec": { @@ -209,12 +209,12 @@ "mode": "verify-transaction", "provenance": "generated", "requirements": [ - "X402-a8bd75d71b" + "X402-05c2aacafc" ], "role": "server", "spec": { "doc": "x402/specs/schemes/exact/scheme_exact_svm.md", - "quote": "The decompiled transaction MUST contain 3 to 7 instructions in this order:", + "quote": "For a single-payee charge (no extra.splits and no ATA creation), a legacy or version-0 transaction MUST contain 3 to 7 instructions in this order:", "section": "3.1 Path 1 — Static Layout Verification (standard wallets)" }, "tier": "offline" @@ -314,12 +314,12 @@ "mode": "verify-transaction", "provenance": "generated", "requirements": [ - "X402-a8bd75d71b" + "X402-05c2aacafc" ], "role": "server", "spec": { "doc": "x402/specs/schemes/exact/scheme_exact_svm.md", - "quote": "The decompiled transaction MUST contain 3 to 7 instructions in this order:", + "quote": "For a single-payee charge (no extra.splits and no ATA creation), a legacy or version-0 transaction MUST contain 3 to 7 instructions in this order:", "section": "3.1 Path 1 — Static Layout Verification (standard wallets)" }, "tier": "offline" @@ -419,12 +419,12 @@ "mode": "verify-transaction", "provenance": "generated", "requirements": [ - "X402-a8bd75d71b" + "X402-05c2aacafc" ], "role": "server", "spec": { "doc": "x402/specs/schemes/exact/scheme_exact_svm.md", - "quote": "The decompiled transaction MUST contain 3 to 7 instructions in this order:", + "quote": "For a single-payee charge (no extra.splits and no ATA creation), a legacy or version-0 transaction MUST contain 3 to 7 instructions in this order:", "section": "3.1 Path 1 — Static Layout Verification (standard wallets)" }, "tier": "offline" @@ -753,6 +753,12 @@ "bugType": "settlement", "description": "The static layout's 200,000 compute unit limit paired with a 5,000,000 micro-lamport unit price: each is within its own cap, but the sponsor would pay a 1,000,000 lamport priority fee. The sponsor bounds the fee it pays as limit times price (RULINGS S6). Differs from x402-exact-v2-verify-accept only in the price. Mutation: compute unit price set to 5000000 micro-lamports.", "expect": { + "alsoConformant": [ + { + "outcome": "accept" + } + ], + "alsoConformantReason": "scheme_exact_svm.md §2.2.1 bounds the compute unit limit and the unit price separately (reference defaults 400,000 units and 5,000,000 micro-lamports per unit) and this transaction is within both; the 2,000 lamport cap on their product is pay-kit's stricter sponsor policy (§2.3: “Sponsors MAY introduce stricter limits but MUST NOT relax the §2.1 MUSTs.”), so a sponsor without it accepts (RULINGS S6).", "outcome": "reject", "rejectCode": "compute-price-over-cap" }, diff --git a/html/package-lock.json b/html/package-lock.json index be25e51e8..a5ad59fc1 100644 --- a/html/package-lock.json +++ b/html/package-lock.json @@ -15,7 +15,7 @@ "devDependencies": { "@playwright/test": "^1.59.1", "esbuild": "^0.25.0", - "tsx": "^4.19.0", + "tsx": "^4.23.15", "typescript": "^5.7.0" } }, @@ -1427,19 +1427,6 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/get-tsconfig": { - "version": "4.13.7", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.7.tgz", - "integrity": "sha512-7tN6rFgBlMgpBML5j8typ92BKFi2sFQvIdpAqLA2beia5avZDrMs0FLZiM5etShWq5irVyGcGMEA1jcDaK7A/Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "resolve-pkg-maps": "^1.0.0" - }, - "funding": { - "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" - } - }, "node_modules/incur": { "version": "0.4.26", "resolved": "https://registry.npmjs.org/incur/-/incur-0.4.26.tgz", @@ -1605,16 +1592,6 @@ "node": ">=18" } }, - "node_modules/resolve-pkg-maps": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", - "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" - } - }, "node_modules/tokenx": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/tokenx/-/tokenx-1.6.0.tgz", @@ -1622,14 +1599,13 @@ "license": "MIT" }, "node_modules/tsx": { - "version": "4.21.0", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", - "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "version": "4.23.15", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.23.15.tgz", + "integrity": "sha512-Yiex1Ovn8z2xPpOWckIiysV1SSyRMY9BkLF++q0yKiDxCqRhosKfMg3janKkiLBwZ5c/YryloKwGZcrEmtwxKw==", "dev": true, "license": "MIT", "dependencies": { - "esbuild": "~0.27.0", - "get-tsconfig": "^4.7.5" + "esbuild": "~0.28.0" }, "bin": { "tsx": "dist/cli.mjs" @@ -1642,9 +1618,9 @@ } }, "node_modules/tsx/node_modules/@esbuild/aix-ppc64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz", - "integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.2.tgz", + "integrity": "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==", "cpu": [ "ppc64" ], @@ -1659,9 +1635,9 @@ } }, "node_modules/tsx/node_modules/@esbuild/android-arm": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.7.tgz", - "integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.2.tgz", + "integrity": "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==", "cpu": [ "arm" ], @@ -1676,9 +1652,9 @@ } }, "node_modules/tsx/node_modules/@esbuild/android-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz", - "integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.2.tgz", + "integrity": "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==", "cpu": [ "arm64" ], @@ -1693,9 +1669,9 @@ } }, "node_modules/tsx/node_modules/@esbuild/android-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.7.tgz", - "integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.2.tgz", + "integrity": "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==", "cpu": [ "x64" ], @@ -1710,9 +1686,9 @@ } }, "node_modules/tsx/node_modules/@esbuild/darwin-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz", - "integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.2.tgz", + "integrity": "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==", "cpu": [ "arm64" ], @@ -1727,9 +1703,9 @@ } }, "node_modules/tsx/node_modules/@esbuild/darwin-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz", - "integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.2.tgz", + "integrity": "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==", "cpu": [ "x64" ], @@ -1744,9 +1720,9 @@ } }, "node_modules/tsx/node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz", - "integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.2.tgz", + "integrity": "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==", "cpu": [ "arm64" ], @@ -1761,9 +1737,9 @@ } }, "node_modules/tsx/node_modules/@esbuild/freebsd-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz", - "integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.2.tgz", + "integrity": "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==", "cpu": [ "x64" ], @@ -1778,9 +1754,9 @@ } }, "node_modules/tsx/node_modules/@esbuild/linux-arm": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz", - "integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.2.tgz", + "integrity": "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==", "cpu": [ "arm" ], @@ -1795,9 +1771,9 @@ } }, "node_modules/tsx/node_modules/@esbuild/linux-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz", - "integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.2.tgz", + "integrity": "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==", "cpu": [ "arm64" ], @@ -1812,9 +1788,9 @@ } }, "node_modules/tsx/node_modules/@esbuild/linux-ia32": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz", - "integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.2.tgz", + "integrity": "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==", "cpu": [ "ia32" ], @@ -1829,9 +1805,9 @@ } }, "node_modules/tsx/node_modules/@esbuild/linux-loong64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz", - "integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.2.tgz", + "integrity": "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==", "cpu": [ "loong64" ], @@ -1846,9 +1822,9 @@ } }, "node_modules/tsx/node_modules/@esbuild/linux-mips64el": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz", - "integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.2.tgz", + "integrity": "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==", "cpu": [ "mips64el" ], @@ -1863,9 +1839,9 @@ } }, "node_modules/tsx/node_modules/@esbuild/linux-ppc64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz", - "integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.2.tgz", + "integrity": "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==", "cpu": [ "ppc64" ], @@ -1880,9 +1856,9 @@ } }, "node_modules/tsx/node_modules/@esbuild/linux-riscv64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz", - "integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.2.tgz", + "integrity": "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==", "cpu": [ "riscv64" ], @@ -1897,9 +1873,9 @@ } }, "node_modules/tsx/node_modules/@esbuild/linux-s390x": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz", - "integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.2.tgz", + "integrity": "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==", "cpu": [ "s390x" ], @@ -1914,9 +1890,9 @@ } }, "node_modules/tsx/node_modules/@esbuild/linux-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.7.tgz", - "integrity": "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.2.tgz", + "integrity": "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==", "cpu": [ "x64" ], @@ -1931,9 +1907,9 @@ } }, "node_modules/tsx/node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz", - "integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.2.tgz", + "integrity": "sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==", "cpu": [ "arm64" ], @@ -1948,9 +1924,9 @@ } }, "node_modules/tsx/node_modules/@esbuild/netbsd-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz", - "integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.2.tgz", + "integrity": "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==", "cpu": [ "x64" ], @@ -1965,9 +1941,9 @@ } }, "node_modules/tsx/node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz", - "integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.2.tgz", + "integrity": "sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==", "cpu": [ "arm64" ], @@ -1982,9 +1958,9 @@ } }, "node_modules/tsx/node_modules/@esbuild/openbsd-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz", - "integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.2.tgz", + "integrity": "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==", "cpu": [ "x64" ], @@ -1999,9 +1975,9 @@ } }, "node_modules/tsx/node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz", - "integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.2.tgz", + "integrity": "sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==", "cpu": [ "arm64" ], @@ -2016,9 +1992,9 @@ } }, "node_modules/tsx/node_modules/@esbuild/sunos-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz", - "integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.2.tgz", + "integrity": "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==", "cpu": [ "x64" ], @@ -2033,9 +2009,9 @@ } }, "node_modules/tsx/node_modules/@esbuild/win32-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz", - "integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.2.tgz", + "integrity": "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==", "cpu": [ "arm64" ], @@ -2050,9 +2026,9 @@ } }, "node_modules/tsx/node_modules/@esbuild/win32-ia32": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz", - "integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.2.tgz", + "integrity": "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==", "cpu": [ "ia32" ], @@ -2067,9 +2043,9 @@ } }, "node_modules/tsx/node_modules/@esbuild/win32-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz", - "integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.2.tgz", + "integrity": "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==", "cpu": [ "x64" ], @@ -2084,9 +2060,9 @@ } }, "node_modules/tsx/node_modules/esbuild": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz", - "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz", + "integrity": "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -2097,32 +2073,32 @@ "node": ">=18" }, "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/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" } }, "node_modules/tsx/node_modules/fsevents": { @@ -2310,9 +2286,9 @@ } }, "node_modules/zod": { - "version": "4.6.5", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.6.5.tgz", - "integrity": "sha512-v5l/aFXZQeai4awLbOpSoHecE9UiMrnfx75tEXLjNonXVARxQ5mOeipTjROUchszUNCqnE+hqAMujRsRHsut2Q==", + "version": "4.6.7", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.6.7.tgz", + "integrity": "sha512-g8W2D2kU6a8untc053fX1uVBKzM7yqAxW/3zwk83+6RyF2+SKOuV+c0wBDhUwzV1PaGapmZH+rmcUzPf+3CGwg==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" diff --git a/html/package.json b/html/package.json index e3b17e80d..885f9d69c 100644 --- a/html/package.json +++ b/html/package.json @@ -21,7 +21,7 @@ "devDependencies": { "@playwright/test": "^1.59.1", "esbuild": "^0.25.0", - "tsx": "^4.19.0", + "tsx": "^4.23.15", "typescript": "^5.7.0" }, "overrides": { diff --git a/playground/app/package.json b/playground/app/package.json index c91cb4dc9..e2850de7b 100644 --- a/playground/app/package.json +++ b/playground/app/package.json @@ -14,8 +14,8 @@ }, "dependencies": { "@noble/hashes": "1.8.0", - "@solana-program/token": "^0.11.0", - "@solana/kit": "^6.5.0", + "@solana-program/token": "^0.18.0", + "@solana/kit": "^8.5.0", "@solana/mpp": "link:../../typescript/packages/mpp", "@solana/pay-kit": "link:../../typescript/packages/pay-kit", "highlight.js": "^11.11.1", diff --git a/playground/pnpm-lock.yaml b/playground/pnpm-lock.yaml index b24fadb69..e62be3cca 100644 --- a/playground/pnpm-lock.yaml +++ b/playground/pnpm-lock.yaml @@ -8,6 +8,8 @@ overrides: baseline-browser-mapping: 2.11.0 browserslist: 4.28.7 nanoid@3.3.11: 3.3.18 + vite: 6.4.5 + zod: 4.6.7 postcss: 8.5.23 react-router: 7.18.2 shell-quote: 1.11.0 @@ -36,11 +38,11 @@ importers: specifier: 1.8.0 version: 1.8.0 '@solana-program/token': - specifier: ^0.11.0 - version: 0.11.0(@solana/kit@6.10.0(typescript@5.9.3)) + specifier: ^0.18.0 + version: 0.18.0(@solana/kit@8.5.0(typescript@5.9.3)) '@solana/kit': - specifier: ^6.5.0 - version: 6.10.0(typescript@5.9.3) + specifier: ^8.5.0 + version: 8.5.0(typescript@5.9.3) '@solana/mpp': specifier: link:../../typescript/packages/mpp version: link:../../typescript/packages/mpp @@ -52,7 +54,7 @@ importers: version: 11.11.1 mppx: specifier: ^0.8.15 - version: 0.8.19(typescript@5.9.3)(viem@2.56.3(typescript@5.9.3)(zod@4.4.3)) + version: 0.8.19(typescript@5.9.3)(viem@2.56.3(typescript@5.9.3)(zod@4.6.7)) react: specifier: ^19.1.0 version: 19.2.7 @@ -77,13 +79,13 @@ importers: version: 19.2.3(@types/react@19.2.17) '@vitejs/plugin-react': specifier: ^4.4.0 - version: 4.7.0(vite@6.4.3(@types/node@25.9.6)(tsx@4.22.4)(yaml@2.9.0)) + version: 4.7.0(vite@6.4.5(@types/node@25.9.6)(tsx@4.22.4)(yaml@2.9.0)) typescript: specifier: ^5.7.0 version: 5.9.3 vite: - specifier: ^6.0.0 - version: 6.4.3(@types/node@25.9.6)(tsx@4.22.4)(yaml@2.9.0) + specifier: 6.4.5 + version: 6.4.5(@types/node@25.9.6)(tsx@4.22.4)(yaml@2.9.0) packages: @@ -672,18 +674,18 @@ packages: '@scure/bip39@1.6.0': resolution: {integrity: sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A==} - '@solana-program/system@0.12.2': - resolution: {integrity: sha512-MaBeOxlvTruQhA7UYkOb3hVTEHPPagOtd+PvTm6a8rGgvEAP0kD4BbC37NceOaR4ABNqdaCmD5OMVRKgrE6KAg==} + '@solana-program/system@0.16.0': + resolution: {integrity: sha512-/RG6q2E2vG/XpdOt8Jj/kbQktPlL5JyJuNGAeN9wDcxKDKQtrGTJpDrJgQUxiEy23fsPNXQbLN8XeCtYoMof3Q==} peerDependencies: - '@solana/kit': ^6.4.0 + '@solana/kit': ^8.5.0 - '@solana-program/token@0.11.0': - resolution: {integrity: sha512-/lB72Pcmkn5kjUfP1Vd8F86HBlhN9RN4hJYgUG5csc23w9LCdYom2CiRdGsK25KkR9UFf6ndCCAMh83hMo+ftw==} + '@solana-program/token@0.18.0': + resolution: {integrity: sha512-YNN13I4BxBnGPGk0NzP/LLQMCmJVdunbtgqjl7/Gfp1fDXQrKXh9df8xu+2ayNdvjGJYC4c9D5vZpVetHdyJaQ==} peerDependencies: - '@solana/kit': ^6.1.0 + '@solana/kit': ^8.5.0 - '@solana/accounts@6.10.0': - resolution: {integrity: sha512-+FxfDOrnifoPlBkF+fr8eeQdgM6xtIgAg9xKMu3WnIz60oZd4Xnry6+ff6t+ePPoZZp397FSg9ZJet68VCWm5Q==} + '@solana/accounts@8.5.0': + resolution: {integrity: sha512-vwwXYCobg1oG4kFeUEsGiNORjPujI2ff3yKLp6lCa7QBIlKaD7kZ2QRI3PZFYcNrMJ6HYNwNeZXR7ixg02pWdA==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -691,8 +693,8 @@ packages: typescript: optional: true - '@solana/addresses@6.10.0': - resolution: {integrity: sha512-vEoCGBTxG0HCERAn84KXkrJjl+pDaNzOpZ0qbgcPS98fYxP5yzbKB8SNOY2bzrbkRUmmw5Q3hqTRERemUN2Gcw==} + '@solana/addresses@8.5.0': + resolution: {integrity: sha512-LwTrDbDSJBng9y0vwiKqb/kSS9daspTGrSYoZPafeMWpAlpmutdD1KXPDHVTa4Xz00hcAfOJXYxRXX5VAoiOag==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -700,8 +702,8 @@ packages: typescript: optional: true - '@solana/assertions@6.10.0': - resolution: {integrity: sha512-lKSAdVo+P/6Lp4vs6shstXmFOpvxrABwn4o1462tb7sKkNapk6o9pPFVPGw4DUgPS3WqWRs1j2tmpuVjhQRntg==} + '@solana/assertions@8.5.0': + resolution: {integrity: sha512-EZDY5rJIV8Mv9xYJ7P+jvE5pihG7pmKZ6pTqbunba/4uZSQN4Klw0FX54LDDklfDvhzmAdXN0nYAnjovTGAPEg==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -709,8 +711,8 @@ packages: typescript: optional: true - '@solana/codecs-core@6.10.0': - resolution: {integrity: sha512-nfAl9OMGo4HanIMxGsQoVB7BxMoqBCYEUxl8oEAZZ09pDxnaXQZkTRXEwPPccag37XfW1ciPd1vWPKwB2b0HHQ==} + '@solana/codecs-core@8.5.0': + resolution: {integrity: sha512-ou38qNrf9XOzCWsu/I4sTzRmnrKqhblwMVvpXwXPKAAUZwkSAKQXonwgZFY68I5HK6nkfq1NLWfZFmTEIZYLiw==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -718,8 +720,8 @@ packages: typescript: optional: true - '@solana/codecs-data-structures@6.10.0': - resolution: {integrity: sha512-CNasJW3bq5u+632Zt5aJ8rOjAjv2HyenpV8o9kAIqdmV4CBpjCCoBnKn8LkuR/sbeREZxJYfhKTXO/9ruAkw7A==} + '@solana/codecs-data-structures@8.5.0': + resolution: {integrity: sha512-CnnNriyltkgxZAKgAJoVRsRnrtdW4KCX37BUoIsquCM+AgSvhSbxaZNz0iaHjGOX7o1Z4s6+j7nAUgad0N/w5A==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -727,8 +729,8 @@ packages: typescript: optional: true - '@solana/codecs-numbers@6.10.0': - resolution: {integrity: sha512-CcM+wX4zOiA9zkh8A7t1787A0Ehgmu5+6Z2tKoHew6cNw/dkaUTPa8JnNHbvfsLC8dfHC1BhAEJl86sKmRsfkQ==} + '@solana/codecs-numbers@8.5.0': + resolution: {integrity: sha512-6Vtf52rHzjf98ykejn9bNGMaQ2k1f4UMIa+BGMbBy4mIRQ5ggdI5oCAb3sZPfJcel2JQHwDlsLHCYdpqC+n6Mg==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -736,8 +738,8 @@ packages: typescript: optional: true - '@solana/codecs-strings@6.10.0': - resolution: {integrity: sha512-zlaqkg7K6F6IN4V/Ec8TWkTn054gxv7ZLagvGkuEyAdPQ6BzzsehOm2TqCuyXgJJTCGPLY1bEk6yH9NxANe0kA==} + '@solana/codecs-strings@8.5.0': + resolution: {integrity: sha512-9lCSCUVkbPLb1o9PLDsaOatdVgrUqqWMrAqJvZPyyuvrC5++wPuKRIGq+5iU3lICY+AwWxrzVyiwdu4xaZVCiw==} engines: {node: '>=20.18.0'} peerDependencies: fastestsmallesttextencoderdecoder: ^1.0.22 @@ -748,8 +750,8 @@ packages: typescript: optional: true - '@solana/codecs@6.10.0': - resolution: {integrity: sha512-lLVuxod4ChWp9i7OvpgIykYG8Q9OGPVXKnHM9VlzDDLylsx7Y1FoQL00sHa7PqFkJVmkBufaA6dcGbQ7FU+lAQ==} + '@solana/codecs@8.5.0': + resolution: {integrity: sha512-wALOoEuL7HAaahZnrhxCwYz10p23hku/LPNfXjlvwgjVYJL08PH3uyWDFO8e9zhcNLOaR13IREE9z8zPUhJjDQ==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -757,8 +759,8 @@ packages: typescript: optional: true - '@solana/errors@6.10.0': - resolution: {integrity: sha512-KBLAxCtAXr357JNhCyIDQXWbuSj5vN6w+28FSfcYY6OOSiphmXLAV3V58jgV0C6iNbIzFJFi6yatFyDTdeJsNg==} + '@solana/errors@8.5.0': + resolution: {integrity: sha512-y/XTiwAZsm2kHoEDJ3ac3NUq/0E4uCbOnBe2m5mmBXF3TGmF562tDKgN5pQ+thiRABvi7b2LqwTBCg4kAdtgRg==} engines: {node: '>=20.18.0'} hasBin: true peerDependencies: @@ -767,8 +769,8 @@ packages: typescript: optional: true - '@solana/fast-stable-stringify@6.10.0': - resolution: {integrity: sha512-iCNed27wk6PKSS3QUtHovRfMWF/jbVWogs2vB4tukKUCsqG4rDfDInIwZ6ur/nY6XTrgi2gMMdZq9GAUlWsbfw==} + '@solana/fast-stable-stringify@8.5.0': + resolution: {integrity: sha512-CTIoOwJ0NScrB8KTzr/V4PJrNHrBAz1zvamM0opgDPQZGzLrBhca1e4eQcGmF6o7Dv3Ve0HdvDJx0B2uG6YxVA==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -776,8 +778,8 @@ packages: typescript: optional: true - '@solana/fixed-points@6.10.0': - resolution: {integrity: sha512-ZkKL0alXH3L7/wMiVG8YUuG8qBKunlM810+YBD7nUPRhifiGsX1zwADViHLYNqLr/jUk0mTYFUcKznTpB/K+Gg==} + '@solana/fixed-points@8.5.0': + resolution: {integrity: sha512-hkB7dUAD/oxXeNOvdMXVqfKZAvOJ1o50gBwzh8yLP1ihdSxVgssb36Vg7806C5HzmIxmTKZclJJokG0cRUXVSw==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -785,8 +787,8 @@ packages: typescript: optional: true - '@solana/functional@6.10.0': - resolution: {integrity: sha512-P8cevu4mAqHTXC37h1TVoOh8zhWB2tlOI/R9vWjYPpcLwcyWf8p2qq4LEGHl5kY+1C+4PNX39HsmCocXOPCDkQ==} + '@solana/functional@8.5.0': + resolution: {integrity: sha512-+8pgF1rVW78FfT0d+ceADFLKpSh/8/o9Ldx5tEkI6paiv0QeClL1rlU5nFs5tjoFkf+92x8PpiLEEGkm0CifOQ==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -794,8 +796,8 @@ packages: typescript: optional: true - '@solana/instruction-plans@6.10.0': - resolution: {integrity: sha512-YG7mo4zykzdc6ZTV0BuN6pveK9qeBySzlYYerq578A4eQu3xcypMAYRGAvhMZtWTanjjmD6CKtM0M7kVp0TNxg==} + '@solana/instruction-plans@8.5.0': + resolution: {integrity: sha512-cES8TzRGuJ5cdVn3hr6GskwwG68rLd8R0FqmzB9NeU/nzPnW/50nRrg36DYX1Nh+OwuU/ehg6zkNNu1Vo72lKQ==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -803,8 +805,8 @@ packages: typescript: optional: true - '@solana/instructions@6.10.0': - resolution: {integrity: sha512-0TToYF+8LXQ3ofPMx+yF6yaM9l4YJvcAPMy0qV5JsrBUFlWXBSANRuudKBQLHMvb+a3OiUTq5X7omuorKMBB3A==} + '@solana/instructions@8.5.0': + resolution: {integrity: sha512-LSMOQRicz8OalMM2DT60PtAaPjvkHPhIvmPEI8KpyWOuNRwABJBRAfn5ypcdSa69VVj4IdOY10tDWZzjN4dviA==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -812,8 +814,8 @@ packages: typescript: optional: true - '@solana/keys@6.10.0': - resolution: {integrity: sha512-26IRfdm/hTUCmM7MeEeX0ULSbCM6OzkZTkfkrPircqmRM7xyNqP4hq7u0P7wjb9dl7NfgyG6K7cdvUxrj2e3mA==} + '@solana/keys@8.5.0': + resolution: {integrity: sha512-mq6amguPYLklpAOC9A+boXQhpcHGjcn4QN40J0l1TvUkfWyFJ4HBbNb35fyWldqqDUV5ujOpaPZmmVvWJBK2Kw==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -821,8 +823,8 @@ packages: typescript: optional: true - '@solana/kit@6.10.0': - resolution: {integrity: sha512-/WnnQp3uARh2JCFSfAakejTAqwmXVuMVTcRn5r2yDwY2yzZ4R6mt/Cl59VPimVLNSoTyN/KsEwhv9omr3ERazQ==} + '@solana/kit@8.5.0': + resolution: {integrity: sha512-bMnXXADeyZFe3XyqzPhlQAIsmPYRiojaRO4JQxwGOmMwiQ5f13ZQodmsOqnt8W/n40P7r/+/pDqWuqG0TUv+yA==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -830,8 +832,8 @@ packages: typescript: optional: true - '@solana/nominal-types@6.10.0': - resolution: {integrity: sha512-9ykyBBvnkInH7fCacjJi7zu2PJyd+OCt+VTjIISv070fHzKIMFqZqJJ/dJ0SRH2aHwfB3n86iVsmtBtuxi4KKA==} + '@solana/nominal-types@8.5.0': + resolution: {integrity: sha512-OfTZ+w/C59Zkp51RJ3dzn2GXUojf9p/PMmSrOpxrj+hci3bdh4e6XDGY+mvP8HGPH+m0nfKWTBCygEslfoX6bg==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -839,8 +841,8 @@ packages: typescript: optional: true - '@solana/offchain-messages@6.10.0': - resolution: {integrity: sha512-RiEgAueeMkFMC1suOXBIcmCZgtXRxy24yk0DldPB37bB4zwOF1SAaRjNRPjIkGK8RhCYrEpPosnzLyavw9ueRg==} + '@solana/offchain-messages@8.5.0': + resolution: {integrity: sha512-C7qBBD1Gfbdv99uoQnuc8XZYwttTQJOYEG2v6z7q3mAL03PN7zdItAlBa+M2tpeRKjTJObRYnUUJDfiIyyGD/Q==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -848,8 +850,8 @@ packages: typescript: optional: true - '@solana/options@6.10.0': - resolution: {integrity: sha512-RO9UT3UYD8/Cu2uM6ZXbKvLeMnVD42+g9JRds7Pfs4AhiOyg4R4TJrQUAppTgavPTO3PBRlWtWOC05ZH/yAIbg==} + '@solana/options@8.5.0': + resolution: {integrity: sha512-Ron9FrWDkwxlmuI6D+NmrZZRngC1MUncglgyN77ThAoxDE1gGMOB88mQvEILeeqONeTA1rDg1uBvbewQcILp+w==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -857,8 +859,8 @@ packages: typescript: optional: true - '@solana/plugin-core@6.10.0': - resolution: {integrity: sha512-JE70YTQOfFACVFGvoJon4Scc/eHUWjMu8Ovo35CcV2kHTAHYMCd4UkBd2gmlhK0vRMMomsQi1ZLPlAlTq0OoUQ==} + '@solana/plugin-core@8.5.0': + resolution: {integrity: sha512-1zmh+UC47yxsZHleDpH4AEVkm9yXIATkWm8v33DJuXaqX3TQXMXuxP39cXAyObIQEpCG8DK8lyAeFTUrIFcDmA==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -866,8 +868,8 @@ packages: typescript: optional: true - '@solana/plugin-interfaces@6.10.0': - resolution: {integrity: sha512-vr0/l9wcM4orwGr8cjkFWaJ9A4HvzuAv00jMFNMg0Spd0GZqnwnpW+D/fXa1lIJnTRaF3EeEjLh4VjKU037T0Q==} + '@solana/plugin-interfaces@8.5.0': + resolution: {integrity: sha512-+s/+cCuzk23/a1ViTIugvXFYHN0txxmvqfuL4qx81NlmGawqEYws6xD+L02wNzJ5rbJeAaBhw2pUFStMfG4vYg==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -875,8 +877,8 @@ packages: typescript: optional: true - '@solana/program-client-core@6.10.0': - resolution: {integrity: sha512-4PPbTLdC1ylHIuvhOFDP8RnSkXPCFjNFWGslzc+UFKnoR4ajzBcByX94jmaruDMk5ncxgj7tr9pzJTvfGHIaMA==} + '@solana/program-client-core@8.5.0': + resolution: {integrity: sha512-HJcnbuvQRcWOV3nTUjzgmQRIs0Of1973UU8uOvSEEW7rxycQwNxJ7fVgxQ5sYOCbT+7rlqqTkDeczvB7I4OwoA==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -884,8 +886,8 @@ packages: typescript: optional: true - '@solana/programs@6.10.0': - resolution: {integrity: sha512-qn/HeLP5KGUJXVub3fyGe69/rWaLX4jzwm6V/1pNxJDbdF+MBdgn18hP6F+VmhfdNmwK0lue3J/1HQ1UTMuQeQ==} + '@solana/programs@8.5.0': + resolution: {integrity: sha512-8PC2E/d5rwCRw1tFwQlpG65YDN56bYmPiBl99QqCP2RzhNdFJ/52xgFumL2G0uLfD3xsuFaWuOIGNxkyfXYm/Q==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -893,8 +895,8 @@ packages: typescript: optional: true - '@solana/promises@6.10.0': - resolution: {integrity: sha512-oJSIn+VBBMWDo8oqw7RV3tI6Jih+Ieup6FcQLYLDUriaeo7+8l1Zdezl8zh7SIfeU4lOfAbRg6mR0huaS/Lltg==} + '@solana/promises@8.5.0': + resolution: {integrity: sha512-qWJbU6RGuZVrtvsGZ+2F46jccaIZDX4czYRRhS3m38cCdE+wKMbqGvWND50xP7D9egOxYKHMqJAJbLQH4gspvQ==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -902,8 +904,8 @@ packages: typescript: optional: true - '@solana/rpc-api@6.10.0': - resolution: {integrity: sha512-RjPIVsAb/85P1ptoO3WpC0x7QG6gG/e4q/3lo6gbSznUZOcoM+8sSBnCX7BwP1ZkCDS6NK/ClXLnhhhYZx+OGg==} + '@solana/rpc-api@8.5.0': + resolution: {integrity: sha512-qlRZ2yC8WEWNg3VX8UEqlZOitKZaeE6KWbn3A/ybtJAYz+mvr3RMDhnQ89RDqIuxPuAFZNV21BRJv3yB9xR44Q==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -911,8 +913,8 @@ packages: typescript: optional: true - '@solana/rpc-parsed-types@6.10.0': - resolution: {integrity: sha512-5275mvSV1mxhwvrMVa+K7BU/nAetpHfcb+8Ql9rtA8RRf6DyiimFQFZUukE4Ez6XJihEpCHNy98yhkgai9wytQ==} + '@solana/rpc-parsed-types@8.5.0': + resolution: {integrity: sha512-ktygZ019trgAyjr8y1GN1x4x6wJYw2Ola6UogAfJT5LoNs6kV3k84yCNAlGv34xRPqCVxlWo4nsIWJf8yWQQ2w==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -920,8 +922,8 @@ packages: typescript: optional: true - '@solana/rpc-spec-types@6.10.0': - resolution: {integrity: sha512-NDZrKyZrJk4HaMFhTE/lAiMB824cWAodKqDHyKi0UteHU9pyRmil3BN1jt7e+j08mwMWwfklSgyrTaq52g6DIQ==} + '@solana/rpc-spec-types@8.5.0': + resolution: {integrity: sha512-YUTMKWWlHCGBmA1wxhIilbxJlad5vEsvc8dDO9VWr7GVkQUlipEU79iGaKk4xQ6Oo1mZWxpGz5mAJUqGraTK4A==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -929,8 +931,8 @@ packages: typescript: optional: true - '@solana/rpc-spec@6.10.0': - resolution: {integrity: sha512-yQdbWw5mZEWrwsunHR9NHkuhMXIB9sPOObwm18D53v5tAJnxTB0IcHvO647XqFDLTK/yQ4AdDtlYD1vsY07AMQ==} + '@solana/rpc-spec@8.5.0': + resolution: {integrity: sha512-0oET5yc880zFGqBMJE2UB7sxW8sIs4hmsP4bmkR2y4ipm1aScC5U+Rd8GaIrupBOVOFj+RXIorC7kQycN/9nhw==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -938,8 +940,8 @@ packages: typescript: optional: true - '@solana/rpc-subscriptions-api@6.10.0': - resolution: {integrity: sha512-CRPQoTtT1cOwOQUsqS7jgo7wYdAj7jB5ab/UmMPWVpecf2FNMhWhgvxP2s82M7VkDGTGl13qaQ0WySmi7Egrlg==} + '@solana/rpc-subscriptions-api@8.5.0': + resolution: {integrity: sha512-PJaAyqZkpG8vuzdxmdWMwp1JS5pyZ6PuL8OMhx6nCt3phkseqIs1NmAf8pQc/RZjIV3hJMMVCwSDG1DE8DY64w==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -947,8 +949,8 @@ packages: typescript: optional: true - '@solana/rpc-subscriptions-channel-websocket@6.10.0': - resolution: {integrity: sha512-KkqP1186HELPlJftA88SNAT2znR8knCVzsUipXVzY4zfW8sN3LOa0ePMzh9VZ/V+J+raTt55laR87ovAO0n+zw==} + '@solana/rpc-subscriptions-channel-websocket@8.5.0': + resolution: {integrity: sha512-sRYYwBFg31z77zfKpJBcAO9MaUWa+bO1PlBcDiToa4luXGuR3dC8TSpi1Yip4T4NCONNzK3yhyeI6sHhGHc8Qw==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -956,8 +958,8 @@ packages: typescript: optional: true - '@solana/rpc-subscriptions-spec@6.10.0': - resolution: {integrity: sha512-nWMwGaG4ulzeX2sskY5TywXF3cwEd8FDmUpLe2JBWxE8XDAOGOKcsYPYFcBgb8ee9KqfPT2PTNdcz9jOhJf34w==} + '@solana/rpc-subscriptions-spec@8.5.0': + resolution: {integrity: sha512-YdCPLHOcQWz8JhMaT/E+YC56nFDJ6D+XOTr6qRWHGe/1PIYGQDVvaFzI7+tF0b6tuv49GoMbpGdkiTX2v6KeUw==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -965,8 +967,8 @@ packages: typescript: optional: true - '@solana/rpc-subscriptions@6.10.0': - resolution: {integrity: sha512-6mfuHp/K7unFKCOTCCBC9ziEGnxe2tyJ74EbR51QUnBeCUdYD7Hhdpxic1WRSJ3UeNW/mG4OzFM6z8Wi64Eh9Q==} + '@solana/rpc-subscriptions@8.5.0': + resolution: {integrity: sha512-8hdWSDKKtMK3kRrR8TExwFo/bWHxVTu4zJ/JkePTQgNtm95kX25/hy+9JHKRtSsNUfXXYM60sQVE18cGgMU7dA==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -974,8 +976,8 @@ packages: typescript: optional: true - '@solana/rpc-transformers@6.10.0': - resolution: {integrity: sha512-2nFUrVTiE720pJOY4XKx3HuYmishw0of/4oScu76YGm6O8wsmvFvPNAkrEinmieWXQkfpBfRvLZmpl8PaAy+ug==} + '@solana/rpc-transformers@8.5.0': + resolution: {integrity: sha512-JYq+EyfzJ1ksZubU9VHynQY1Z3k1tosdxG6KE4Cua/rFuXPosSn7o5h9FLLbSB5cTVcnj0lGNrBaVYW4AVK4iA==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -983,8 +985,8 @@ packages: typescript: optional: true - '@solana/rpc-transport-http@6.10.0': - resolution: {integrity: sha512-JrdNuYi0nBbD3X8JUtgX1dQJwIwz/WJvmigDdELysXfGB2bTJpfjqGDLhCLOz2sRl66FASIEqgG/LVa2C9VXcA==} + '@solana/rpc-transport-http@8.5.0': + resolution: {integrity: sha512-xfIFZa+oxXLgA6BXaE2bXjiy2yZM1qO1URzzF0lmTekJM/okS8EZAQwEicWpYkvfdHJZ2x/oagD3AOSBBCWrsw==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -992,8 +994,8 @@ packages: typescript: optional: true - '@solana/rpc-types@6.10.0': - resolution: {integrity: sha512-zaSecTfCPvz/vcoAmKD6XoRstGHTr1EKJBD8T9UcpEFFB6CtF6DxerDB+wrzkamuT6msmnR2DWXMrYOGDAsgIg==} + '@solana/rpc-types@8.5.0': + resolution: {integrity: sha512-L050pZqQ8gaFABF26NAYoatyZZeJo52AKvQQ3i58LRtUc6wcrpCF+4x4U/EDER2YVAc6Qx1xWvGnAomGhI6vzw==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1001,8 +1003,8 @@ packages: typescript: optional: true - '@solana/rpc@6.10.0': - resolution: {integrity: sha512-EwxsqoD+NXV+m+iobnWNtATD93gTgaNsOiQOzYB1/2e+8S6fl6obdNPB55yfXgtl4jt6GV6/ae4xuPhLv76vvg==} + '@solana/rpc@8.5.0': + resolution: {integrity: sha512-7CQFNOMhXrY/LT0qdsi3h0chy4A/Ao93pyBLqFQqxzlub0st8dC5wl+MDXhkxaBos/DZOu1V4EleWv6qbLMlow==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1010,8 +1012,8 @@ packages: typescript: optional: true - '@solana/signers@6.10.0': - resolution: {integrity: sha512-+vtCc+mT1FpGxrA5oL2aaMxSHiMJ2hH5PcDIfjo2XJkHz2klZiCZyT5F9+zpltc9vdi1QTElQq59Sfplmtd33A==} + '@solana/signers@8.5.0': + resolution: {integrity: sha512-F9VvFsG9Av+Sbs4mQpuVlszb6msujxnqKQqa4TsRT24GOqKOFr4Xvs7HqgVJV/BPIDnz7u0omUhUILesHJDfkQ==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1019,8 +1021,8 @@ packages: typescript: optional: true - '@solana/subscribable@6.10.0': - resolution: {integrity: sha512-VsR6XMwkiDBkZJUcoGkEOhf397pOV75gKCL9Bx8bpi2T3Bbs0CxUpMn4yaUgAnRba3eXmjbXMNCXjttfa6sKbw==} + '@solana/subscribable@8.5.0': + resolution: {integrity: sha512-v1/hL/l4kubwYVuaMNmtQcmTgDuKG6e9Hjv9fCxkYCdDIUERgmm9DX/So1386+6rkQBVRC7wTSH86Jq+RIqNGQ==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1028,8 +1030,8 @@ packages: typescript: optional: true - '@solana/sysvars@6.10.0': - resolution: {integrity: sha512-cG13p1+onxz+20iWjwWQr1Z1jQwPm0fnjoW75fqZq7p4rVCie3L2sXvaJsYPjWKrUvpOzOIEHnqZGkG05rCpjg==} + '@solana/sysvars@8.5.0': + resolution: {integrity: sha512-vidKFEOAujEVizDUHFCmmIpHsS3Zu/fXJKcDUtbUn+bwD9Z1fRiper8rZW3Qdtgu1GmrH3O8MoyL2Nrp7k6QNw==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1037,8 +1039,8 @@ packages: typescript: optional: true - '@solana/transaction-confirmation@6.10.0': - resolution: {integrity: sha512-ULvtg65qfenh4T/GYcIlKSUv5EqDcng9UN0dxbHU4kuZdR2e0B8HN2xDC4WhcFQVeFJSbTZmaYFkeTY/Y4gfGQ==} + '@solana/transaction-confirmation@8.5.0': + resolution: {integrity: sha512-dUVHhyaJ9tt535ZJfgPAdKo6zycCAn1mqKKP/FYvCz/4FiAKnyvqj8rxd66yvvuJVhkpjbcPDDagm/P8JEYUug==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1046,8 +1048,8 @@ packages: typescript: optional: true - '@solana/transaction-messages@6.10.0': - resolution: {integrity: sha512-s7v8G3BTxGlKYIj3eWCG0g1296v+1LBt16mVnlRH5FuyaJ5AdhlhtRho5HUDpdwE8EXun+y1c48V6uhcZ8wdbQ==} + '@solana/transaction-introspection@8.5.0': + resolution: {integrity: sha512-VPYVLcpieu5YwwC1wmh3zZ/KHWmqJWPS7iMPVpf90L79/1Dvkg+YYQHnVeN4VQdb7VFnfpTqUnSQpfERDk0Sag==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1055,8 +1057,17 @@ packages: typescript: optional: true - '@solana/transactions@6.10.0': - resolution: {integrity: sha512-VADSqP9OTYmhrox4pcgDd4+RjVmednXSE0+8Y7SPK4PN1pK5Az2RJ0nSsy0xcTnaOr8mF/crwFktqPrRQwSbQA==} + '@solana/transaction-messages@8.5.0': + resolution: {integrity: sha512-8SHxirU5K0kFmOwwD6XTGI5LWP/bLvLBDbemT4xDOaL+6xkLzlTMtzlgKb/Td5UtqyYOoew0FBVLJzJx/QApOw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/transactions@8.5.0': + resolution: {integrity: sha512-IGRWI38rq5b94gy93wn/gVSQBuwNPSUv3GnWkd6R6Tc7jLbfRlYbYHJNHH5o28Fmlr+nlEn4bgu3BiqMWxuLmg==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1122,13 +1133,13 @@ packages: resolution: {integrity: sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: - vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 + vite: 6.4.5 abitype@1.2.3: resolution: {integrity: sha512-Ofer5QUnuUdTFsBRwARMoWKOH1ND5ehwYhJ3OJ/BQO+StkwQjHw0XyVh4vDttzHB7QOFhPHa/o413PJ82gU/Tg==} peerDependencies: typescript: '>=5.0.4' - zod: ^3.22.0 || ^4.0.0 + zod: 4.6.7 peerDependenciesMeta: typescript: optional: true @@ -1139,7 +1150,7 @@ packages: resolution: {integrity: sha512-dpKH+N27vRjarMVTFFkeY445VTKftzGWpL0FiT7xmVmzQRKazZexzC5uHG0f6XKsVLAuUlndnbGau6lRejClxg==} peerDependencies: typescript: '>=5.0.4' - zod: ^3.22.0 || ^4.0.0 + zod: 4.6.7 peerDependenciesMeta: typescript: optional: true @@ -1714,8 +1725,8 @@ packages: undici-types@7.24.6: resolution: {integrity: sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==} - undici-types@8.5.0: - resolution: {integrity: sha512-+FxhD+5RUdCZHlVPt+pd0DaYYHBPsgoHovxhMnFq9R1SOejHGE4ma0swzuRoKhOisEzsjFWdFedyD0JQmftrHg==} + undici-types@8.12.3: + resolution: {integrity: sha512-EXE4ydL3S76dFb27UFjNVZHTyv/TLdATj/KUe29ptdcg6qXL48J2tZ3126E5kICj5jn781OR+XlVH1N6Mz8jbA==} unified@11.0.5: resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} @@ -1755,8 +1766,8 @@ packages: typescript: optional: true - vite@6.4.3: - resolution: {integrity: sha512-NTKlcQjlAK7MlQoyb6LgaqHc8sso/pVyUJYWMws3jg21uTJw/LddqIFPcPqP6PzpgbIcZyKI85sFE4HBrQDA8A==} + vite@6.4.5: + resolution: {integrity: sha512-4enwjFfi4IwtEh0w+jPzpLVOFQiPHmmzPxcHXQOyEur47o6u0jE573DmGpjA+7irXoMLYRZD5ZaFUEneS3abPg==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true peerDependencies: @@ -1811,6 +1822,18 @@ packages: utf-8-validate: optional: true + ws@8.22.0: + resolution: {integrity: sha512-Ydggc987+RO0AnWtZ/7Wq9FtNvcrL1b/RO0ud9mWjUPgDrsAAwQSF51sm2hm1XofbU/4jkpGEsLFsZZxU+1DOg==} + 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 + y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} @@ -1831,8 +1854,8 @@ packages: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} engines: {node: '>=12'} - zod@4.4.3: - resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} + zod@4.6.7: + resolution: {integrity: sha512-g8W2D2kU6a8untc053fX1uVBKzM7yqAxW/3zwk83+6RyF2+SKOuV+c0wBDhUwzV1PaGapmZH+rmcUzPf+3CGwg==} zwitch@2.0.4: resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} @@ -2234,170 +2257,172 @@ snapshots: '@noble/hashes': 1.8.0 '@scure/base': 1.2.6 - '@solana-program/system@0.12.2(@solana/kit@6.10.0(typescript@5.9.3))': + '@solana-program/system@0.16.0(@solana/kit@8.5.0(typescript@5.9.3))': dependencies: - '@solana/kit': 6.10.0(typescript@5.9.3) + '@solana/kit': 8.5.0(typescript@5.9.3) - '@solana-program/token@0.11.0(@solana/kit@6.10.0(typescript@5.9.3))': + '@solana-program/token@0.18.0(@solana/kit@8.5.0(typescript@5.9.3))': dependencies: - '@solana-program/system': 0.12.2(@solana/kit@6.10.0(typescript@5.9.3)) - '@solana/kit': 6.10.0(typescript@5.9.3) + '@solana-program/system': 0.16.0(@solana/kit@8.5.0(typescript@5.9.3)) + '@solana/kit': 8.5.0(typescript@5.9.3) - '@solana/accounts@6.10.0(typescript@5.9.3)': + '@solana/accounts@8.5.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) + '@solana/addresses': 8.5.0(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-strings': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/rpc-spec': 8.5.0(typescript@5.9.3) + '@solana/rpc-types': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/addresses@6.10.0(typescript@5.9.3)': + '@solana/addresses@8.5.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/assertions': 8.5.0(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-strings': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/nominal-types': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/assertions@6.10.0(typescript@5.9.3)': + '@solana/assertions@8.5.0(typescript@5.9.3)': dependencies: - '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 - '@solana/codecs-core@6.10.0(typescript@5.9.3)': + '@solana/codecs-core@8.5.0(typescript@5.9.3)': dependencies: - '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 - '@solana/codecs-data-structures@6.10.0(typescript@5.9.3)': + '@solana/codecs-data-structures@8.5.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) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 - '@solana/codecs-numbers@6.10.0(typescript@5.9.3)': + '@solana/codecs-numbers@8.5.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) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 - '@solana/codecs-strings@6.10.0(typescript@5.9.3)': + '@solana/codecs-strings@8.5.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) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 - '@solana/codecs@6.10.0(typescript@5.9.3)': + '@solana/codecs@8.5.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) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-data-structures': 8.5.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.5.0(typescript@5.9.3) + '@solana/codecs-strings': 8.5.0(typescript@5.9.3) + '@solana/fixed-points': 8.5.0(typescript@5.9.3) + '@solana/options': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/errors@6.10.0(typescript@5.9.3)': + '@solana/errors@8.5.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)': + '@solana/fast-stable-stringify@8.5.0(typescript@5.9.3)': optionalDependencies: typescript: 5.9.3 - '@solana/fixed-points@6.10.0(typescript@5.9.3)': + '@solana/fixed-points@8.5.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) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 - '@solana/functional@6.10.0(typescript@5.9.3)': + '@solana/functional@8.5.0(typescript@5.9.3)': optionalDependencies: typescript: 5.9.3 - '@solana/instruction-plans@6.10.0(typescript@5.9.3)': + '@solana/instruction-plans@8.5.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) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/instructions': 8.5.0(typescript@5.9.3) + '@solana/keys': 8.5.0(typescript@5.9.3) + '@solana/promises': 8.5.0(typescript@5.9.3) + '@solana/transaction-messages': 8.5.0(typescript@5.9.3) + '@solana/transactions': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/instructions@6.10.0(typescript@5.9.3)': + '@solana/instructions@8.5.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) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 - '@solana/keys@6.10.0(typescript@5.9.3)': + '@solana/keys@8.5.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) + '@solana/assertions': 8.5.0(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-strings': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/nominal-types': 8.5.0(typescript@5.9.3) + '@solana/promises': 8.5.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) + '@solana/kit@8.5.0(typescript@5.9.3)': + dependencies: + '@solana/accounts': 8.5.0(typescript@5.9.3) + '@solana/addresses': 8.5.0(typescript@5.9.3) + '@solana/codecs': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/functional': 8.5.0(typescript@5.9.3) + '@solana/instruction-plans': 8.5.0(typescript@5.9.3) + '@solana/instructions': 8.5.0(typescript@5.9.3) + '@solana/keys': 8.5.0(typescript@5.9.3) + '@solana/offchain-messages': 8.5.0(typescript@5.9.3) + '@solana/plugin-core': 8.5.0(typescript@5.9.3) + '@solana/plugin-interfaces': 8.5.0(typescript@5.9.3) + '@solana/program-client-core': 8.5.0(typescript@5.9.3) + '@solana/programs': 8.5.0(typescript@5.9.3) + '@solana/promises': 8.5.0(typescript@5.9.3) + '@solana/rpc': 8.5.0(typescript@5.9.3) + '@solana/rpc-api': 8.5.0(typescript@5.9.3) + '@solana/rpc-parsed-types': 8.5.0(typescript@5.9.3) + '@solana/rpc-spec-types': 8.5.0(typescript@5.9.3) + '@solana/rpc-subscriptions': 8.5.0(typescript@5.9.3) + '@solana/rpc-types': 8.5.0(typescript@5.9.3) + '@solana/signers': 8.5.0(typescript@5.9.3) + '@solana/subscribable': 8.5.0(typescript@5.9.3) + '@solana/sysvars': 8.5.0(typescript@5.9.3) + '@solana/transaction-confirmation': 8.5.0(typescript@5.9.3) + '@solana/transaction-introspection': 8.5.0(typescript@5.9.3) + '@solana/transaction-messages': 8.5.0(typescript@5.9.3) + '@solana/transactions': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: @@ -2405,167 +2430,171 @@ snapshots: - fastestsmallesttextencoderdecoder - utf-8-validate - '@solana/nominal-types@6.10.0(typescript@5.9.3)': + '@solana/nominal-types@8.5.0(typescript@5.9.3)': optionalDependencies: typescript: 5.9.3 - '@solana/offchain-messages@6.10.0(typescript@5.9.3)': + '@solana/offchain-messages@8.5.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) + '@solana/addresses': 8.5.0(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-data-structures': 8.5.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.5.0(typescript@5.9.3) + '@solana/codecs-strings': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/keys': 8.5.0(typescript@5.9.3) + '@solana/nominal-types': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/options@6.10.0(typescript@5.9.3)': + '@solana/options@8.5.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) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-data-structures': 8.5.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.5.0(typescript@5.9.3) + '@solana/codecs-strings': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/plugin-core@6.10.0(typescript@5.9.3)': + '@solana/plugin-core@8.5.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) + '@solana/plugin-interfaces@8.5.0(typescript@5.9.3)': + dependencies: + '@solana/accounts': 8.5.0(typescript@5.9.3) + '@solana/addresses': 8.5.0(typescript@5.9.3) + '@solana/instruction-plans': 8.5.0(typescript@5.9.3) + '@solana/keys': 8.5.0(typescript@5.9.3) + '@solana/rpc-spec': 8.5.0(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 8.5.0(typescript@5.9.3) + '@solana/rpc-types': 8.5.0(typescript@5.9.3) + '@solana/signers': 8.5.0(typescript@5.9.3) + '@solana/transactions': 8.5.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) + '@solana/program-client-core@8.5.0(typescript@5.9.3)': + dependencies: + '@solana/accounts': 8.5.0(typescript@5.9.3) + '@solana/addresses': 8.5.0(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/instruction-plans': 8.5.0(typescript@5.9.3) + '@solana/instructions': 8.5.0(typescript@5.9.3) + '@solana/plugin-interfaces': 8.5.0(typescript@5.9.3) + '@solana/rpc-api': 8.5.0(typescript@5.9.3) + '@solana/signers': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/programs@6.10.0(typescript@5.9.3)': + '@solana/programs@8.5.0(typescript@5.9.3)': dependencies: - '@solana/addresses': 6.10.0(typescript@5.9.3) - '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/addresses': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/promises@6.10.0(typescript@5.9.3)': + '@solana/promises@8.5.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) + '@solana/rpc-api@8.5.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.5.0(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-strings': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/keys': 8.5.0(typescript@5.9.3) + '@solana/rpc-parsed-types': 8.5.0(typescript@5.9.3) + '@solana/rpc-spec': 8.5.0(typescript@5.9.3) + '@solana/rpc-transformers': 8.5.0(typescript@5.9.3) + '@solana/rpc-types': 8.5.0(typescript@5.9.3) + '@solana/transaction-messages': 8.5.0(typescript@5.9.3) + '@solana/transactions': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/rpc-parsed-types@6.10.0(typescript@5.9.3)': + '@solana/rpc-parsed-types@8.5.0(typescript@5.9.3)': optionalDependencies: typescript: 5.9.3 - '@solana/rpc-spec-types@6.10.0(typescript@5.9.3)': + '@solana/rpc-spec-types@8.5.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 - '@solana/rpc-spec@6.10.0(typescript@5.9.3)': + '@solana/rpc-spec@8.5.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) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/rpc-spec-types': 8.5.0(typescript@5.9.3) + '@solana/subscribable': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 - '@solana/rpc-subscriptions-api@6.10.0(typescript@5.9.3)': + '@solana/rpc-subscriptions-api@8.5.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) + '@solana/addresses': 8.5.0(typescript@5.9.3) + '@solana/keys': 8.5.0(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 8.5.0(typescript@5.9.3) + '@solana/rpc-transformers': 8.5.0(typescript@5.9.3) + '@solana/rpc-types': 8.5.0(typescript@5.9.3) + '@solana/transaction-messages': 8.5.0(typescript@5.9.3) + '@solana/transactions': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/rpc-subscriptions-channel-websocket@6.10.0(typescript@5.9.3)': + '@solana/rpc-subscriptions-channel-websocket@8.5.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.0 + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/functional': 8.5.0(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 8.5.0(typescript@5.9.3) + '@solana/subscribable': 8.5.0(typescript@5.9.3) + ws: 8.22.0 optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: - bufferutil - utf-8-validate - '@solana/rpc-subscriptions-spec@6.10.0(typescript@5.9.3)': + '@solana/rpc-subscriptions-spec@8.5.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) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/promises': 8.5.0(typescript@5.9.3) + '@solana/rpc-spec-types': 8.5.0(typescript@5.9.3) + '@solana/subscribable': 8.5.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) + '@solana/rpc-subscriptions@8.5.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/fast-stable-stringify': 8.5.0(typescript@5.9.3) + '@solana/functional': 8.5.0(typescript@5.9.3) + '@solana/promises': 8.5.0(typescript@5.9.3) + '@solana/rpc-spec-types': 8.5.0(typescript@5.9.3) + '@solana/rpc-subscriptions-api': 8.5.0(typescript@5.9.3) + '@solana/rpc-subscriptions-channel-websocket': 8.5.0(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 8.5.0(typescript@5.9.3) + '@solana/rpc-transformers': 8.5.0(typescript@5.9.3) + '@solana/rpc-types': 8.5.0(typescript@5.9.3) + '@solana/subscribable': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: @@ -2573,105 +2602,105 @@ snapshots: - fastestsmallesttextencoderdecoder - utf-8-validate - '@solana/rpc-transformers@6.10.0(typescript@5.9.3)': + '@solana/rpc-transformers@8.5.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) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/functional': 8.5.0(typescript@5.9.3) + '@solana/nominal-types': 8.5.0(typescript@5.9.3) + '@solana/rpc-spec-types': 8.5.0(typescript@5.9.3) + '@solana/rpc-types': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/rpc-transport-http@6.10.0(typescript@5.9.3)': + '@solana/rpc-transport-http@8.5.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.5.0 + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/rpc-spec': 8.5.0(typescript@5.9.3) + '@solana/rpc-spec-types': 8.5.0(typescript@5.9.3) + undici-types: 8.12.3 optionalDependencies: typescript: 5.9.3 - '@solana/rpc-types@6.10.0(typescript@5.9.3)': + '@solana/rpc-types@8.5.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) + '@solana/addresses': 8.5.0(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.5.0(typescript@5.9.3) + '@solana/codecs-strings': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/fixed-points': 8.5.0(typescript@5.9.3) + '@solana/nominal-types': 8.5.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) + '@solana/rpc@8.5.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/fast-stable-stringify': 8.5.0(typescript@5.9.3) + '@solana/functional': 8.5.0(typescript@5.9.3) + '@solana/rpc-api': 8.5.0(typescript@5.9.3) + '@solana/rpc-spec': 8.5.0(typescript@5.9.3) + '@solana/rpc-spec-types': 8.5.0(typescript@5.9.3) + '@solana/rpc-transformers': 8.5.0(typescript@5.9.3) + '@solana/rpc-transport-http': 8.5.0(typescript@5.9.3) + '@solana/rpc-types': 8.5.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) + '@solana/signers@8.5.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.5.0(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/instructions': 8.5.0(typescript@5.9.3) + '@solana/keys': 8.5.0(typescript@5.9.3) + '@solana/nominal-types': 8.5.0(typescript@5.9.3) + '@solana/offchain-messages': 8.5.0(typescript@5.9.3) + '@solana/transaction-messages': 8.5.0(typescript@5.9.3) + '@solana/transactions': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/subscribable@6.10.0(typescript@5.9.3)': + '@solana/subscribable@8.5.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/errors': 8.5.0(typescript@5.9.3) + '@solana/promises': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 - '@solana/sysvars@6.10.0(typescript@5.9.3)': + '@solana/sysvars@8.5.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) + '@solana/accounts': 8.5.0(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-data-structures': 8.5.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/rpc-types': 8.5.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) + '@solana/transaction-confirmation@8.5.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.5.0(typescript@5.9.3) + '@solana/codecs-strings': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/keys': 8.5.0(typescript@5.9.3) + '@solana/promises': 8.5.0(typescript@5.9.3) + '@solana/rpc': 8.5.0(typescript@5.9.3) + '@solana/rpc-subscriptions': 8.5.0(typescript@5.9.3) + '@solana/rpc-types': 8.5.0(typescript@5.9.3) + '@solana/transaction-messages': 8.5.0(typescript@5.9.3) + '@solana/transactions': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: @@ -2679,36 +2708,51 @@ snapshots: - fastestsmallesttextencoderdecoder - utf-8-validate - '@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) + '@solana/transaction-introspection@8.5.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.5.0(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-strings': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/instructions': 8.5.0(typescript@5.9.3) + '@solana/rpc-types': 8.5.0(typescript@5.9.3) + '@solana/transaction-messages': 8.5.0(typescript@5.9.3) + '@solana/transactions': 8.5.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) + '@solana/transaction-messages@8.5.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.5.0(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-data-structures': 8.5.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/functional': 8.5.0(typescript@5.9.3) + '@solana/instructions': 8.5.0(typescript@5.9.3) + '@solana/nominal-types': 8.5.0(typescript@5.9.3) + '@solana/rpc-types': 8.5.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/transactions@8.5.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.5.0(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-data-structures': 8.5.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.5.0(typescript@5.9.3) + '@solana/codecs-strings': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/functional': 8.5.0(typescript@5.9.3) + '@solana/instructions': 8.5.0(typescript@5.9.3) + '@solana/keys': 8.5.0(typescript@5.9.3) + '@solana/nominal-types': 8.5.0(typescript@5.9.3) + '@solana/rpc-types': 8.5.0(typescript@5.9.3) + '@solana/transaction-messages': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: @@ -2776,7 +2820,7 @@ snapshots: '@ungap/structured-clone@1.3.1': {} - '@vitejs/plugin-react@4.7.0(vite@6.4.3(@types/node@25.9.6)(tsx@4.22.4)(yaml@2.9.0))': + '@vitejs/plugin-react@4.7.0(vite@6.4.5(@types/node@25.9.6)(tsx@4.22.4)(yaml@2.9.0))': dependencies: '@babel/core': 7.29.7 '@babel/plugin-transform-react-jsx-self': 7.29.7(@babel/core@7.29.7) @@ -2784,19 +2828,19 @@ snapshots: '@rolldown/pluginutils': 1.0.0-beta.27 '@types/babel__core': 7.20.5 react-refresh: 0.17.0 - vite: 6.4.3(@types/node@25.9.6)(tsx@4.22.4)(yaml@2.9.0) + vite: 6.4.5(@types/node@25.9.6)(tsx@4.22.4)(yaml@2.9.0) transitivePeerDependencies: - supports-color - abitype@1.2.3(typescript@5.9.3)(zod@4.4.3): + abitype@1.2.3(typescript@5.9.3)(zod@4.6.7): optionalDependencies: typescript: 5.9.3 - zod: 4.4.3 + zod: 4.6.7 - abitype@1.2.4(typescript@5.9.3)(zod@4.4.3): + abitype@1.2.4(typescript@5.9.3)(zod@4.6.7): optionalDependencies: typescript: 5.9.3 - zod: 4.4.3 + zod: 4.6.7 ansi-regex@5.0.1: {} @@ -3374,14 +3418,14 @@ snapshots: transitivePeerDependencies: - supports-color - mppx@0.8.19(typescript@5.9.3)(viem@2.56.3(typescript@5.9.3)(zod@4.4.3)): + mppx@0.8.19(typescript@5.9.3)(viem@2.56.3(typescript@5.9.3)(zod@4.6.7)): dependencies: '@stripe/stripe-js': 9.13.0 eventsource-parser: 3.1.1 - ox: 0.14.33(typescript@5.9.3)(zod@4.4.3) + ox: 0.14.33(typescript@5.9.3)(zod@4.6.7) structured-headers: 2.0.3 - viem: 2.56.3(typescript@5.9.3)(zod@4.4.3) - zod: 4.4.3 + viem: 2.56.3(typescript@5.9.3)(zod@4.6.7) + zod: 4.6.7 transitivePeerDependencies: - typescript @@ -3391,7 +3435,7 @@ snapshots: node-releases@2.0.57: {} - ox@0.14.33(typescript@5.9.3)(zod@4.4.3): + ox@0.14.33(typescript@5.9.3)(zod@4.6.7): dependencies: '@adraffy/ens-normalize': 1.11.1 '@noble/ciphers': 1.3.0 @@ -3399,14 +3443,14 @@ snapshots: '@noble/hashes': 1.8.0 '@scure/bip32': 1.7.0 '@scure/bip39': 1.6.0 - abitype: 1.2.4(typescript@5.9.3)(zod@4.4.3) + abitype: 1.2.4(typescript@5.9.3)(zod@4.6.7) eventemitter3: 5.0.1 optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: - zod - ox@0.14.44(typescript@5.9.3)(zod@4.4.3): + ox@0.14.44(typescript@5.9.3)(zod@4.6.7): dependencies: '@adraffy/ens-normalize': 1.11.1 '@noble/ciphers': 1.3.0 @@ -3414,7 +3458,7 @@ snapshots: '@noble/hashes': 1.8.0 '@scure/bip32': 1.7.0 '@scure/bip39': 1.6.0 - abitype: 1.2.4(typescript@5.9.3)(zod@4.4.3) + abitype: 1.2.4(typescript@5.9.3)(zod@4.6.7) eventemitter3: 5.0.1 optionalDependencies: typescript: 5.9.3 @@ -3630,7 +3674,7 @@ snapshots: undici-types@7.24.6: optional: true - undici-types@8.5.0: {} + undici-types@8.12.3: {} unified@11.0.5: dependencies: @@ -3681,15 +3725,15 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.3 - viem@2.56.3(typescript@5.9.3)(zod@4.4.3): + viem@2.56.3(typescript@5.9.3)(zod@4.6.7): dependencies: '@noble/curves': 1.9.1 '@noble/hashes': 1.8.0 '@scure/bip32': 1.7.0 '@scure/bip39': 1.6.0 - abitype: 1.2.3(typescript@5.9.3)(zod@4.4.3) + abitype: 1.2.3(typescript@5.9.3)(zod@4.6.7) isows: 1.0.7(ws@8.21.0) - ox: 0.14.44(typescript@5.9.3)(zod@4.4.3) + ox: 0.14.44(typescript@5.9.3)(zod@4.6.7) ws: 8.21.0 optionalDependencies: typescript: 5.9.3 @@ -3698,7 +3742,7 @@ snapshots: - utf-8-validate - zod - vite@6.4.3(@types/node@25.9.6)(tsx@4.22.4)(yaml@2.9.0): + vite@6.4.5(@types/node@25.9.6)(tsx@4.22.4)(yaml@2.9.0): dependencies: esbuild: 0.25.12 fdir: 6.5.0(picomatch@4.0.4) @@ -3720,6 +3764,8 @@ snapshots: ws@8.21.0: {} + ws@8.22.0: {} + y18n@5.0.8: {} yallist@3.1.1: {} @@ -3739,6 +3785,6 @@ snapshots: y18n: 5.0.8 yargs-parser: 21.1.1 - zod@4.4.3: {} + zod@4.6.7: {} zwitch@2.0.4: {} diff --git a/playground/pnpm-workspace.yaml b/playground/pnpm-workspace.yaml index 6468983e1..5270552da 100644 --- a/playground/pnpm-workspace.yaml +++ b/playground/pnpm-workspace.yaml @@ -8,6 +8,8 @@ overrides: baseline-browser-mapping: '2.11.0' browserslist: '4.28.7' 'nanoid@3.3.11': '3.3.18' + vite: '6.4.5' + zod: '4.6.7' postcss: '8.5.23' react-router: '7.18.2' shell-quote: '1.11.0' diff --git a/playground/test-results/.last-run.json b/playground/test-results/.last-run.json new file mode 100644 index 000000000..cbcc1fbac --- /dev/null +++ b/playground/test-results/.last-run.json @@ -0,0 +1,4 @@ +{ + "status": "passed", + "failedTests": [] +} \ No newline at end of file diff --git a/python/pyproject.toml b/python/pyproject.toml index 8faf2d366..a30428783 100644 --- a/python/pyproject.toml +++ b/python/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "solana-pay-kit" -version = "0.10.0" +version = "0.11.0" description = "Building blocks for Agentic payments (x402, MPP, AP2)" readme = "README.md" requires-python = ">=3.11" @@ -47,7 +47,7 @@ packages = ["src/solana_pay_kit"] [tool.uv] # docspec-python constrains Black to the vulnerable 23.x line even though its # formatter integration remains compatible with current Black releases. -override-dependencies = ["black>=26.3.1"] +override-dependencies = ["black>=26.10.1"] [tool.ruff] target-version = "py311" diff --git a/python/src/solana_pay_kit/protocols/x402/exact/verify.py b/python/src/solana_pay_kit/protocols/x402/exact/verify.py index 126a557d7..200b4f7c2 100644 --- a/python/src/solana_pay_kit/protocols/x402/exact/verify.py +++ b/python/src/solana_pay_kit/protocols/x402/exact/verify.py @@ -180,6 +180,13 @@ def verify( if expected_memo: ExactVerifier._find_memo_match(account_keys, instructions, expected_memo) + # §2.1.4: only the fee payer and the transfer authority may sign. + allowed_signers = (account_keys[0], transfer["authority"]) + for signer in account_keys[: int(message.header.num_required_signatures)]: + if signer not in allowed_signers: + reason = "invalid_exact_svm_payload_transaction_unexpected_signer" + raise InvalidProofError(reason, code=reason) + # The destination ATA must pre-exist; ATA-create is never accepted. transfer["destinationCreateAta"] = False return transfer diff --git a/python/tests/test_pk_x402_verifier.py b/python/tests/test_pk_x402_verifier.py index 681b47889..908d31b85 100644 --- a/python/tests/test_pk_x402_verifier.py +++ b/python/tests/test_pk_x402_verifier.py @@ -523,6 +523,22 @@ def test_reject_unknown_fourth_instruction(): assert e.value.code == "invalid_exact_svm_payload_unknown_fourth_instruction" +def test_reject_extra_required_signer(): + fee_payer, authority, pay_to, src, dest = _scenario() + extra = Keypair() + memo = Instruction(Pubkey.from_string(MEMO_PROGRAM), b"/pay", [AccountMeta(extra.pubkey(), True, False)]) + ixs = [ + _compute_limit_ix(), + _compute_price_ix(), + _transfer_checked_ix(source=src, mint=MINT, destination=dest, authority=authority.pubkey()), + memo, + ] + tx = _tx_b64(fee_payer, ixs, [fee_payer, authority, extra]) + with pytest.raises(InvalidProofError) as e: + ExactVerifier.verify(tx, _requirement(pay_to), [str(fee_payer.pubkey())]) + assert e.value.code == "invalid_exact_svm_payload_transaction_unexpected_signer" + + # -- rule 10: memo binding --------------------------------------------------- diff --git a/python/uv.lock b/python/uv.lock index 66284fb52..9e1f8314a 100644 --- a/python/uv.lock +++ b/python/uv.lock @@ -14,7 +14,7 @@ resolution-markers = [ ] [manifest] -overrides = [{ name = "black", specifier = ">=26.3.1" }] +overrides = [{ name = "black", specifier = ">=26.10.1" }] [[package]] name = "aiolimiter" @@ -93,7 +93,7 @@ wheels = [ [[package]] name = "black" -version = "26.5.1" +version = "26.10.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, @@ -103,29 +103,29 @@ dependencies = [ { name = "platformdirs" }, { name = "pytokens" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c0/37/5628dd55bf2b34257fc7603f0fe97c40e3aaf24265f416a9c85c95ca1436/black-26.5.1.tar.gz", hash = "sha256:dd321f668053961824bcc1be1cc1df748b2d7e4fa28086b08331e577b0100a73", size = 679439, upload-time = "2026-05-18T16:53:36.107Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4b/96/3c3e09f09f44a37aac36b178a279cd19aa7001bd796187a7b162a294c81f/black-26.5.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:96ae2c733b2aabdd9986e2c5df628ff3473676cd1c5faded1ff496cf6d74083c", size = 1970639, upload-time = "2026-05-18T17:05:11.461Z" }, - { url = "https://files.pythonhosted.org/packages/83/ea/5ad117b9ee3ecd933c712bcbae610006e5b7cc9f41c526cd7ed3b6c4124c/black-26.5.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0e48b87e03bf109288e55cfceadcfa15ff5470aca2851a851950ed2926f450d7", size = 1792130, upload-time = "2026-05-18T17:05:12.983Z" }, - { url = "https://files.pythonhosted.org/packages/06/3a/7c448bc623fcdfa96672531beb5a616ea5e64f6975955254d7731ffb0ad9/black-26.5.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5119fa92ae61f786e8c3662fd60aece1d0a2dd5cca5d0c79417a95e7a4272a59", size = 1846134, upload-time = "2026-05-18T17:05:14.506Z" }, - { url = "https://files.pythonhosted.org/packages/a1/5b/0b39b3a5917f0657ac014ad2edb58c139553a478adfe7f817abf1622ff6e/black-26.5.1-cp311-cp311-win_amd64.whl", hash = "sha256:30d3c14661f2792e9142cce3eeeb1cbc175b3eb5f733be0c8eeb99651e52b0c3", size = 1478883, upload-time = "2026-05-18T17:05:16.542Z" }, - { url = "https://files.pythonhosted.org/packages/4c/48/dc222692e0f95030db1bbfb6c857e76858bad09058221ea7aae815255327/black-26.5.1-cp311-cp311-win_arm64.whl", hash = "sha256:1ef92b76f7733f282fd096ea406200b5a286c42947412b0eaff3a74e3616cefe", size = 1277776, upload-time = "2026-05-18T17:05:18.029Z" }, - { url = "https://files.pythonhosted.org/packages/24/99/7744b906703228264ef73bdd534df88ec1ef3de45c4e78f6d31b9e32d0c9/black-26.5.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4ad6fa01f941920f54f2bbb35f3df7673428a0ef98a0b0840c2eaef3b110efa8", size = 2012518, upload-time = "2026-05-18T17:05:20.108Z" }, - { url = "https://files.pythonhosted.org/packages/b7/c0/c5a3b1636dfd09c42534f2b3cf33506814f6d3e066fb0879ffa16c1ae860/black-26.5.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3915f256e75a2d7cf88d8953d37f780455dc586cc72dee059c528fe77f581217", size = 1816016, upload-time = "2026-05-18T17:05:21.84Z" }, - { url = "https://files.pythonhosted.org/packages/1f/0e/36044316b65ca471d3bb6d3703fd06fb50c6b727c3562f6a5a3153634f88/black-26.5.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d98d4137277c75dfb898ec8d846c4fd68ba1e9cf77f95e2865c203dc18f4c3d", size = 1884150, upload-time = "2026-05-18T17:05:23.546Z" }, - { url = "https://files.pythonhosted.org/packages/b3/33/dafc5808c2af43672912111d7c3354af1615f7e2be3bed7a878461abbe4d/black-26.5.1-cp312-cp312-win_amd64.whl", hash = "sha256:a1dca32d9f1784af512a13410ec204c6f7f0aa9797a111c42e1c03449821c264", size = 1486825, upload-time = "2026-05-18T17:05:25.004Z" }, - { url = "https://files.pythonhosted.org/packages/82/14/b965ee6ad2a311f28bdbf692def3ee9848d2ae289dab28b27657fcee3e78/black-26.5.1-cp312-cp312-win_arm64.whl", hash = "sha256:1037d5ac7b7b310b2632ad867ec8d0e4c4819dcdb0b820f63135da746a24e418", size = 1288646, upload-time = "2026-05-18T17:05:26.477Z" }, - { url = "https://files.pythonhosted.org/packages/3f/5c/c384363980e11e25ca6b93205949bb331fbf35f4e0dbec376dfa6326cec8/black-26.5.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2b36cf2ddf5566e205f6535f782a62194a184d33e175b64ae8c40b1737522be3", size = 2009020, upload-time = "2026-05-18T17:05:28.132Z" }, - { url = "https://files.pythonhosted.org/packages/0b/df/9f31c5e0babbfed77d505fc5d120beb98b21b33feaeded3924ea941fe360/black-26.5.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1f7ea64ebfa01b50f693508fc39f875e264446d3b097088f84f203b9d09618a0", size = 1813335, upload-time = "2026-05-18T17:05:31.266Z" }, - { url = "https://files.pythonhosted.org/packages/fb/24/8e7b9a2fa61b0afd82209efe937557d180a1fa055bd7f6161eb9defc3719/black-26.5.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ecb3e624844c798144e9bd986954e0adc81d8911a1f30f375e1252fe26e8c294", size = 1881614, upload-time = "2026-05-18T17:05:32.718Z" }, - { url = "https://files.pythonhosted.org/packages/49/ad/b4e0d9365ba8ac34f6bbab62a4b1b2dd5d618fac3fa1b8db968c844201b5/black-26.5.1-cp313-cp313-win_amd64.whl", hash = "sha256:e1a26503279b6b310669fb0b219c39e4820b77e8189fe80f522bb511f247db0a", size = 1488925, upload-time = "2026-05-18T17:05:34.259Z" }, - { url = "https://files.pythonhosted.org/packages/a1/4b/652b859bf5df88a751c30451b09338f7fd26a77d1271c666992f836b7711/black-26.5.1-cp313-cp313-win_arm64.whl", hash = "sha256:5c34b25da232ead53a6f335b76dbea124f4d152ad568b9080d6f944bc2b34b52", size = 1289883, upload-time = "2026-05-18T17:05:36.019Z" }, - { url = "https://files.pythonhosted.org/packages/a6/16/a8da8eb208c51c7f4ce74609a45d0dcc6d8a2141e45e81ee5289d1bb0d59/black-26.5.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:e88976690a64b0af98312ca958415849cb42423423c5f2ee74af4b49a97a2168", size = 2004800, upload-time = "2026-05-18T17:05:38.182Z" }, - { url = "https://files.pythonhosted.org/packages/11/8a/a479296a19e383b70a725882a6cf3d786540601ff03cabbaaf1cce864c5a/black-26.5.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:32d5ea7f6c8bdfa6e648326ebca1f02b0764e2a029edc6f8dce2627e19d468c3", size = 1815576, upload-time = "2026-05-18T17:05:40.309Z" }, - { url = "https://files.pythonhosted.org/packages/81/6b/cfaf3d39f25132c156a068f6b805576c9103a84086019507c70e1911ee7d/black-26.5.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ea8d16dc41655aa113cd64665e7219446cd7e4ff2248d7178eaa905190c86b18", size = 1877927, upload-time = "2026-05-18T17:05:42.463Z" }, - { url = "https://files.pythonhosted.org/packages/66/76/302e313964bcff7e28df329d39f84f5270095730d85ff0acc260610a0d82/black-26.5.1-cp314-cp314-win_amd64.whl", hash = "sha256:577f21094ea469ef92ec1adaf2c9441a226d2144d01a5be2fa823cecf6543e50", size = 1511860, upload-time = "2026-05-18T17:05:43.943Z" }, - { url = "https://files.pythonhosted.org/packages/27/4e/a3827e35e0e567f9f9ee59e2a0ab979267dca98718f25547ca8c6733afd4/black-26.5.1-cp314-cp314-win_arm64.whl", hash = "sha256:ed1a20af114c301a0269bf01163d51dbef72737fd65f850001e7cbe7f3c7abae", size = 1316632, upload-time = "2026-05-18T17:05:45.521Z" }, - { url = "https://files.pythonhosted.org/packages/94/51/f975cae76d44274cc2868dc9040ac5d58d464784610234455b4e7b19c6ef/black-26.5.1-py3-none-any.whl", hash = "sha256:4ed7f7da04046d2e488437170797d3b4a4ad83906683bcb7dfc68b673bbce5e2", size = 213693, upload-time = "2026-05-18T16:53:33.964Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/f8/65/a9611a6ec0a8c88d86e59385da02d68d9533f7e86a05913d20c67be54029/black-26.10.1.tar.gz", hash = "sha256:5f9f83beae62437e060dafd53d7f1fc327e3d3494f74d72ee5c2b73eb90fc4e7", size = 741979, upload-time = "2026-10-10T04:13:40.776Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6f/1e/c1d4f71299d45f4ff54c9c42ef9214d6b228223f196bc1bb2ee196aeaeee/black-26.10.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9a0219b29cd70e49f920acb7081e6ce5025c719008447c521d0200dcad93206a", size = 2121821, upload-time = "2026-10-10T04:18:36.793Z" }, + { url = "https://files.pythonhosted.org/packages/7f/e2/43944049c0945199bbd5c8b291b85306bfd0eeccbc908bf65538a69ff1b0/black-26.10.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7bdade400bfe24d78a7762896acc2f9a8e1a17fb0fd0536bf6b7c7097cf3eec7", size = 1961908, upload-time = "2026-10-10T04:18:38.942Z" }, + { url = "https://files.pythonhosted.org/packages/d5/e9/9616d58f69f0e4bfa89ebe8686b6ef50f4b4f0f91237ae4c76f34dabf8aa/black-26.10.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ff57f63029aa1353fa8b1b0c8971fd88a6c92dc766608d2eee33ad2deb23270e", size = 2019042, upload-time = "2026-10-10T04:18:40.612Z" }, + { url = "https://files.pythonhosted.org/packages/c5/de/0415cce69e2402a5c186cdb5462a0edd3fa44d69d1a1630e68e58daaa6a4/black-26.10.1-cp311-cp311-win_amd64.whl", hash = "sha256:3414a0c52901964dceabd98c7c56beac0f964115a116ecedcce7247359b14017", size = 1608383, upload-time = "2026-10-10T04:18:42.25Z" }, + { url = "https://files.pythonhosted.org/packages/a9/61/af18e716432e932f166ce9dfa419ce3f05fd5ef8c52c0510d27ae41aaa51/black-26.10.1-cp311-cp311-win_arm64.whl", hash = "sha256:1935b32f5326028019856e18cb42b4da63db23765dc84464cec723e0de478a9b", size = 1466048, upload-time = "2026-10-10T04:18:44.271Z" }, + { url = "https://files.pythonhosted.org/packages/f7/ca/357ccdd12e8f8429539f8f52edc153de58acba84f6670ac36c254a276691/black-26.10.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fe85fc4019bee59bc495c0f2a8ee76c5cd02c7015508d94a967ba2376f39a52c", size = 2167369, upload-time = "2026-10-10T04:18:45.948Z" }, + { url = "https://files.pythonhosted.org/packages/a5/a2/4709110a7ca326ba7b4f81a669fbebc20653c79a972b0f8de4ba5b5c5e68/black-26.10.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:182f6c32be38074b16d378498c498b32cb51928178ee611485344972c35ec9c6", size = 1990732, upload-time = "2026-10-10T04:18:48.252Z" }, + { url = "https://files.pythonhosted.org/packages/1e/96/9f8fa839c169d19c38ce6582d9449f2d7d70dabd313ac28f15a930260c1f/black-26.10.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b5347d760f0c02bb00dd249384cab71c3bf828b4f68d5b401eb116e0390f147d", size = 2065235, upload-time = "2026-10-10T04:18:50.064Z" }, + { url = "https://files.pythonhosted.org/packages/2b/ee/929eaf7de6f05a3141d6df72acf9248118f49a5e48f9375be3180e9babf7/black-26.10.1-cp312-cp312-win_amd64.whl", hash = "sha256:4d9a90516db1d99c25dbb20cc0998e0e01531dd903466c7744e56d66f864220a", size = 1621579, upload-time = "2026-10-10T04:18:51.59Z" }, + { url = "https://files.pythonhosted.org/packages/90/3a/8b6a44abf9648b087311003b91298226c1763172cd8d223ece5b7cf8f795/black-26.10.1-cp312-cp312-win_arm64.whl", hash = "sha256:2ffbc023a12d0c729408823b8f10514490bd0baa301d0d4e21a7240249f9507f", size = 1469662, upload-time = "2026-10-10T04:18:53.245Z" }, + { url = "https://files.pythonhosted.org/packages/99/6b/bc0d39990bd7a71457d669639fa06acf6191bec28bafe8b8103f597cce76/black-26.10.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b6272cfd7e1e8e271f5b0e0207259fe2834687e5cb9b5f620b34a44db9754993", size = 2153812, upload-time = "2026-10-10T04:18:55.041Z" }, + { url = "https://files.pythonhosted.org/packages/85/0e/cc83b88a6b1a51fc051aa4e24663918f0bf4fa9fca98552ee93a125a6780/black-26.10.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:978113a40223a6aaefc17364176a809a320e6b288683841427fff04c6d7b4130", size = 1980352, upload-time = "2026-10-10T04:18:56.849Z" }, + { url = "https://files.pythonhosted.org/packages/7b/0f/4dd24ea0ebadbe05e293c3ea7fbebd4389f50508f714640c9b309a0849d2/black-26.10.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:03c0ddd93bb392e71209903a691767eb366fe1a76deb9509ccbaae9e1f14bb52", size = 2055268, upload-time = "2026-10-10T04:18:58.974Z" }, + { url = "https://files.pythonhosted.org/packages/a2/06/221f8e81891ecf5e4df9c258a11037997f1f218533ffe4fa1dc4db37f19c/black-26.10.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6dba8138cdc99061ef07b958ac082d2aa057b6961d1936f9717c350f02bab5f", size = 1625938, upload-time = "2026-10-10T04:19:00.65Z" }, + { url = "https://files.pythonhosted.org/packages/2b/3b/763d2dd073fc1e2cbf0fe5e584fe96913bf0d14cd725d1116f4b38453adf/black-26.10.1-cp313-cp313-win_arm64.whl", hash = "sha256:d42dd2fac7c342ae67e64ee99c9532e20b2a84e92c79ed3317fa2ef54c801d93", size = 1470752, upload-time = "2026-10-10T04:19:03.009Z" }, + { url = "https://files.pythonhosted.org/packages/76/7b/e8d275b23f3023881c0b0d8ce3bbda0d100c79bdef87fb6518bf9e0c5040/black-26.10.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:8375962579d537364cc0efa19b1474481915d3a793f9fc0774901814c5e5b5f4", size = 2147731, upload-time = "2026-10-10T04:19:04.643Z" }, + { url = "https://files.pythonhosted.org/packages/ee/62/e44f86ee5fc7b893ee0ee935a79c785932da7758d2c339749d90a20ef213/black-26.10.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:d8b3a9074a680b3c5749633714e9ae3992a1e5a23343a97ad61cd9b119b444d2", size = 1981714, upload-time = "2026-10-10T04:19:06.287Z" }, + { url = "https://files.pythonhosted.org/packages/89/2f/e12ca76edfcd037fe9e7e7635d9468d1d51255cf25a01b2f8f97a38f147d/black-26.10.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:289282aa2e09d3162312a3be1788ff21b08e9ea9cc4a81e656024728b32428fb", size = 2047807, upload-time = "2026-10-10T04:19:08.193Z" }, + { url = "https://files.pythonhosted.org/packages/c3/af/676d3c5cbb2ab0f17c8459b3ae8ea15ebdcc5a2f1c1c586228ec85b8897f/black-26.10.1-cp314-cp314-win_amd64.whl", hash = "sha256:5cd88fd7b444ca51f3fc883b6f6657ea53a258b0b2eef6d9f2dfcfa17ce0e27b", size = 1652537, upload-time = "2026-10-10T04:19:09.817Z" }, + { url = "https://files.pythonhosted.org/packages/ad/7b/860022d369fdd5fe14280b1e7109f58753c371ff91ce2311d68a056e488a/black-26.10.1-cp314-cp314-win_arm64.whl", hash = "sha256:2520037aa62f8a1454d0811b8f5c88b444445b03a4bfba480d8d220893b64c34", size = 1504226, upload-time = "2026-10-10T04:19:11.367Z" }, + { url = "https://files.pythonhosted.org/packages/b1/28/9dd29175c1db777e6189e2a0bb5f37101adf19c3e509b236c8920f778d0b/black-26.10.1-py3-none-any.whl", hash = "sha256:28842f9a8207cc1df6eb983a35a14c5a0dfcd603d214fe82d84bef552afd2e3a", size = 239267, upload-time = "2026-10-10T04:13:38.808Z" }, ] [[package]] @@ -1931,7 +1931,7 @@ gcp-kms = [ [[package]] name = "solana-pay-kit" -version = "0.10.0" +version = "0.11.0" source = { editable = "." } dependencies = [ { name = "certifi" }, @@ -2369,14 +2369,14 @@ wheels = [ [[package]] name = "werkzeug" -version = "3.1.8" +version = "3.1.9" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markupsafe" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/dd/b2/381be8cfdee792dd117872481b6e378f85c957dd7c5bca38897b08f765fd/werkzeug-3.1.8.tar.gz", hash = "sha256:9bad61a4268dac112f1c5cd4630a56ede601b6ed420300677a869083d70a4c44", size = 875852, upload-time = "2026-04-02T18:49:14.268Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a4/34/4dd12fc8bb7d61c91467ec3efe415ffa7d5456f799954b40c5bbaeae470e/werkzeug-3.1.9.tar.gz", hash = "sha256:55ca7c70a75689be937aa27f8ff4b018f06ff4838fc73045560bf0f5a1291060", size = 940188, upload-time = "2026-09-27T18:33:41.637Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl", hash = "sha256:63a77fb8892bf28ebc3178683445222aa500e48ebad5ec77b0ad80f8726b1f50", size = 226459, upload-time = "2026-04-02T18:49:12.72Z" }, + { url = "https://files.pythonhosted.org/packages/a1/38/df03f564f43cec2684823f3cccae1a652ee7face1cbaa76fb223096e64d7/werkzeug-3.1.9-py3-none-any.whl", hash = "sha256:6392e50c78460ba618e5b21f08a71f59c99ce99cdc6cf6e3dd7e6ccca8754fab", size = 228700, upload-time = "2026-09-27T18:33:39.685Z" }, ] [[package]] diff --git a/rust/README.md b/rust/README.md index 6d20ab8c6..750adcc3f 100644 --- a/rust/README.md +++ b/rust/README.md @@ -250,14 +250,26 @@ and client — plus SIWX. after the handler runs, so it needs a `fee_payer_signer` (the fee payer signs the settlement as the channel's zero-share payee, and doubles as receiver authorizer — the voucher signer — by default) and is gated with `paid_upto_get` -/ `paid_upto_post` rather than `paid_get` / `paid_post`. +/ `paid_upto_post` rather than `paid_get` / `paid_post`. The recipient's token +account for each offered currency must already exist: opens are refused until +it does, and settlement never creates it at the fee payer's expense. The `upto` gate reads the meter only once the response body is complete, so it buffers the whole body before answering: a streaming handler reaches the client in one piece at the end. Bodies over 16 MiB, or bodies that fail mid-stream, are not delivered; the request settles at what was metered so far and answers 502. If settlement is still being retried in the background when the body is ready, -the response is served without a `PAYMENT-RESPONSE` header. +the response is served without a `PAYMENT-RESPONSE` header. A request dropped +after its channel opened (a client disconnect, a timeout layer) still settles +what was metered. A settlement that lands within the program's open-slot +window (1,500 slots) leaves the channel account `Distributed`, holding the +fee payer's rent until a permissionless `reclaim`; the `upto` server does not +run one. When the payer's token account can no longer take its refund (closed +or frozen since the open), settlement only seals the channel: `distribute` +would send that refund to the protocol treasury. Run `distribute_sealed` +periodically; it finds those channels on chain and distributes each once the +account is usable again, or once `withdraw_delay` has passed since the open, +when the refund goes to the treasury and the seller is paid. `batch-settlement` is for high-throughput APIs: the client opens one channel and signs a cumulative voucher per request, which the gate (`paid_batch_get` / @@ -270,7 +282,11 @@ operator and caps its total channel escrow; the bundled server currently offers client-signed vouchers. When a payer force-closes a channel, `finalize_close` applies the server's latest voucher with `settle_and_seal` during the grace period rather than forfeiting it, then finalizes -permissionlessly once the grace period has run out. +permissionlessly once the grace period has run out. A channel whose payer refund +account cannot take its refund is sealed without its `distribute`; later +`finalize_close` passes distribute it once the account is usable, or once the +channel has been sealed for its grace period, when the refund goes to the +treasury. ## Client diff --git a/rust/crates/conformance/src/case.rs b/rust/crates/conformance/src/case.rs index 703aa1ee0..8f974a827 100644 --- a/rust/crates/conformance/src/case.rs +++ b/rust/crates/conformance/src/case.rs @@ -620,6 +620,27 @@ pub enum Expect { }, } +/// A verdict the pinned specs also allow beside a case's primary `expect`. +/// +/// The primary verdict is the Rust kit's (or the authored one); when the spec +/// text leaves the choice to the implementation (a sponsor's stricter local +/// policy, a check the spec does not order, a rule it states for another +/// instruction only), the vector lists the other conformant verdicts in +/// `expect.alsoConformant` and the judge passes a result that matches any of +/// them. Every use carries the reason, quoting the spec. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Alternative { + Accept, + Reject(RejectCode), +} + +/// The alternatives and the reason they are conformant. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct AlsoConformant { + pub verdicts: Vec, + pub reason: String, +} + /// Where the expected value comes from. #[derive(Debug, Clone, PartialEq, Eq)] pub enum Provenance { @@ -761,6 +782,35 @@ pub struct Case { pub input: Input, pub expect: Expect, pub provenance: Provenance, + /// Other verdicts the specs allow (`expect.alsoConformant`). + pub also_conformant: Option, +} + +impl Case { + /// Record verdicts the specs also allow beside the primary one, with the + /// reason (quote the spec). Panics on an empty list, a reason shorter + /// than a sentence, or an alternative equal to the primary verdict. + pub fn also_conformant(mut self, verdicts: &[Alternative], reason: &str) -> Self { + let primary = match &self.expect { + Expect::Reject { code, .. } => Alternative::Reject(*code), + Expect::Accept(_) | Expect::AcceptAuthored(_) => Alternative::Accept, + }; + assert!( + !verdicts.is_empty() && reason.trim().len() >= 24, + "{}: also_conformant needs verdicts and a reason", + self.id + ); + assert!( + !verdicts.contains(&primary), + "{}: an alternative repeats the primary verdict", + self.id + ); + self.also_conformant = Some(AlsoConformant { + verdicts: verdicts.to_vec(), + reason: reason.to_string(), + }); + self + } } /// Fluent constructor so registry entries stay readable. Every field without @@ -800,6 +850,7 @@ impl CaseBuilder { input, expect, provenance: Provenance::Generated, + also_conformant: None, }, } } @@ -819,6 +870,12 @@ impl CaseBuilder { self } + /// See [`Case::also_conformant`]. + pub fn also_conformant(mut self, verdicts: &[Alternative], reason: &str) -> Self { + self.case = self.case.also_conformant(verdicts, reason); + self + } + pub fn build(self) -> Case { self.case } diff --git a/rust/crates/conformance/src/cases/mod.rs b/rust/crates/conformance/src/cases/mod.rs index 1c3ce133c..6f1037b08 100644 --- a/rust/crates/conformance/src/cases/mod.rs +++ b/rust/crates/conformance/src/cases/mod.rs @@ -22,6 +22,15 @@ pub mod x402_policy; pub mod x402_tx_versions; pub mod x402_upto; +/// Why an accept is also conformant where pay-kit's sponsors refuse a +/// priority fee above 2,000 lamports (limit times price, RULINGS S6): the +/// x402 schemes bound each factor and leave a tighter total to the sponsor. +pub const SPONSOR_FEE_PRODUCT_POLICY: &str = "scheme_exact_svm.md §2.2.1 bounds the compute unit limit and the unit price separately (reference defaults 400,000 units and 5,000,000 micro-lamports per unit) and this transaction is within both; the 2,000 lamport cap on their product is pay-kit's stricter sponsor policy (§2.3: “Sponsors MAY introduce stricter limits but MUST NOT relax the §2.1 MUSTs.”), so a sponsor without it accepts (RULINGS S6)."; + +/// As [`SPONSOR_FEE_PRODUCT_POLICY`], for the payment-channel transactions an +/// upto or batch-settlement sponsor co-signs. +pub const CHANNEL_FEE_PRODUCT_POLICY: &str = "the upto and batch-settlement schemes cap the compute unit limit at 400,000 and the unit price at 5,000,000 micro-lamports (or a version-1 priorityFee at 5 lamports per unit) and this transaction is within them; the 2,000 lamport cap on the total fee is pay-kit's stricter local policy, which the schemes allow but do not require (upto: “A sponsor MAY apply a stricter local policy for compute-unit limit, compute-unit price, and required-signature count”; batch-settlement: “A sponsor MAY apply stricter local compute-unit, priority-fee, or required-signature caps”), so a sponsor without it accepts (RULINGS S6)."; + /// `registry! { name => case_expr; ... }`: one constructor fn per case, the /// module's `cases()`, and a positive-control `#[test]` per case that also /// asserts the fn name equals the case id (dashes as underscores). diff --git a/rust/crates/conformance/src/cases/session_server.rs b/rust/crates/conformance/src/cases/session_server.rs index f846a484e..b7754912c 100644 --- a/rust/crates/conformance/src/cases/session_server.rs +++ b/rust/crates/conformance/src/cases/session_server.rs @@ -562,6 +562,7 @@ fn build_recipe(server: Server) -> BuildRecipe { server, authorized: Authorized::SessionKey, edits: vec![], + client_blockhash: None, } } @@ -1757,6 +1758,17 @@ crate::registry! { build_edit(Edit::Remove("/methodDetails/recentBlockhash")), invalid_challenge(), ).build(); + session_build_foreign_blockhash_reject => build_case( + "session-build-foreign-blockhash-reject", + s("Method Details", "The server MUST obtain it from the selected network, and the client MUST use it as the transaction message's recent blockhash."), + &[R_BLOCKHASH_USE], + "The challenged recentBlockhash is not a live blockhash on the client's cluster (its RPC's latest is another), so it is not from the selected network: an open signed over it would be valid on another cluster. The client refuses before signing. Pair: session-build-open-client-paid.", + BuildRecipe { + client_blockhash: Some(crate::realize::session::OTHER_BLOCKHASH), + ..build_recipe(server()) + }, + invalid_challenge(), + ).build(); session_build_missing_recent_slot_reject => build_case( "session-build-missing-recent-slot-reject", s("Method Details", "Conditionally REQUIRED when channelId is absent and MUST be absent when resuming an existing channel."), diff --git a/rust/crates/conformance/src/cases/x402_batch.rs b/rust/crates/conformance/src/cases/x402_batch.rs index 991526798..6e01c8e4a 100644 --- a/rust/crates/conformance/src/cases/x402_batch.rs +++ b/rust/crates/conformance/src/cases/x402_batch.rs @@ -77,7 +77,9 @@ const NO_GRANT: &str = "X402-f882f2074a"; const OPT_IN: &str = "X402-84916fe051"; const TOKEN_PROGRAM_OWNER: &str = "X402-23747f44c3"; const TOKEN_PROGRAM_VERIFY: &str = "X402-1230bb35a3"; -const CLAIMS_ONE_TO_FOUR: &str = "X402-7f4ee54a73"; +const CLAIMS_CAPACITY: &str = "X402-76654742e7"; +const SETTLE_CAPACITY: &str = "X402-c2ca42b7a4"; +const SERVER_COPIES_CAPACITY: &str = "X402-8f57677e36"; const SEAL_CLOSE_AUTH: &str = "X402-45c411d301"; const COMMITMENT_ID: &str = "X402-5ebca343d1"; const STATIC_VALIDATE: &str = "X402-4ea8d1b0d9"; @@ -111,9 +113,9 @@ const TX_FACILITATOR_REJECTS: &str = "X402TX-5267172b18"; const TX_CLIENT_INTERSECT: &str = "X402TX-61c735c7a9"; const TX_CLIENT_EMPTY: &str = "X402TX-2909c4b4ec"; const TX_SIZE: &str = "X402TX-dc7b0f3305"; -const TX_V1_BUDGET: &str = "X402TX-644919eb3b"; -const TX_V1_CAPS: &str = "X402TX-0f874a9c63"; -const TX_V1_NO_CB: &str = "X402TX-936b492daa"; +const TX_V1_BUDGET: &str = "X402TX-f9bcc1a14a"; +const TX_V1_CAPS: &str = "X402TX-703c03cfb5"; +const TX_V1_NO_CB: &str = "X402TX-915632f040"; const TX_SERVER_COPIES: &str = "X402TX-f39a33ff74"; // ── spec references ── @@ -156,8 +158,12 @@ fn variants_spec() -> SpecRef { fn refund_voucher_spec() -> SpecRef { s("4.3 Client PaymentPayload Variants", "| `voucher` | `BatchVoucher` | REQUIRED in client mode. The server's accepted cumulative amount (`expiresAt` MUST be `0`).") } +fn settle_spec() -> SpecRef { + s("4.5 Facilitator Interface", "`channels[]` MUST contain at least one entry and at most `extra.maxSettleChannels` entries, or four when the facilitator advertises no `maxSettleChannels`.") +} + fn claims_spec() -> SpecRef { - s("4.5 Facilitator Interface", "`claims[]` MUST contain between one and four entries so the instruction pairs fit in a legacy Solana transaction without address lookup tables.") + s("4.5 Facilitator Interface", "`claims[]` MUST contain at least one entry and at most `extra.maxClaimChannels` entries, or four when the facilitator advertises no `maxClaimChannels`, so the instruction pairs fit in one transaction without address lookup tables.") } fn wire_spec() -> SpecRef { s( @@ -315,6 +321,15 @@ fn verify_input( input } +/// Mark a verify vector whose verdict rests on the resource server's own +/// record alone (`batchServerChannel`: the charged or accepted cumulative, +/// a close-pending mark), which a stateless facilitator never sees +/// (RULINGS B1): `batchVerdictFromStore: true`. +fn from_store(mut input: Value) -> Value { + input["batchVerdictFromStore"] = json!(true); + input +} + fn voucher_payload(config: &Value, voucher: Value) -> Value { json!({ "type": "voucher", "channelConfig": config, "voucher": voucher }) } @@ -456,6 +471,10 @@ fn policy_case( /// An `open` deposit: no stored record, no channel onchain yet. fn open_input(transaction: String) -> Value { + open_input_with(transaction, Atas::Healthy) +} + +fn open_input_with(transaction: String, atas: Atas) -> Value { let config = cfg(); let payload = json!({ "type": "deposit", @@ -468,7 +487,7 @@ fn open_input(transaction: String) -> Value { &requirements(), &payload, None, - fx::rpc_fixtures(None, Atas::Healthy, TOKEN_PROGRAM), + fx::rpc_fixtures(None, atas, TOKEN_PROGRAM), ) } @@ -843,6 +862,17 @@ fn v1_route() -> Route { } } +/// A facilitator configured to accept version 0 only, stated explicitly: +/// the scheme gives its own accepted set no default (“The facilitator +/// enforces its own accepted set; it does not read +/// `PaymentRequirements.extra.transactionVersions`.”). +fn v0_only_route() -> Route { + Route { + tx_versions: Some(vec![0]), + ..Route::default() + } +} + fn v1_top_up(config: solana_message::v1::TransactionConfig, prefix: Vec) -> String { let mut ixs = prefix; ixs.push(fx::top_up_ix(&cfg(), TOP_UP_AMOUNT_ADDED)); @@ -1084,35 +1114,53 @@ crate::registry! { rej(RejectCode::InvalidPayload), ).build(); batch_wire_redemption_claim_frozen => wire_case( - "batch-wire-redemption-claim-frozen", claims_spec(), &[CLAIMS_ONE_TO_FOUR], + "batch-wire-redemption-claim-frozen", claims_spec(), &[CLAIMS_CAPACITY], "claim payload with two entries, each channelId + full channelConfig + the latest BatchVoucher.", wire("redemption", json!({ "type": "claim", "claims": [claim_entry(&cfg(), 5_000), claim_entry(&with(with(cfg(), "salt", json!("43")), "openSlot", json!(341_000_050)), 7_000)] })), json_pin(), ).build(); batch_wire_redemption_claim_empty_reject => wire_case( - "batch-wire-redemption-claim-empty-reject", claims_spec(), &[CLAIMS_ONE_TO_FOUR], + "batch-wire-redemption-claim-empty-reject", claims_spec(), &[CLAIMS_CAPACITY], "claims: [] is below the one-entry minimum.", wire("redemption", json!({ "type": "claim", "claims": [] })), rej(RejectCode::InvalidPayload), ).authored(None).build(); - batch_wire_redemption_claim_five_entries_reject => wire_case( - "batch-wire-redemption-claim-five-entries-reject", claims_spec(), &[CLAIMS_ONE_TO_FOUR], - "Five claims exceed the four entries one legacy transaction can carry.", - wire("redemption", json!({ "type": "claim", "claims": (0..5).map(|i| claim_entry(&with(cfg(), "salt", json!((100 + i).to_string())), 1_000)).collect::>() })), + batch_wire_redemption_claim_eighteen_entries => wire_case( + "batch-wire-redemption-claim-eighteen-entries", claims_spec(), &[CLAIMS_CAPACITY], + "Eighteen claims, the version-1 capacity (extra.maxClaimChannels 18): the payload parses. More than four is no longer a wire error; a facilitator that builds version 0 rejects it against its own capacity.", + wire("redemption", json!({ "type": "claim", "claims": (0..18).map(|i| claim_entry(&with(cfg(), "salt", json!((100 + i).to_string())), 1_000)).collect::>() })), + json_pin(), + ).build(); + batch_wire_redemption_claim_nineteen_entries_reject => wire_case( + "batch-wire-redemption-claim-nineteen-entries-reject", claims_spec(), &[CLAIMS_CAPACITY], + "Nineteen claims exceed what fits one version-1 transaction, so no facilitator can advertise that capacity: the payload is malformed for every facilitator.", + wire("redemption", json!({ "type": "claim", "claims": (0..19).map(|i| claim_entry(&with(cfg(), "salt", json!((100 + i).to_string())), 1_000)).collect::>() })), rej(RejectCode::InvalidPayload), ).authored(None).build(); batch_wire_redemption_claim_entry_without_config_reject => wire_case( - "batch-wire-redemption-claim-entry-without-config-reject", s("4.5 Facilitator Interface", "| Claim | `claims[].channelConfig` | `ChannelConfig` | Full channel configuration. |"), &[CLAIMS_ONE_TO_FOUR], + "batch-wire-redemption-claim-entry-without-config-reject", s("4.5 Facilitator Interface", "| Claim | `claims[].channelConfig` | `ChannelConfig` | Full channel configuration. |"), &[CLAIMS_CAPACITY], "A claim entry without its channelConfig cannot be derived or validated.", wire("redemption", json!({ "type": "claim", "claims": [without(claim_entry(&cfg(), 5_000), "channelConfig")] })), rej(RejectCode::InvalidPayload), ).build(); batch_wire_redemption_settle_frozen => wire_case( - "batch-wire-redemption-settle-frozen", s("4.5 Facilitator Interface", "`channels[]` MUST contain between one and four entries, the same transaction-size bound as `claims[]`."), &[CLAIMS_ONE_TO_FOUR], + "batch-wire-redemption-settle-frozen", settle_spec(), &[SETTLE_CAPACITY], "settle payload: channels[] of {channelId, channelConfig}.", wire("redemption", json!({ "type": "settle", "channels": [{ "channelId": channel(&cfg()), "channelConfig": cfg() }] })), json_pin(), ).build(); + batch_wire_redemption_settle_thirteen_channels => wire_case( + "batch-wire-redemption-settle-thirteen-channels", settle_spec(), &[SETTLE_CAPACITY], + "Thirteen settle channels, the version-1 capacity (extra.maxSettleChannels 13): the payload parses.", + wire("redemption", json!({ "type": "settle", "channels": (0..13).map(|i| { let c = with(cfg(), "salt", json!((200 + i).to_string())); json!({ "channelId": channel(&c), "channelConfig": c }) }).collect::>() })), + json_pin(), + ).build(); + batch_wire_redemption_settle_fourteen_channels_reject => wire_case( + "batch-wire-redemption-settle-fourteen-channels-reject", settle_spec(), &[SETTLE_CAPACITY], + "Fourteen settle channels exceed the largest capacity a facilitator may advertise (13): the payload is malformed for every facilitator.", + wire("redemption", json!({ "type": "settle", "channels": (0..14).map(|i| { let c = with(cfg(), "salt", json!((200 + i).to_string())); json!({ "channelId": channel(&c), "channelConfig": c }) }).collect::>() })), + rej(RejectCode::InvalidPayload), + ).authored(None).build(); batch_wire_redemption_seal_frozen => wire_case( "batch-wire-redemption-seal-frozen", s("4.5 Facilitator Interface", "| Seal | `closeAuthorization` | `CloseAuthorization` | REQUIRED (section 3)."), &[SEAL_CLOSE_AUTH], "seal payload: the tag beside channelId, channelConfig, the latest voucher and closeAuthorization {validBefore, signature}.", @@ -1137,8 +1185,14 @@ crate::registry! { wire("requirements", v1_route().requirements()), json_pin(), ).build(); + batch_wire_requirements_redemption_capacity => wire_case( + "batch-wire-requirements-redemption-capacity", s("GET /supported", "The server MUST copy `feePayer`, `transactionVersions`, `maxClaimChannels`, `maxSettleChannels`, and `maxIdleSecs` into `PaymentRequirements.extra`"), &[SERVER_COPIES_CAPACITY], + "Requirements of a route whose facilitator builds redemptions as version 1 carry its capacity, extra.maxClaimChannels 18 and extra.maxSettleChannels 13, copied from /supported; the SDK's requirements type keeps both.", + wire("requirements", requirements_with(&[("transactionVersions", json!([0, 1])), ("maxClaimChannels", json!(18)), ("maxSettleChannels", json!(13))])), + json_pin(), + ).build(); batch_wire_requirements_unknown_transaction_version_reject => wire_case( - "batch-wire-requirements-unknown-transaction-version-reject", tx_versions_spec("Entries are the integers `0` and `1`, the Wallet Standard `supportedTransactionVersions` vocabulary."), &[TX_SERVER_COPIES], + "batch-wire-requirements-unknown-transaction-version-reject", tx_versions_spec("Entries MUST be the JSON integers `0` and `1` only."), &[TX_SERVER_COPIES], "extra.transactionVersions [0, 2]: 2 is not a transaction message version.", wire("requirements", requirements_with(&[("transactionVersions", json!([0, 2]))])), rej(RejectCode::InvalidPayload), @@ -1316,19 +1370,19 @@ crate::registry! { batch_verify_voucher_one_below_reject => voucher_case( "batch-verify-voucher-one-below-reject", cumulative_spec(), BugType::Settlement, "Charged 3000, amount 1000: a voucher at 3999 underpays by one unit.", - voucher_input(&cfg(), honest_voucher(3_999), 3_000, 10_000, ChannelAccount::default()), + from_store(voucher_input(&cfg(), honest_voucher(3_999), 3_000, 10_000, ChannelAccount::default())), rej(RejectCode::CumulativeAmountMismatch), ).requirements(&[EVERY_PAID_REQUEST]).build(); batch_verify_voucher_one_above_reject => voucher_case( "batch-verify-voucher-one-above-reject", cumulative_spec(), BugType::Settlement, "A voucher at 4001: in client mode each fresh voucher advances the cumulative by exactly the amount, not at least it (a stateless facilitator floor would accept it; the server rule is equality, RULINGS B1).", - voucher_input(&cfg(), honest_voucher(4_001), 3_000, 10_000, ChannelAccount::default()), + from_store(voucher_input(&cfg(), honest_voucher(4_001), 3_000, 10_000, ChannelAccount::default())), rej(RejectCode::CumulativeAmountMismatch), ).requirements(&[EVERY_PAID_REQUEST]).build(); batch_verify_voucher_stale_reject => voucher_case( "batch-verify-voucher-stale-reject", cumulative_spec(), BugType::Replay, "A voucher at the already-charged 3000 (no stored voucher with that signature): stale, not a fresh authorization.", - voucher_input(&cfg(), honest_voucher(3_000), 3_000, 10_000, ChannelAccount::default()), + from_store(voucher_input(&cfg(), honest_voucher(3_000), 3_000, 10_000, ChannelAccount::default())), rej(RejectCode::CumulativeAmountMismatch), ).requirements(&[EVERY_PAID_REQUEST]).build(); batch_verify_voucher_at_deposit => voucher_case( @@ -1382,7 +1436,7 @@ crate::registry! { batch_verify_voucher_close_pending_in_store_reject => voucher_case( "batch-verify-voucher-close-pending-in-store-reject", s("4.5 Facilitator Interface", "For this unilateral path, the server MUST mark the channel close-pending and reject further paid requests."), BugType::Settlement, "The server already marked the channel close-pending (a sponsored request_close confirmed): further paid requests are refused.", - { let mut i = voucher_input(&cfg(), honest_voucher(4_000), 3_000, 10_000, ChannelAccount::default()); i["batchServerChannel"]["closeRequestedAt"] = json!(1_785_000_000_u64); i }, + { let mut i = voucher_input(&cfg(), honest_voucher(4_000), 3_000, 10_000, ChannelAccount::default()); i["batchServerChannel"]["closeRequestedAt"] = json!(1_785_000_000_u64); from_store(i) }, rej(RejectCode::ChannelClosing), ).requirements(&[CLOSE_PENDING, CLOSING]).build(); batch_verify_voucher_onchain_closed_account_reject => voucher_case( @@ -1427,6 +1481,12 @@ crate::registry! { voucher_input(&with(cfg(), "receiver", json!(keys::X402_OTHER_PAY_TO)), honest_voucher(4_000), 3_000, 10_000, ChannelAccount::default()), rej(RejectCode::ChannelState), ).requirements(&[RECEIVER_IS_PAY_TO]).build(); + batch_verify_voucher_receiver_quotes_a_code_reject => voucher_case( + "batch-verify-voucher-receiver-quotes-a-code-reject", bindings_spec(), BugType::AuthBypass, + "channelConfig.receiver is the text invalid_batch_settlement_svm_cumulative_amount_mismatch rather than payTo. The failure is the receiver binding (channel-state), whatever code the client's own text names: a verifier that classifies its error by searching the message reports a cumulative mismatch, and answers it with the corrective 402 carrying the channel's latest voucher.", + voucher_input(&with(cfg(), "receiver", json!("invalid_batch_settlement_svm_cumulative_amount_mismatch")), honest_voucher(4_000), 3_000, 10_000, ChannelAccount::default()), + rej(RejectCode::ChannelState), + ).requirements(&[RECEIVER_IS_PAY_TO]).build(); batch_verify_voucher_token_not_asset_reject => voucher_case( "batch-verify-voucher-token-not-asset-reject", bindings_spec(), BugType::AuthBypass, "channelConfig.token is another mint than the asset (voucher signed for that config's PDA).", @@ -1450,13 +1510,23 @@ crate::registry! { "channelConfig omits receiverAuthorizer while the requirements advertise one: both MUST be present and equal.", voucher_input(&without(cfg(), "receiverAuthorizer"), honest_voucher(4_000), 3_000, 10_000, ChannelAccount::default()), rej(RejectCode::ReceiverAuthorizerMismatch), - ).requirements(&[RA_EQUAL, RA_BOTH_PRESENT]).build(); + ) + .also_conformant( + &[crate::case::Alternative::Reject(RejectCode::PayloadType)], + "channelConfig.receiverAuthorizer is a required field of the wire object (“| `receiverAuthorizer` | string | Required.”), so a verifier that validates the payload shape before comparing it with extra.receiverAuthorizer refuses it as invalid_batch_settlement_svm_payload_type; the spec does not order the two checks.", + ) + .requirements(&[RA_EQUAL, RA_BOTH_PRESENT]).build(); batch_verify_voucher_server_mode_config_reject => voucher_case( "batch-verify-voucher-server-mode-config-reject", s("4.2 Shared Wire Objects and Program Mapping", "Omitted or `\"client\"` selects client mode; `\"server\"` selects server mode and MUST equal `extra.voucherSigner`."), BugType::AuthBypass, "channelConfig.voucherSigner \"server\" on a client-mode route: the mode must equal extra.voucherSigner.", voucher_input(&with(cfg(), "voucherSigner", json!("server")), honest_voucher(4_000), 3_000, 10_000, ChannelAccount::default()), rej(RejectCode::ChannelState), - ).requirements(&["X402-22712c36e1"]).build(); + ) + .also_conformant( + &[crate::case::Alternative::Reject(RejectCode::PayloadType)], + "no reason code names a voucherSigner that differs from extra.voucherSigner; a server-mode channelConfig on a client-mode route is a payload the route's operation does not take (invalid_batch_settlement_svm_payload_type, “payload `type` is not valid for the current verify or settle operation”) as plausibly as a channel-state mismatch.", + ) + .requirements(&["X402-22712c36e1"]).build(); batch_verify_accepted_amount_mismatch_reject => voucher_case( "batch-verify-accepted-amount-mismatch-reject", accepted_spec(), BugType::Precedence, "accepted.amount \"500\" while the route charges 1000 (voucher otherwise valid at 4000).", @@ -1509,10 +1579,24 @@ crate::registry! { ); batch_verify_top_up_compute_budget_prefix => policy_case( "batch-verify-top-up-compute-budget-prefix", policy_spec("If both are present, the limit MUST precede the price."), &[LAYOUT, LIMIT_BEFORE_PRICE, CB_LIMIT, CB_PRICE], - "Paired accept: SetComputeUnitLimit 400000 then SetComputeUnitPrice 5000000 (both at the cap) before the top_up.", - top_up_tx(vec![fx::compute_ix(&fx::unit_limit(400_000)), fx::compute_ix(&fx::unit_price(5_000_000))], TOP_UP_AMOUNT_ADDED, memo()), + "Paired accept: SetComputeUnitLimit 400000 (at the cap) then SetComputeUnitPrice 5000 before the top_up, a 2000 lamport priority fee: exactly the sponsor's cap on the fee it pays (RULINGS S6).", + top_up_tx(vec![fx::compute_ix(&fx::unit_limit(400_000)), fx::compute_ix(&fx::unit_price(5_000))], TOP_UP_AMOUNT_ADDED, memo()), Expect::Accept(Pin::Outcome), ); + batch_verify_top_up_priority_fee_over_cap_reject => policy_case( + "batch-verify-top-up-priority-fee-over-cap-reject", policy_spec("A sponsor MAY apply stricter local compute-unit, priority-fee, or required-signature caps, but MUST NOT relax the absolute maxima above."), &[CB_LIMIT, CB_PRICE], + "SetComputeUnitLimit 400000 and SetComputeUnitPrice 5000000, each at its own cap: the sponsor would pay a 2000000 lamport priority fee, so it bounds the fee as limit times price (RULINGS S6). Pair: batch-verify-top-up-compute-budget-prefix.", + top_up_tx(vec![fx::compute_ix(&fx::unit_limit(400_000)), fx::compute_ix(&fx::unit_price(5_000_000))], TOP_UP_AMOUNT_ADDED, memo()), + rej(RejectCode::SetupTransaction), + ) + .also_conformant(&[crate::case::Alternative::Accept], super::CHANNEL_FEE_PRODUCT_POLICY); + batch_verify_top_up_implicit_limit_priority_fee_over_cap_reject => policy_case( + "batch-verify-top-up-implicit-limit-priority-fee-over-cap-reject", policy_spec("A sponsor MAY apply stricter local compute-unit, priority-fee, or required-signature caps, but MUST NOT relax the absolute maxima above."), &[CB_PRICE], + "SetComputeUnitPrice 5001 with no SetComputeUnitLimit: the runtime budgets 200000 units for each of the top_up and the memo, so the sponsor would pay 2001 lamports, one over its cap (RULINGS S6). A verifier that bounds only declared limits accepts it.", + top_up_tx(vec![fx::compute_ix(&fx::unit_price(5_001))], TOP_UP_AMOUNT_ADDED, memo()), + rej(RejectCode::SetupTransaction), + ) + .also_conformant(&[crate::case::Alternative::Accept], super::CHANNEL_FEE_PRODUCT_POLICY); batch_verify_top_up_three_lighthouse => policy_case( "batch-verify-top-up-three-lighthouse", policy_spec("and at most three Lighthouse instructions"), &[LAYOUT, ALLOWLIST], "Paired accept: the memo followed by three Lighthouse assertions in the suffix.", @@ -1520,7 +1604,7 @@ crate::registry! { Expect::Accept(Pin::Outcome), ); batch_verify_top_up_legacy_message => policy_case( - "batch-verify-top-up-legacy-message", policy_spec("The message MAY be legacy or version `0`, but it MUST NOT contain Address Lookup Table lookups."), &[STATIC_VALIDATE], + "batch-verify-top-up-legacy-message", policy_spec("The message version MUST be one advertised in `extra.transactionVersions` (0 when the field is absent; see [Transaction versions](#transaction-versions)), and the message MUST NOT contain Address Lookup Table lookups."), &[STATIC_VALIDATE], "The canonical top_up compiled as a legacy (unversioned) message: accepted and policed like version 0.", fx::sponsored_legacy(vec![fx::top_up_ix(&cfg(), TOP_UP_AMOUNT_ADDED), fx::memo_ix(fx::MEMO)]), Expect::Accept(Pin::Outcome), @@ -1605,7 +1689,7 @@ crate::registry! { rej(RejectCode::SetupTransaction), ); batch_verify_top_up_duplicate_limit_reject => policy_case( - "batch-verify-top-up-duplicate-limit-reject", policy_spec("An optional Compute Budget prefix containing at most one `SetComputeUnitLimit` instruction"), &[LAYOUT], + "batch-verify-top-up-duplicate-limit-reject", policy_spec("In a legacy or version-0 transaction, an optional Compute Budget prefix containing at most one `SetComputeUnitLimit` instruction"), &[LAYOUT], "Two SetComputeUnitLimit instructions.", top_up_tx(vec![fx::compute_ix(&fx::unit_limit(200_000)), fx::compute_ix(&fx::unit_limit(200_000))], TOP_UP_AMOUNT_ADDED, memo()), rej(RejectCode::SetupTransaction), @@ -1647,10 +1731,14 @@ crate::registry! { rej(RejectCode::SetupTransaction), ); batch_verify_top_up_trailing_bytes_reject => policy_case( - "batch-verify-top-up-trailing-bytes-reject", s("Canonical open", "The facilitator MUST fully decode the instruction data, reject truncated data or trailing bytes"), &[FULL_DECODE], - "top_up data with one trailing byte (10 bytes instead of 9).", + "batch-verify-top-up-trailing-bytes-reject", top_up_spec(), &[TOP_UP_AMOUNT], + "top_up data with one trailing byte (10 bytes instead of 9). The Rust sponsor decodes the top_up as strictly as the open and refuses it; the spec states the trailing-bytes rule for the open only.", fx::sponsored(vec![{ let mut ix = fx::top_up_ix(&cfg(), TOP_UP_AMOUNT_ADDED); ix.data.push(0); ix }, fx::memo_ix(fx::MEMO)]), rej(RejectCode::SetupTransaction), + ) + .also_conformant( + &[crate::case::Alternative::Accept], + "“The facilitator MUST fully decode the instruction data, reject truncated data or trailing bytes” is stated under Canonical open only; Canonical top_up requires that “The facilitator MUST confirm the decoded amount equals `payload.deposit.amount`”, which a decoder that ignores the extra byte also confirms.", ); batch_verify_top_up_fee_payer_as_account_reject => policy_case( "batch-verify-top-up-fee-payer-as-account-reject", s("Canonical top_up", "In this form `extra.feePayer` authorizes only the bounded transaction fee and MUST NOT be an instruction account, authority, source, or delegate."), &[TOP_UP_FEE_PAYER, "X402-9ca40ae469"], @@ -1679,6 +1767,13 @@ crate::registry! { top_up_input_with(&route(), top_up_tx(vec![], TOP_UP_AMOUNT_ADDED, memo()), "6000", 4_000, Atas::FrozenPayer, TOKEN_PROGRAM), rej(RejectCode::SettlementSimulation), ).requirements(&[SETTLEMENT_ACCOUNTS, "X402-fbdea947ae"]).authored(None).build(); + batch_verify_top_up_unfunded_payer_reject => case( + "batch-verify-top-up-unfunded-payer-reject", "batch-verify-setup-policy.json", Mode::VerifyTransaction, Role::Server, BugType::Settlement, + s("Canonical top_up", "It MUST confirm the payer has sufficient tokens."), + "The accept top-up, but the payer's token account holds 1 base unit against the 6000 top-up. The deposit is broadcast only after the handler runs, so a verifier that skips the balance serves the request and only then finds the deposit cannot land.", + top_up_input_with(&route(), top_up_tx(vec![], TOP_UP_AMOUNT_ADDED, memo()), "6000", 4_000, Atas::UnfundedPayer, TOKEN_PROGRAM), + rej(RejectCode::SettlementSimulation), + ).requirements(&["X402-014270dc81"]).build(); // ── server verify: open ── batch_verify_open_accept => open_case( @@ -1687,6 +1782,13 @@ crate::registry! { open_tx(honest_open(), open_suffix()), Expect::AcceptAuthored(json!({})), ).authored(None).build(); + batch_verify_open_unfunded_payer_reject => case( + "batch-verify-open-unfunded-payer-reject", "batch-verify-open.json", Mode::VerifyTransaction, Role::Server, BugType::Settlement, + s("Canonical open", "It MUST confirm the payer has sufficient tokens for the deposit and the sponsor has sufficient SOL for the transaction fee plus the channel PDA and escrow ATA rent."), + "The accept open, but the payer's token account holds 1 base unit against the 10000 deposit. The deposit is broadcast only after the handler runs, so a verifier that skips the balance serves the request and only then finds the open cannot land. Pair: batch-verify-open-accept.", + open_input_with(open_tx(honest_open(), open_suffix()), Atas::UnfundedPayer), + rej(RejectCode::SettlementSimulation), + ).requirements(&["X402-0ff4cabcb4"]).build(); batch_verify_open_missing_binding_memo_reject => open_case( "batch-verify-open-missing-binding-memo-reject", s("Top-level instruction layout", "An `open` suffix also carries exactly one binding Memo from section 3."), &[MEMO_EXACT, BINDING_KEY], "The open carries only the seller memo: without the binding memo the channel is bound to no receiver authorizer.", @@ -1763,7 +1865,7 @@ crate::registry! { "batch-verify-refund-voucher-not-accepted-cumulative-reject", "batch-verify-refund.json", Mode::VerifyTransaction, Role::Server, BugType::Settlement, s("4.5 Facilitator Interface", "In client mode it MUST reject a voucher whose `maxClaimableAmount` differs from its accepted cumulative amount."), "The refund's voucher is at 2000 while the server accepted 3000: a payer cannot close at an older watermark.", - refund_input_with(refund_payload(Some(honest_voucher(2_000)), Some(request_close(memo()))), ChannelAccount::default()), + from_store(refund_input_with(refund_payload(Some(honest_voucher(2_000)), Some(request_close(memo()))), ChannelAccount::default())), rej(RejectCode::CloseState), ).requirements(&[REFUND_CUMULATIVE]).authored(None).build(); batch_verify_refund_with_amount_reject => case( @@ -1837,15 +1939,15 @@ crate::registry! { // ── transaction versions (x402-txv1) ── batch_txv1_top_up_v1_advertised => txv1_case( - "batch-txv1-top-up-v1-advertised", tx_versions_spec("A version-1 transaction carries its compute budget in the message `TransactionConfig`."), &[TX_ADVERTISED, TX_DEPOSIT_VERSION, TX_V1_BUDGET], + "batch-txv1-top-up-v1-advertised", tx_versions_spec("A version-1 transaction carries its compute budget in the message's `TransactionConfigMask` and the config values that follow it"), &[TX_ADVERTISED, TX_DEPOSIT_VERSION, TX_V1_BUDGET], "The route advertises transactionVersions [0, 1]: a version-1 top_up with computeUnitLimit, loadedAccountsDataSizeLimit and a priorityFee within the cap in its header, no ComputeBudget instruction, is accepted.", v1_input(&v1_route(), v1_top_up(fx::v1_budget(), vec![])), Expect::Accept(Pin::Outcome), ).build(); batch_txv1_top_up_v1_not_advertised_reject => txv1_case( "batch-txv1-top-up-v1-not-advertised-reject", tx_versions_spec("The facilitator MUST reject a message whose version is outside the set it accepts, before inspecting any instruction, with `unsupported_transaction_version`."), &[TX_FACILITATOR_REJECTS, TX_ADVERTISED], - "The same version-1 top_up on a route that accepts only version 0 (no transactionVersions advertised).", - v1_input(&route(), v1_top_up(fx::v1_budget(), vec![])), + "The same version-1 top_up to a facilitator configured to accept only version 0 (batchServer.transactionVersions [0]).", + v1_input(&v0_only_route(), v1_top_up(fx::v1_budget(), vec![])), rej(RejectCode::UnsupportedVersion), ).authored(None).build(); batch_txv1_top_up_v0_on_v1_route => txv1_case( @@ -1855,47 +1957,55 @@ crate::registry! { Expect::Accept(Pin::Outcome), ).build(); batch_txv1_top_up_v1_compute_budget_instruction_reject => txv1_case( - "batch-txv1-top-up-v1-compute-budget-instruction-reject", t("Top-level instruction layout", "A version-1 transaction that contains a Compute Budget instruction MUST be rejected."), &[TX_V1_NO_CB], + "batch-txv1-top-up-v1-compute-budget-instruction-reject", t("Top-level instruction layout", "A version-1 transaction that contains a Compute Budget instruction MUST be rejected (an x402 sponsor rule; the runtime treats such instructions as no-ops)."), &[TX_V1_NO_CB], "A version-1 top_up that also carries a SetComputeUnitLimit instruction.", v1_input(&v1_route(), v1_top_up(fx::v1_budget(), vec![fx::compute_ix(&fx::unit_limit(200_000))])), rej(RejectCode::SetupTransaction), ).build(); batch_txv1_top_up_v1_missing_unit_limit_reject => txv1_case( - "batch-txv1-top-up-v1-missing-unit-limit-reject", t("Top-level instruction layout", "`computeUnitLimit` MUST be present and MUST NOT exceed `400000`"), &[TX_V1_CAPS, TX_V1_BUDGET], + "batch-txv1-top-up-v1-missing-unit-limit-reject", t("Top-level instruction layout", "`computeUnitLimit` (bit 2) MUST be set and MUST NOT exceed `400000`"), &[TX_V1_CAPS, TX_V1_BUDGET], "A version-1 top_up whose header config omits computeUnitLimit (it would be budgeted zero).", v1_input(&v1_route(), v1_top_up(solana_message::v1::TransactionConfig::empty().with_loaded_accounts_data_size_limit(64 * 1024 * 1024), vec![])), rej(RejectCode::SetupTransaction), ).build(); batch_txv1_top_up_v1_missing_loaded_limit_reject => txv1_case( - "batch-txv1-top-up-v1-missing-loaded-limit-reject", t("Top-level instruction layout", "`loadedAccountsDataSizeLimit` MUST be present"), &[TX_V1_CAPS, TX_V1_BUDGET], + "batch-txv1-top-up-v1-missing-loaded-limit-reject", t("Top-level instruction layout", "`loadedAccountsDataSizeLimit` (bit 3) MUST be set"), &[TX_V1_CAPS, TX_V1_BUDGET], "A version-1 top_up whose header config omits loadedAccountsDataSizeLimit.", v1_input(&v1_route(), v1_top_up(solana_message::v1::TransactionConfig::empty().with_compute_unit_limit(200_000), vec![])), rej(RejectCode::SetupTransaction), ).build(); batch_txv1_top_up_v1_loaded_limit_below_max => txv1_case( - "batch-txv1-top-up-v1-loaded-limit-below-max", t("Top-level instruction layout", "`loadedAccountsDataSizeLimit` MUST be present"), &[TX_V1_CAPS, TX_V1_BUDGET], + "batch-txv1-top-up-v1-loaded-limit-below-max", t("Top-level instruction layout", "`loadedAccountsDataSizeLimit` (bit 3) MUST be set"), &[TX_V1_CAPS, TX_V1_BUDGET], "A version-1 top_up whose header sets loadedAccountsDataSizeLimit 32 MiB (present, below the runtime maximum): the spec requires the field, not a particular value, and a sponsor may only tighten caps it names.", v1_input(&v1_route(), v1_top_up(fx::v1_budget().with_loaded_accounts_data_size_limit(32 * 1024 * 1024), vec![])), Expect::AcceptAuthored(json!({})), ).authored(None).build(); batch_txv1_top_up_v1_unit_limit_over_cap_reject => txv1_case( - "batch-txv1-top-up-v1-unit-limit-over-cap-reject", t("Top-level instruction layout", "`computeUnitLimit` MUST be present and MUST NOT exceed `400000`"), &[TX_V1_CAPS], + "batch-txv1-top-up-v1-unit-limit-over-cap-reject", t("Top-level instruction layout", "`computeUnitLimit` (bit 2) MUST be set and MUST NOT exceed `400000`"), &[TX_V1_CAPS], "Header computeUnitLimit 400001.", v1_input(&v1_route(), v1_top_up(fx::v1_budget().with_compute_unit_limit(400_001), vec![])), rej(RejectCode::SetupTransaction), ).build(); batch_txv1_top_up_v1_priority_fee_over_cap_reject => txv1_case( "batch-txv1-top-up-v1-priority-fee-over-cap-reject", t("Top-level instruction layout", "`priorityFee * 1000000 <= 5000000 * computeUnitLimit`"), &[TX_V1_CAPS], - "priorityFee 1000001 lamports at computeUnitLimit 200000: 1000001 × 10^6 > 5000000 × 200000 (one lamport over the cap).", - v1_input(&v1_route(), v1_top_up(fx::v1_budget().with_priority_fee(1_000_001), vec![])), + "priorityFee 1501 lamports at computeUnitLimit 300: 1501 × 10^6 > 5000000 × 300 (one lamport over the cap), and still under the sponsor's 2000 lamport cap on the total fee, so only the per-unit rule rejects it.", + v1_input(&v1_route(), v1_top_up(fx::v1_budget().with_compute_unit_limit(300).with_priority_fee(1_501), vec![])), rej(RejectCode::SetupTransaction), ).build(); batch_txv1_top_up_v1_priority_fee_at_cap => txv1_case( "batch-txv1-top-up-v1-priority-fee-at-cap", t("Top-level instruction layout", "`priorityFee * 1000000 <= 5000000 * computeUnitLimit`"), &[TX_V1_CAPS], - "Paired accept: priorityFee 1000000 lamports at computeUnitLimit 200000 is exactly the cap.", - v1_input(&v1_route(), v1_top_up(fx::v1_budget().with_priority_fee(1_000_000), vec![])), + "Paired accept: priorityFee 1500 lamports at computeUnitLimit 300 is exactly the per-unit cap, and under the sponsor's 2000 lamport cap on the total fee (RULINGS S6).", + v1_input(&v1_route(), v1_top_up(fx::v1_budget().with_compute_unit_limit(300).with_priority_fee(1_500), vec![])), Expect::Accept(Pin::Outcome), ).build(); + batch_txv1_top_up_v1_priority_fee_over_sponsor_cap_reject => txv1_case( + "batch-txv1-top-up-v1-priority-fee-over-sponsor-cap-reject", t("Top-level instruction layout", "`priorityFee * 1000000 <= 5000000 * computeUnitLimit`"), &[TX_V1_CAPS], + "priorityFee 2001 lamports at computeUnitLimit 200000: far under the per-unit cap, but one lamport over the cap the sponsor puts on the total fee it pays (RULINGS S6).", + v1_input(&v1_route(), v1_top_up(fx::v1_budget().with_priority_fee(2_001), vec![])), + rej(RejectCode::SetupTransaction), + ) + .also_conformant(&[crate::case::Alternative::Accept], super::CHANNEL_FEE_PRODUCT_POLICY) + .build(); batch_txv1_top_up_v0_over_1232_bytes_reject => txv1_case( "batch-txv1-top-up-v0-over-1232-bytes-reject", tx_versions_spec("A legacy or version-0 transaction MUST NOT exceed 1232 serialized bytes; a version-1 transaction MUST NOT exceed 4096 serialized bytes."), &[TX_SIZE], "A version-0 top_up whose three 330-byte Lighthouse assertions push it past 1232 serialized bytes.", @@ -1916,8 +2026,12 @@ crate::registry! { ).build(); batch_txv1_refund_v1_not_advertised_reject => txv1_case( "batch-txv1-refund-v1-not-advertised-reject", t("4.3 Client PaymentPayload Variants", "Its message version MUST be one advertised in `extra.transactionVersions`."), &[TX_REFUND_VERSION, TX_FACILITATOR_REJECTS], - "A client-mode refund whose request_close is version 1 on a route that accepts only version 0.", - refund_input_with(refund_payload(Some(honest_voucher(3_000)), Some(fx::sponsored_v1(vec![fx::request_close_ix(&cfg()), fx::memo_ix(fx::MEMO)], fx::v1_budget()))), ChannelAccount::default()), + "A client-mode refund whose request_close is version 1, to a facilitator configured to accept only version 0 (batchServer.transactionVersions [0]).", + { + let mut input = refund_input_with(refund_payload(Some(honest_voucher(3_000)), Some(fx::sponsored_v1(vec![fx::request_close_ix(&cfg()), fx::memo_ix(fx::MEMO)], fx::v1_budget()))), ChannelAccount::default()); + input["batchServer"] = v0_only_route().server_json(); + input + }, rej(RejectCode::UnsupportedVersion), ).authored(None).build(); } diff --git a/rust/crates/conformance/src/cases/x402_exact.rs b/rust/crates/conformance/src/cases/x402_exact.rs index 3d36ca48d..140190eb7 100644 --- a/rust/crates/conformance/src/cases/x402_exact.rs +++ b/rust/crates/conformance/src/cases/x402_exact.rs @@ -549,6 +549,10 @@ crate::registry! { X402HeaderSpec { mutation: Some(Mutation::OverPay { transfer: 0, delta: 1 }), ..header(devnet_route()) }, Expect::Accept(Pin::Envelope(vec!["x402Version", "hasAccepted", "payloadHasTransaction"])), ) + .also_conformant( + &[crate::case::Alternative::Reject(RejectCode::AmountMismatch)], + "§1.4 tolerates overpayment, but §3.1 also reads “Fee payer isolation, destination ATA derivation, and exact amount match are enforced on both layouts” and §2.3 lets a sponsor's policy refuse a scheme-valid transaction (“A transaction MAY be valid under the `exact` scheme while being rejected by a sponsor's policy.”), so a sponsor that requires the exact amount is conformant too (RULINGS S5).", + ) .build(); x402_exact_verify_accepted_amount_lie_reject => verify_case( "x402-exact-verify-accepted-amount-lie-reject", diff --git a/rust/crates/conformance/src/cases/x402_policy.rs b/rust/crates/conformance/src/cases/x402_policy.rs index a616af580..fe64ba000 100644 --- a/rust/crates/conformance/src/cases/x402_policy.rs +++ b/rust/crates/conformance/src/cases/x402_policy.rs @@ -17,7 +17,7 @@ use crate::mutate::Mutation; const VERIFY: &str = "x402-verify-policy.json"; const BUILD: &str = "x402-build-policy.json"; -const STATIC_LAYOUT: &str = "X402-a8bd75d71b"; +const STATIC_LAYOUT: &str = "X402-05c2aacafc"; const LIGHTHOUSE_ALLOWED: &str = "X402-a1cf65b0f0"; const FUND_SAFETY: &str = "X402-985ecc1ea3"; const SIGNATURE_ONLY_FOR_FEES: &str = "X402-0ad718daab"; @@ -90,7 +90,7 @@ crate::registry! { x402_exact_verify_unknown_program_reject => reject_case( "x402-exact-verify-unknown-program-reject", BugType::Settlement, - layout_spec("The decompiled transaction MUST contain 3 to 7 instructions in this order:"), + layout_spec("For a single-payee charge (no extra.splits and no ATA creation), a legacy or version-0 transaction MUST contain 3 to 7 instructions in this order:"), &[STATIC_LAYOUT], "An instruction of a program that is neither Lighthouse nor Memo (the Stake program) in an optional position of the static layout.", mutated(devnet_route(), Mutation::AddProgramInstruction { program: STAKE_PROGRAM, data: &[0] }), @@ -98,7 +98,7 @@ crate::registry! { x402_exact_verify_compute_heap_frame_reject => reject_case( "x402-exact-verify-compute-heap-frame-reject", BugType::Settlement, - layout_spec("The decompiled transaction MUST contain 3 to 7 instructions in this order:"), + layout_spec("For a single-payee charge (no extra.splits and no ATA creation), a legacy or version-0 transaction MUST contain 3 to 7 instructions in this order:"), &[STATIC_LAYOUT], "Position 1 must be SetComputeUnitLimit (ComputeBudget discriminator 2); here it is RequestHeapFrame (discriminator 1). Only unit limit and unit price are accepted compute budget instructions.", mutated(devnet_route(), Mutation::SetComputeBudgetData { index: 0, data: REQUEST_HEAP_FRAME }), @@ -106,7 +106,7 @@ crate::registry! { x402_exact_verify_extra_compute_budget_reject => reject_case( "x402-exact-verify-extra-compute-budget-reject", BugType::Settlement, - layout_spec("The decompiled transaction MUST contain 3 to 7 instructions in this order:"), + layout_spec("For a single-payee charge (no extra.splits and no ATA creation), a legacy or version-0 transaction MUST contain 3 to 7 instructions in this order:"), &[STATIC_LAYOUT], "A third ComputeBudget instruction (RequestHeapFrame) ahead of the unit limit and price, so the transfer is no longer at position 3.", mutated(devnet_route(), Mutation::AddComputeBudget { data: REQUEST_HEAP_FRAME }), @@ -142,7 +142,8 @@ crate::registry! { &[SPONSORSHIP_ABUSE], "The static layout's 200,000 compute unit limit paired with a 5,000,000 micro-lamport unit price: each is within its own cap, but the sponsor would pay a 1,000,000 lamport priority fee. The sponsor bounds the fee it pays as limit times price (RULINGS S6). Differs from x402-exact-v2-verify-accept only in the price.", mutated(devnet_route(), Mutation::SetComputeUnitPrice { micro_lamports: 5_000_000 }), - ); + ) + .also_conformant(&[crate::case::Alternative::Accept], super::SPONSOR_FEE_PRODUCT_POLICY); // RULINGS SIG1: the client's signature verifies over this message // before the sponsor claims, co-signs or sends it. x402_exact_verify_forged_client_signature_reject => reject_case( diff --git a/rust/crates/conformance/src/cases/x402_tx_versions.rs b/rust/crates/conformance/src/cases/x402_tx_versions.rs index 95e5e22b5..419b347f1 100644 --- a/rust/crates/conformance/src/cases/x402_tx_versions.rs +++ b/rust/crates/conformance/src/cases/x402_tx_versions.rs @@ -30,16 +30,19 @@ const INTERSECT_HIGHEST: &str = "X402TX-61c735c7a9"; const EMPTY_FAILS: &str = "X402TX-2909c4b4ec"; const SPONSOR_SET: &str = "X402TX-24efe57db3"; const SIZE_LIMITS: &str = "X402TX-dc7b0f3305"; -const V1_BUDGET: &str = "X402TX-644919eb3b"; -const V1_CAPS: &str = "X402TX-eb681e1701"; -const V1_NO_BUDGET_IX: &str = "X402TX-936b492daa"; -const V1_LAYOUT: &str = "X402TX-d188782061"; -const FAST_PATH_PRICE: &str = "X402TX-2ad7a3f326"; +const V1_BUDGET: &str = "X402TX-f9bcc1a14a"; +const V1_CAPS: &str = "X402TX-997feeb51d"; +const V1_NO_BUDGET_IX: &str = "X402TX-915632f040"; +const V1_CLIENT_NO_BUDGET_IX: &str = "X402TX-4cd70365fd"; +const V1_FEE_PRECISION: &str = "X402TX-74fb884aa9"; +const V1_LAYOUT: &str = "X402TX-4c2fd60e66"; +const FAST_PATH_PRICE: &str = "X402TX-655bb4a79a"; const EXACTLY_ONE: &str = "X402TX-ee90546220"; const NOT_LESS: &str = "X402TX-516a2d7b57"; const FEE_PAYER_ISOLATION: &str = "X402TX-dd5384e0fe"; const SELF_SPEND: &str = "X402TX-bc031b7add"; const TRANSFER_MATCH: &str = "X402TX-f9c2b66234"; +const INVALID_ENTRY: &str = "X402TX-927d17b62e"; const BOTH: &[u8] = &[0, 1]; @@ -87,7 +90,7 @@ fn caps_spec() -> SpecRef { spec( SVM, "2.2.1 Compute Budget Controls (SHOULD)", - "In a version-1 transaction the same caps apply to the message TransactionConfig instead: computeUnitLimit MUST be present and MUST NOT exceed the configured maximum, loadedAccountsDataSizeLimit MUST be present, and priorityFee (total lamports) MUST satisfy priorityFee 1000000 <= maxPriorityFeeMicroLamports computeUnitLimit.", + "In a version-1 transaction the same caps apply to the message config values instead (§1.5): computeUnitLimit (bit 2) MUST be set and MUST NOT exceed the configured maximum, loadedAccountsDataSizeLimit (bit 3) MUST be set, and priorityFee (bits 0 and 1, total lamports) MUST satisfy", ) } @@ -95,7 +98,7 @@ fn layout_spec() -> SpecRef { spec( SVM, "3.1 Path 1 — Static Layout Verification (standard wallets)", - "A version-1 transaction MUST contain 1 to 5 instructions in this order:", + "For a single-payee charge, a version-1 transaction MUST contain 1 to 5 instructions in this order:", ) } @@ -294,6 +297,26 @@ crate::registry! { ) .authored(None) .build(); + x402_build_unknown_entry_reject => build( + "x402-build-unknown-entry-reject", + spec(SVM, "1.5 Transaction Versions (MUST)", "A client or server MUST treat a field containing any non-integer entry (a string, null, or \"legacy\") or any integer other than 0 or 1 as invalid and fail closed with unsupported_transaction_version."), + &[INVALID_ENTRY], + "extra.transactionVersions [2, 1, 0]: version 2 is not a defined entry, so the whole field is invalid and the client fails with unsupported_transaction_version instead of building version 1 from the entries it knows.", + build_with(v1_offer(json!([2, 1, 0])), json!({})), + reject(RejectCode::UnsupportedVersion, "unsupported_transaction_version: invalid entry 2"), + ) + .authored(None) + .build(); + x402_build_string_entry_reject => build( + "x402-build-string-entry-reject", + spec(SVM, "1.5 Transaction Versions (MUST)", "A client or server MUST treat a field containing any non-integer entry (a string, null, or \"legacy\") or any integer other than 0 or 1 as invalid and fail closed with unsupported_transaction_version."), + &[INVALID_ENTRY], + "extra.transactionVersions [\"1\", 0]: a stringified version is not a valid entry, so the client fails with unsupported_transaction_version rather than reading it as 1 or skipping it.", + build_with(v1_offer(json!(["1", 0])), json!({})), + reject(RejectCode::UnsupportedVersion, "unsupported_transaction_version: string entry"), + ) + .authored(None) + .build(); x402_build_legacy_only_reject => build( "x402-build-legacy-only-reject", spec(SVM, "1.5 Transaction Versions (MUST)", "They are never advertised in extra.transactionVersions and clients MUST NOT build them."), @@ -320,8 +343,8 @@ crate::registry! { BugType::AuthBypass, sponsor_spec(), &[SPONSOR_SET, PAYLOAD_VERSION], - "A sponsor with the default accepted set [0] receives the same valid version-1 transaction: rejected with unsupported_transaction_version before any instruction is inspected. Pair: x402-verify-v1-accept.", - layout(MessageFormat::V1, None, None), + "A sponsor whose accepted set is [0] receives the same valid version-1 transaction: rejected with unsupported_transaction_version before any instruction is inspected. The set is stated explicitly (input.x402ServerTransactionVersions): §1.5 gives the sponsor's own set no default. Pair: x402-verify-v1-accept.", + layout(MessageFormat::V1, Some(&[0]), None), reject(RejectCode::UnsupportedVersion, "unsupported_transaction_version"), ).build(); x402_verify_v1_explicit_v0_sponsor_reject => verify( @@ -378,8 +401,8 @@ crate::registry! { x402_verify_v1_compute_budget_instruction_reject => verify( "x402-verify-v1-compute-budget-instruction-reject", BugType::Settlement, - spec(SVM, "2.2.1 Compute Budget Controls (SHOULD)", "A version-1 transaction that contains a Compute Budget instruction MUST be rejected."), - &[V1_NO_BUDGET_IX, V1_BUDGET], + spec(SVM, "2.2.1 Compute Budget Controls (SHOULD)", "A version-1 transaction that contains a Compute Budget instruction MUST be rejected (an x402 sponsor rule; the runtime treats such instructions as no-ops)."), + &[V1_NO_BUDGET_IX, V1_CLIENT_NO_BUDGET_IX, V1_BUDGET], "Version-1 static layout preceded by a SetComputeUnitLimit instruction: the runtime ignores it under version 1, so a sponsor bounding it bounds nothing. Pair: x402-verify-v1-accept.", layout(MessageFormat::V1, Some(BOTH), Some(Mutation::AddComputeBudget { data: LIMIT_IX })), from_table(&Mutation::AddComputeBudget { data: LIMIT_IX }), @@ -404,13 +427,40 @@ crate::registry! { ) .authored(None) .build(); + x402_verify_v1_loaded_data_limit_4mib_accept => verify( + "x402-verify-v1-loaded-data-limit-4mib-accept", + BugType::Settlement, + caps_spec(), + &[V1_CAPS, V1_BUDGET], + "Version-1 header loadedAccountsDataSizeLimit 4194304 (4 MiB), what the TypeScript, Go and Python x402 clients request: the spec requires the limit to be set, not to be the runtime maximum, so a sponsor that demands 64 MiB refuses every reference client. Pair: x402-verify-v1-missing-loaded-data-limit-reject.", + layout(MessageFormat::V1, Some(BOTH), Some(Mutation::V1LoadedAccountsDataSizeLimit { bytes: 4 * 1024 * 1024 })), + Expect::Accept(Pin::Outcome), + ).build(); + x402_verify_v1_loaded_data_limit_small_accept => verify( + "x402-verify-v1-loaded-data-limit-small-accept", + BugType::Settlement, + caps_spec(), + &[V1_CAPS], + "Version-1 header loadedAccountsDataSizeLimit 32768 (32 KiB), set but small: accepted at verification. A budget too small to load the payment's programs fails at simulation, which this offline vector does not run.", + layout(MessageFormat::V1, Some(BOTH), Some(Mutation::V1LoadedAccountsDataSizeLimit { bytes: 32 * 1024 })), + Expect::Accept(Pin::Outcome), + ).build(); + x402_verify_v1_heap_size_reject => verify( + "x402-verify-v1-heap-size-reject", + BugType::Settlement, + spec(SVM, "2.2.1 Compute Budget Controls (SHOULD)", "Only SetComputeUnitLimit (discriminator 2) and SetComputeUnitPrice (discriminator 3) SHOULD be accepted; other ComputeBudget instruction types expand execution surface without being necessary for payment verification and SHOULD be rejected."), + &[V1_CAPS], + "Version-1 header requesting a 64 KiB heap (TransactionConfigMask bit 4), the header form of RequestHeapFrame that a sponsor refuses on version 0 (x402-exact-verify-compute-heap-frame-reject). Pair: x402-verify-v1-accept.", + layout(MessageFormat::V1, Some(BOTH), Some(Mutation::V1HeapSize { bytes: 64 * 1024 })), + from_table(&Mutation::V1HeapSize { bytes: 64 * 1024 }), + ).build(); x402_verify_v1_compute_limit_at_cap_accept => verify( "x402-verify-v1-compute-limit-at-cap-accept", BugType::Settlement, caps_spec(), &[V1_CAPS], - "Version-1 header computeUnitLimit at the configured maximum (200000): accepted (the base layout already sits at the cap; this pins it explicitly next to its over-cap pair).", - layout(MessageFormat::V1, Some(BOTH), Some(Mutation::V1ComputeUnitLimit { limit: 200_000 })), + "Version-1 header computeUnitLimit at the reference default maximum (400000, scheme_exact_svm.md §2.2.1): accepted, pinned next to its over-cap pair.", + layout(MessageFormat::V1, Some(BOTH), Some(Mutation::V1ComputeUnitLimit { limit: 400_000 })), Expect::Accept(Pin::Outcome), ).build(); x402_verify_v1_compute_limit_over_cap_reject => verify( @@ -418,14 +468,14 @@ crate::registry! { BugType::Settlement, caps_spec(), &[V1_CAPS], - "Version-1 header computeUnitLimit 200001, one unit over the configured maximum.", - layout(MessageFormat::V1, Some(BOTH), Some(Mutation::V1ComputeUnitLimit { limit: 200_001 })), - from_table(&Mutation::V1ComputeUnitLimit { limit: 200_001 }), + "Version-1 header computeUnitLimit 400001, one unit over the reference default maximum (scheme_exact_svm.md §2.2.1: 400,000).", + layout(MessageFormat::V1, Some(BOTH), Some(Mutation::V1ComputeUnitLimit { limit: 400_001 })), + from_table(&Mutation::V1ComputeUnitLimit { limit: 400_001 }), ).build(); x402_verify_v1_priority_fee_at_cap_accept => verify( "x402-verify-v1-priority-fee-at-cap-accept", BugType::Settlement, - spec(SVM, "3.1 Path 1 — Static Layout Verification (standard wallets)", "The legacy/version-0 Compute Budget price and the version-1 total priority fee MUST each be no greater than 5 lamports/CU on this path, using the normalization in §1.5 for version 1."), + spec(SVM, "3.1 Path 1 — Static Layout Verification (standard wallets)", "The legacy/version-0 Compute Budget price and the version-1 total priority fee MUST each be no greater than maxPriorityFeeMicroLamports (default 5 lamports/CU) on this path, using the normalization in §1.5 for version 1."), &[FAST_PATH_PRICE, V1_CAPS], "Version-1 priorityFee 1500 lamports over 300 units: exactly 5 lamports (5000000 micro-lamports) per unit, the fast-path cap, and under the 2000 lamport cap a sponsor may put on the total fee (scheme_exact_svm.md §2.2.1). Accepted (the cap is inclusive).", layout(MessageFormat::V1, Some(BOTH), Some(Mutation::V1Budget { limit: 300, lamports: 1_500 })), @@ -434,8 +484,8 @@ crate::registry! { x402_verify_v1_priority_fee_over_cap_reject => verify( "x402-verify-v1-priority-fee-over-cap-reject", BugType::Settlement, - spec(SVM, "3.1 Path 1 — Static Layout Verification (standard wallets)", "The legacy/version-0 Compute Budget price and the version-1 total priority fee MUST each be no greater than 5 lamports/CU on this path, using the normalization in §1.5 for version 1."), - &[FAST_PATH_PRICE, V1_CAPS], + spec(SVM, "3.1 Path 1 — Static Layout Verification (standard wallets)", "The legacy/version-0 Compute Budget price and the version-1 total priority fee MUST each be no greater than maxPriorityFeeMicroLamports (default 5 lamports/CU) on this path, using the normalization in §1.5 for version 1."), + &[FAST_PATH_PRICE, V1_CAPS, V1_FEE_PRECISION], "Version-1 priorityFee 1501 lamports over 300 units: one lamport above priorityFee * 1000000 <= 5000000 * 300, and still under a 2000 lamport cap on the total fee, so only the per-unit rule rejects it. A sponsor that compares the lamport total with the per-unit cap accepts it.", layout(MessageFormat::V1, Some(BOTH), Some(Mutation::V1Budget { limit: 300, lamports: 1_501 })), from_table(&Mutation::V1Budget { limit: 300, lamports: 1_501 }), @@ -478,7 +528,12 @@ crate::registry! { &[EXACTLY_ONE], "Version-1 TransferChecked declaring 9 decimals for a 6-decimal mint.", Mutation::SetDecimals { transfer: 0, decimals: 9 }, - ).build(); + ) + .also_conformant( + &[crate::case::Alternative::Accept], + "§1.4 matches a transfer by mint, destination ATA and amount (“correct mint, correct destination ATA, amount >= required”) and the scheme never names the TransferChecked decimals; the token program fails a TransferChecked whose decimals differ from the mint's, which the sponsor's simulation catches (§2.2.3, not run by offline vectors), so a static verifier that leaves it to simulation is conformant.", + ) + .build(); x402_verify_v1_fee_payer_authority_reject => v1_policy( "x402-verify-v1-fee-payer-authority-reject", spec(SVM, "2.1.1 Fee Payer Isolation (MUST)", "The fee payer / sponsor MUST NOT be the authority on any observed transfer (self-spend protection)."), diff --git a/rust/crates/conformance/src/cases/x402_upto.rs b/rust/crates/conformance/src/cases/x402_upto.rs index 07fa889da..28909441f 100644 --- a/rust/crates/conformance/src/cases/x402_upto.rs +++ b/rust/crates/conformance/src/cases/x402_upto.rs @@ -54,7 +54,7 @@ const REDERIVE_PDA: &str = "X402-cf373442ff"; const OPEN_ENCODES: &str = "X402-d75fb10a6f"; const DEPOSIT_NO_VOUCHER: &str = "X402-f747c74e76"; const STATIC_INSPECT: &str = "X402-52c9f1e405"; -const NO_LOOKUP_TABLES: &str = "X402-c1174b72d8"; +const NO_LOOKUP_TABLES: &str = "X402-4de59a1f27"; const FEE_PAYER_EQ: &str = "X402-9d68660de5"; const SIGNER_SET: &str = "X402-9af8f33cd6"; const FROM_SIGNATURE: &str = "X402-bcbf7025e5"; @@ -85,11 +85,11 @@ const TV_CLIENT: &str = "X402TX-61c735c7a9"; const TV_CLIENT_EMPTY: &str = "X402TX-2909c4b4ec"; const TV_REJECT_FIRST: &str = "X402TX-5267172b18"; const TV_SIZE: &str = "X402TX-dc7b0f3305"; -const TV_V1_BUDGET: &str = "X402TX-644919eb3b"; +const TV_V1_BUDGET: &str = "X402TX-f9bcc1a14a"; const TV_MESSAGE: &str = "X402TX-4de59a1f27"; const TV_NO_PREFIX: &str = "X402TX-125d312b26"; -const TV_V1_CAPS: &str = "X402TX-0f874a9c63"; -const TV_V1_NO_CB: &str = "X402TX-936b492daa"; +const TV_V1_CAPS: &str = "X402TX-703c03cfb5"; +const TV_V1_NO_CB: &str = "X402TX-915632f040"; const TV_LEGACY: &str = "X402TX-77742f428c"; const TV_OPEN_VERSION: &str = "X402TX-d444d01b9e"; @@ -195,7 +195,7 @@ fn s_txv1_budget() -> SpecRef { spec( TXV1, "Top-level instruction layout", - "In a version-1 transaction the same caps apply to the message TransactionConfig instead: computeUnitLimit MUST be present and MUST NOT exceed 400000, loadedAccountsDataSizeLimit MUST be present, and priorityFee (total lamports) MUST satisfy priorityFee 1000000 <= 5000000 computeUnitLimit.", + "computeUnitLimit (bit 2) MUST be set and MUST NOT exceed 400000, loadedAccountsDataSizeLimit (bit 3) MUST be set, and priorityFee (bits 0 and 1, total lamports) MUST satisfy priorityFee * 1000000 <= 5000000 * computeUnitLimit, evaluated without overflow.", ) } @@ -219,6 +219,17 @@ fn v1_route() -> Route { } } +/// A sponsor configured to accept version 0 only, stated explicitly: the +/// scheme gives a facilitator's own accepted set no default (“The facilitator +/// enforces its own accepted set; it does not read +/// `PaymentRequirements.extra.transactionVersions`.”). +fn v0_only_route() -> Route { + Route { + versions: Some(vec![0]), + ..Route::default() + } +} + fn input_of(spec: &VerifySpec) -> Input { Input::Static( spec.input() @@ -525,7 +536,7 @@ crate::registry! { x402_upto_verify_legacy_message_accept => accept( "x402-upto-verify-legacy-message-accept", POLICY_FILE, - spec(SVM, "Message and signer rules", "The message MAY be legacy or version 0, but it MUST NOT contain Address Lookup Table lookups."), + spec(SVM, "Message and signer rules", "The message version MUST be one advertised in extra.transactionVersions (0 when the field is absent; see [Transaction versions](#transaction-versions)), and the message MUST NOT contain Address Lookup Table lookups."), &[NO_LOOKUP_TABLES], "The same open compiled as a legacy (unversioned) message is accepted and policed like version 0.", with(base(), Tamper::Form(Form::Legacy)), @@ -535,8 +546,16 @@ crate::registry! { POLICY_FILE, spec(SVM, "Top-level instruction layout", "A sponsor MAY apply a stricter local policy for compute-unit limit, compute-unit price, and required-signature count (operator-configurable caps), but MUST NOT admit a compute-unit limit above 400000 or a compute-unit price above 5000000 microlamports."), &[CB_LIMIT, CB_PRICE, CB_ABSOLUTE], - "SetComputeUnitLimit 400000 and SetComputeUnitPrice 5000000 sit exactly at the absolute ceilings and are accepted.", - with(base(), Tamper::Prefix(vec![unit_limit_ix(400_000), unit_price_ix(5_000_000)])), + "SetComputeUnitLimit 400000 sits exactly at the absolute ceiling and SetComputeUnitPrice 5000 makes a 2000 lamport priority fee, exactly the sponsor's cap on the fee it pays (RULINGS S6): accepted.", + with(base(), Tamper::Prefix(vec![unit_limit_ix(400_000), unit_price_ix(5_000)])), + ); + x402_upto_verify_implicit_limit_at_fee_cap_accept => accept( + "x402-upto-verify-implicit-limit-at-fee-cap-accept", + POLICY_FILE, + spec(SVM, "Top-level instruction layout", "A sponsor MAY apply a stricter local policy for compute-unit limit, compute-unit price, and required-signature count (operator-configurable caps), but MUST NOT admit a compute-unit limit above 400000 or a compute-unit price above 5000000 microlamports."), + &[CB_PRICE, CB_ABSOLUTE, VERIFIER_POLICY], + "SetComputeUnitPrice 5000 with no SetComputeUnitLimit: the runtime budgets 200000 units for each of the open and the memo, a 2000 lamport priority fee, exactly the sponsor's cap (RULINGS S6): accepted. Pair: x402-upto-verify-implicit-limit-priority-fee-over-cap-reject.", + with(base(), Tamper::Prefix(vec![unit_price_ix(5_000)])), ); x402_upto_verify_two_memos_unbound_accept => accept_lenient( "x402-upto-verify-two-memos-unbound-accept", @@ -875,7 +894,7 @@ crate::registry! { x402_upto_verify_lookup_table_reject => reject( "x402-upto-verify-lookup-table-reject", POLICY_FILE, - spec(SVM, "Message and signer rules", "The message MAY be legacy or version 0, but it MUST NOT contain Address Lookup Table lookups."), + spec(SVM, "Message and signer rules", "The message version MUST be one advertised in extra.transactionVersions (0 when the field is absent; see [Transaction versions](#transaction-versions)), and the message MUST NOT contain Address Lookup Table lookups."), &[NO_LOOKUP_TABLES], BugType::AuthBypass, base(), @@ -1104,6 +1123,30 @@ crate::registry! { RejectCode::ComputePriceOverCap, None, ); + x402_upto_verify_priority_fee_over_cap_reject => verify_case( + "x402-upto-verify-priority-fee-over-cap-reject", + POLICY_FILE, + spec(SVM, "Top-level instruction layout", "A sponsor MAY apply a stricter local policy for compute-unit limit, compute-unit price, and required-signature count (operator-configurable caps), but MUST NOT admit a compute-unit limit above 400000 or a compute-unit price above 5000000 microlamports."), + &[CB_LIMIT, CB_PRICE, VERIFIER_POLICY], + BugType::AuthBypass, + "SetComputeUnitLimit 400000 and SetComputeUnitPrice 5000000: each at its absolute ceiling, but the sponsor would pay a 2000000 lamport priority fee. The sponsor bounds the fee it pays as limit times price (RULINGS S6): rejected as compute-price-over-cap. Pair: x402-upto-verify-compute-at-caps-accept.", + with(base(), Tamper::Prefix(vec![unit_limit_ix(400_000), unit_price_ix(5_000_000)])), + Expect::Reject { code: RejectCode::ComputePriceOverCap, reason: None }, + None, + ) + .also_conformant(&[crate::case::Alternative::Accept], super::CHANNEL_FEE_PRODUCT_POLICY); + x402_upto_verify_implicit_limit_priority_fee_over_cap_reject => verify_case( + "x402-upto-verify-implicit-limit-priority-fee-over-cap-reject", + POLICY_FILE, + spec(SVM, "Top-level instruction layout", "A sponsor MAY apply a stricter local policy for compute-unit limit, compute-unit price, and required-signature count (operator-configurable caps), but MUST NOT admit a compute-unit limit above 400000 or a compute-unit price above 5000000 microlamports."), + &[CB_PRICE, VERIFIER_POLICY], + BugType::AuthBypass, + "SetComputeUnitPrice 5001 with no SetComputeUnitLimit: the runtime budgets 200000 units for each of the open and the memo, so the sponsor would pay 2001 lamports, one over its cap (RULINGS S6). A verifier that bounds only declared limits accepts it: rejected as compute-price-over-cap. Pair: x402-upto-verify-implicit-limit-at-fee-cap-accept.", + with(base(), Tamper::Prefix(vec![unit_price_ix(5_001)])), + Expect::Reject { code: RejectCode::ComputePriceOverCap, reason: None }, + None, + ) + .also_conformant(&[crate::case::Alternative::Accept], super::CHANNEL_FEE_PRODUCT_POLICY); x402_upto_verify_compute_limit_over_cap_reject => reject( "x402-upto-verify-compute-limit-over-cap-reject", POLICY_FILE, @@ -1129,7 +1172,7 @@ crate::registry! { x402_upto_verify_compute_duplicate_limit_reject => reject( "x402-upto-verify-compute-duplicate-limit-reject", POLICY_FILE, - spec(SVM, "Top-level instruction layout", "An optional Compute Budget prefix containing at most one SetComputeUnitLimit instruction and at most one SetComputeUnitPrice instruction."), + spec(SVM, "Top-level instruction layout", "In a legacy or version-0 transaction, an optional Compute Budget prefix containing at most one SetComputeUnitLimit instruction and at most one SetComputeUnitPrice instruction."), &[LAYOUT], BugType::Wire, base(), @@ -1140,7 +1183,7 @@ crate::registry! { x402_upto_verify_compute_duplicate_price_reject => reject( "x402-upto-verify-compute-duplicate-price-reject", POLICY_FILE, - spec(SVM, "Top-level instruction layout", "An optional Compute Budget prefix containing at most one SetComputeUnitLimit instruction and at most one SetComputeUnitPrice instruction."), + spec(SVM, "Top-level instruction layout", "In a legacy or version-0 transaction, an optional Compute Budget prefix containing at most one SetComputeUnitLimit instruction and at most one SetComputeUnitPrice instruction."), &[LAYOUT], BugType::Wire, base(), @@ -1638,7 +1681,7 @@ crate::registry! { s_txv1_reject(), &[TV_REJECT_FIRST, TV_MESSAGE], BugType::Wire, - base(), + VerifySpec::honest(v0_only_route()), Tamper::Form(Form::v1()), RejectCode::UnsupportedVersion, None, @@ -1649,7 +1692,7 @@ crate::registry! { s_txv1_reject(), &[TV_REJECT_FIRST], BugType::Wire, - with(base(), Tamper::Suffix(vec![memo_ix(NONCE_MEMO), solana_instruction::Instruction { program_id: keys::pubkey(keys::SPLIT_RECIPIENT_2), accounts: vec![], data: vec![1] }])), + with(VerifySpec::honest(v0_only_route()), Tamper::Suffix(vec![memo_ix(NONCE_MEMO), solana_instruction::Instruction { program_id: keys::pubkey(keys::SPLIT_RECIPIENT_2), accounts: vec![], data: vec![1] }])), Tamper::Form(Form::v1()), RejectCode::UnsupportedVersion, None, @@ -1657,7 +1700,7 @@ crate::registry! { x402_upto_verify_v1_compute_budget_instruction_reject => reject( "x402-upto-verify-v1-compute-budget-instruction-reject", TXV1_FILE, - spec(TXV1, "Top-level instruction layout", "A version-1 transaction that contains a Compute Budget instruction MUST be rejected."), + spec(TXV1, "Top-level instruction layout", "A version-1 transaction that contains a Compute Budget instruction MUST be rejected (an x402 sponsor rule; the runtime treats such instructions as no-ops)."), &[TV_V1_NO_CB, TV_NO_PREFIX], BugType::Wire, with(VerifySpec::honest(v1_route()), Tamper::Form(Form::v1())), @@ -1682,8 +1725,8 @@ crate::registry! { s_txv1_budget(), &[TV_V1_CAPS], BugType::AuthBypass, - "A version-1 open at 200000 units with priorityFee 1000001 lamports (priorityFee * 1000000 > 5000000 * computeUnitLimit): rejected as compute-price-over-cap.", - with(VerifySpec::honest(v1_route()), Tamper::Form(Form::V1 { unit_limit: Some(200_000), priority_fee_lamports: Some(1_000_001), loaded_accounts_data_size_limit: Some(64 * 1024 * 1024) })), + "A version-1 open at 300 units with priorityFee 1501 lamports (priorityFee * 1000000 > 5000000 * computeUnitLimit), still under the 2000 lamport cap on the total fee, so only the per-unit rule rejects it: rejected as compute-price-over-cap.", + with(VerifySpec::honest(v1_route()), Tamper::Form(Form::V1 { unit_limit: Some(300), priority_fee_lamports: Some(1_501), loaded_accounts_data_size_limit: Some(64 * 1024 * 1024) })), Expect::Reject { code: RejectCode::ComputePriceOverCap, reason: None }, None, ); @@ -1692,9 +1735,21 @@ crate::registry! { TXV1_FILE, s_txv1_budget(), &[TV_V1_CAPS], - "A version-1 open at 200000 units with priorityFee 1000000 lamports: exactly 5000000 micro-lamports per unit, accepted.", - with(VerifySpec::honest(v1_route()), Tamper::Form(Form::V1 { unit_limit: Some(200_000), priority_fee_lamports: Some(1_000_000), loaded_accounts_data_size_limit: Some(64 * 1024 * 1024) })), + "A version-1 open at 300 units with priorityFee 1500 lamports: exactly 5000000 micro-lamports per unit and under the 2000 lamport cap a sponsor puts on the total fee (RULINGS S6), accepted.", + with(VerifySpec::honest(v1_route()), Tamper::Form(Form::V1 { unit_limit: Some(300), priority_fee_lamports: Some(1_500), loaded_accounts_data_size_limit: Some(64 * 1024 * 1024) })), ); + x402_upto_verify_v1_priority_fee_over_sponsor_cap_reject => verify_case( + "x402-upto-verify-v1-priority-fee-over-sponsor-cap-reject", + TXV1_FILE, + s_txv1_budget(), + &[TV_V1_CAPS], + BugType::AuthBypass, + "A version-1 open at 200000 units with priorityFee 2001 lamports: far under 5000000 micro-lamports per unit, but one lamport over the cap the sponsor puts on the total fee it pays (RULINGS S6): rejected as compute-price-over-cap.", + with(VerifySpec::honest(v1_route()), Tamper::Form(Form::V1 { unit_limit: Some(200_000), priority_fee_lamports: Some(2_001), loaded_accounts_data_size_limit: Some(64 * 1024 * 1024) })), + Expect::Reject { code: RejectCode::ComputePriceOverCap, reason: None }, + None, + ) + .also_conformant(&[crate::case::Alternative::Accept], super::CHANNEL_FEE_PRODUCT_POLICY); x402_upto_verify_v1_missing_limit_reject => verify_case( "x402-upto-verify-v1-missing-limit-reject", TXV1_FILE, diff --git a/rust/crates/conformance/src/fixture_rpc.rs b/rust/crates/conformance/src/fixture_rpc.rs index 09cff8a6b..93663dcef 100644 --- a/rust/crates/conformance/src/fixture_rpc.rs +++ b/rust/crates/conformance/src/fixture_rpc.rs @@ -77,7 +77,8 @@ pub struct Fixtures { impl Fixtures { /// Parse `input.rpcFixtures`, defaulting the blockhash to the charge /// request's `methodDetails.recentBlockhash` (what the retired TS driver - /// did, so every SDK sees the chain state it always saw). + /// did, so every SDK sees the chain state it always saw), or the session + /// open challenge's. pub fn from_input(input: &Value) -> Result { let raw = input.get("rpcFixtures").cloned().unwrap_or(json!({})); let mut mints = BTreeMap::new(); @@ -141,9 +142,13 @@ impl Fixtures { .and_then(Value::as_str) .map(str::to_string) .or_else(|| { - input - .pointer("/request/methodDetails/recentBlockhash") - .and_then(Value::as_str) + ["/request", "/sessionOpenBuild/request"] + .iter() + .find_map(|request| { + input + .pointer(&format!("{request}/methodDetails/recentBlockhash")) + .and_then(Value::as_str) + }) .map(str::to_string) }); Ok(Self { diff --git a/rust/crates/conformance/src/interop/adapters.rs b/rust/crates/conformance/src/interop/adapters.rs index f6b65d10d..cad745bd7 100644 --- a/rust/crates/conformance/src/interop/adapters.rs +++ b/rust/crates/conformance/src/interop/adapters.rs @@ -126,6 +126,18 @@ const RUST_UPTO_SERVER: Native = native( "../rust", "x402_harness_upto_server", ); +const RUST_BATCH_CLIENT: Native = native( + "rust-client-rust-x402-batch", + "rust", + "../rust", + "x402_harness_batch_client", +); +const RUST_BATCH_SERVER: Native = native( + "rust-server-rust-x402-batch", + "rust", + "../rust", + "x402_harness_batch_server", +); const GO_CLIENT: Native = native("go-client-go", "go", "go-client", "paykit-client"); const GO_SERVER: Native = native("go-server-go", "go", "go-server", "paykit-server"); const SWIFT_CLIENT: Native = native( @@ -189,6 +201,14 @@ const TS_EXACT_CLIENT: &[&str] = &[ "tsx", "src/fixtures/typescript/exact-client.ts", ]; +const TS_UPTO_SERVER: &[&str] = &[ + "pnpm", + "exec", + "node", + "--import", + "tsx", + "src/fixtures/typescript/upto-server.ts", +]; const TS_EXACT_SERVER: &[&str] = &[ "pnpm", "exec", @@ -264,7 +284,7 @@ const fn a( } } -use Intent::{Charge, Session, X402Exact, X402Upto}; +use Intent::{Charge, Session, X402Batch, X402Exact, X402Upto}; use Launch::{Native as N, Source as S}; use Role::{Client as C, Server as Sv}; @@ -371,8 +391,19 @@ pub const ADAPTERS: &[Adapter] = &[ ), // x402 upto servers. a("rust", "rust", Sv, X402Upto, "rust", N(RUST_UPTO_SERVER)), + a( + "typescript", + "typescript", + Sv, + X402Upto, + "typescript", + S(TS_UPTO_SERVER), + ), a("go", "go", Sv, X402Upto, "go-paykit", N(GO_SERVER)), a("python", "python", Sv, X402Upto, "python", S(PY_SERVER)), + // x402 batch-settlement: only the Rust SDK implements it. + a("rust", "rust", C, X402Batch, "rust", N(RUST_BATCH_CLIENT)), + a("rust", "rust", Sv, X402Batch, "rust", N(RUST_BATCH_SERVER)), // MPP session. a( "python", diff --git a/rust/crates/conformance/src/interop/chain.rs b/rust/crates/conformance/src/interop/chain.rs index cbcad9b67..fdb6bd2e9 100644 --- a/rust/crates/conformance/src/interop/chain.rs +++ b/rust/crates/conformance/src/interop/chain.rs @@ -230,6 +230,22 @@ impl Chain { // create it (draft-solana-charge-00 "SPL Tokens"). self.fund_token(&acc.pay_to.pubkey, mint, 1, program)?; self.fund_token(&acc.upto_pay_to.pubkey, mint, 1, program)?; + // batch-settlement: the sponsor holds the channel's zero-share + // payee seat, whose token account the settlement simulation reads. + // Its distribute also pays the protocol treasury's token account, + // which a deployed cluster already has. + if scenario.intent == super::claims::Intent::X402Batch { + self.fund_token(&acc.fee_payer.pubkey, mint, 0, program)?; + } + // Payment-channels `distribute` (batch and upto) also pays the + // protocol treasury's token account, which a deployed cluster + // already has; the upto readiness check refuses the open without it. + if matches!( + scenario.intent, + super::claims::Intent::X402Batch | super::claims::Intent::X402Upto + ) { + self.fund_token(PAYMENT_CHANNEL_TREASURY_OWNER, mint, 0, program)?; + } if scenario.pre_create_platform_ata { self.fund_token(&acc.platform.pubkey, mint, 0, program)?; } @@ -243,6 +259,24 @@ impl Chain { .map_err(|e| format!("{method}: {e}")) } + /// Confirmed signatures touching `address`, newest first. + pub fn signatures_for_address(&self, address: &str) -> Result, String> { + let v = self.send( + "getSignaturesForAddress", + json!([address, {"commitment": "confirmed"}]), + )?; + v.as_array() + .ok_or_else(|| format!("getSignaturesForAddress {address}: {v}"))? + .iter() + .map(|entry| { + entry["signature"] + .as_str() + .map(str::to_string) + .ok_or_else(|| format!("getSignaturesForAddress {address}: {entry}")) + }) + .collect() + } + /// Token balance of `owner`'s ATA; a missing account reads as zero. pub fn token_balance(&self, owner: &str, mint: &str, program: &str) -> Result { let ata = crate::keys::ata(owner, mint, program).to_string(); @@ -283,7 +317,8 @@ impl Chain { loop { let v = self.send( "getTransaction", - json!([signature, {"commitment": "confirmed", "encoding": "base64", "maxSupportedTransactionVersion": 0}]), + // Version 1 (SIMD-0385) settlements are read back too. + json!([signature, {"commitment": "confirmed", "encoding": "base64", "maxSupportedTransactionVersion": 1}]), ); match v { Ok(v) if !v.is_null() => return Ok(v), diff --git a/rust/crates/conformance/src/interop/claims.rs b/rust/crates/conformance/src/interop/claims.rs index 9e13ea4c7..ca76e89c3 100644 --- a/rust/crates/conformance/src/interop/claims.rs +++ b/rust/crates/conformance/src/interop/claims.rs @@ -9,14 +9,17 @@ pub enum Intent { Charge, X402Exact, X402Upto, + /// x402 `batch-settlement`: deposit, vouchers, then out-of-band redemption. + X402Batch, Session, } impl Intent { - pub const ALL: [Intent; 4] = [ + pub const ALL: [Intent; 5] = [ Intent::Charge, Intent::X402Exact, Intent::X402Upto, + Intent::X402Batch, Intent::Session, ]; @@ -26,6 +29,7 @@ impl Intent { Intent::Charge => "charge", Intent::X402Exact => "x402-exact", Intent::X402Upto => "x402-upto", + Intent::X402Batch => "x402-batch", Intent::Session => "session", } } @@ -33,7 +37,7 @@ impl Intent { pub fn protocol(self) -> &'static str { match self { Intent::Charge | Intent::Session => "mpp", - Intent::X402Exact | Intent::X402Upto => "x402", + Intent::X402Exact | Intent::X402Upto | Intent::X402Batch => "x402", } } @@ -42,6 +46,7 @@ impl Intent { Intent::Charge => "charge", Intent::X402Exact => "exact", Intent::X402Upto => "upto", + Intent::X402Batch => "batch-settlement", Intent::Session => "session", } } diff --git a/rust/crates/conformance/src/interop/runner.rs b/rust/crates/conformance/src/interop/runner.rs index 605d29f0b..a5ffb7fd6 100644 --- a/rust/crates/conformance/src/interop/runner.rs +++ b/rust/crates/conformance/src/interop/runner.rs @@ -218,16 +218,19 @@ pub fn environment(s: &Scenario, acc: &Accounts, rpc_url: &str) -> BTreeMap { + Intent::X402Exact | Intent::X402Upto | Intent::X402Batch => { set( "PAY_KIT_HARNESS_PROTOCOL", - if s.intent == Intent::X402Upto { - "x402-upto" - } else { - "x402" + match s.intent { + Intent::X402Upto => "x402-upto", + Intent::X402Batch => "x402-batch", + _ => "x402", } .into(), ); + if let Some(channels) = s.batch_channels { + set("X402_HARNESS_BATCH_CHANNELS", channels.to_string()); + } set("X402_HARNESS_AMOUNT", s.amount.into()); if let Some(actual) = s.actual_amount { set("X402_HARNESS_ACTUAL_AMOUNT", actual.into()); @@ -340,7 +343,35 @@ fn paid_once(s: &Scenario, before: &Balances, after: &Balances) -> Result<(), St fn settled(ctx: &Ctx<'_>, s: &Scenario, acc: &Accounts, signature: &str) -> Result<(), String> { let tx = ctx.chain.transaction(signature, SETTLEMENT_DEADLINE)?; let message = settle::decode(&tx)?; - settle::assert_shape(s, acc, &message) + if let Some(version) = s.settled_version { + if message.version() != version.to_string() { + return Err(format!( + "settled transaction is version {}, expected version {version}", + message.version() + )); + } + } + settle::assert_shape(s, acc, &message)?; + if let Some(version) = s.open_version { + let channel = message + .upto_channel(s.primary_delta()) + .ok_or("the settlement names no channel")? + .to_string(); + // The channel's first transaction is the client's open. + let open = ctx + .chain + .signatures_for_address(&channel)? + .pop() + .ok_or_else(|| format!("no transaction on channel {channel}"))?; + let open_version = + settle::decode(&ctx.chain.transaction(&open, SETTLEMENT_DEADLINE)?)?.version(); + if open_version != version.to_string() { + return Err(format!( + "channel open {open} is version {open_version}, expected version {version}" + )); + } + } + Ok(()) } fn assert_paid( @@ -374,6 +405,86 @@ fn assert_paid( Ok(()) } +/// `x402-batch`: every deposit open landed; the server redeemed every channel +/// with one claim and one distribute transaction while they fit one version-1 +/// transaction (18 claims, 13 distributes); each redemption transaction has +/// the scenario's message version; and `payTo` received every charge. +fn assert_batch_redeemed( + ctx: &Ctx<'_>, + s: &Scenario, + acc: &Accounts, + result: &ClientResult, + before: &Balances, +) -> Result<(), String> { + if result.status != 200 || !result.ok || result.body["paid"] != true { + return Err(format!( + "expected every payment and the redemption to succeed, got {} (ok={}): {}", + result.status, result.ok, result.body + )); + } + let signatures = |pointer: &str| -> Result, String> { + result + .body + .pointer(pointer) + .and_then(Value::as_array) + .ok_or_else(|| format!("the client reported no {pointer}"))? + .iter() + .map(|v| { + v.as_str() + .map(str::to_string) + .ok_or(format!("{pointer}: {v}")) + }) + .collect() + }; + let channels = usize::from( + s.batch_channels + .ok_or("x402-batch scenario without channels")?, + ); + let deposits = signatures("/deposits")?; + if deposits.len() != channels { + return Err(format!( + "{} deposits for {channels} channels", + deposits.len() + )); + } + for signature in &deposits { + settle::decode(&ctx.chain.transaction(signature, SETTLEMENT_DEADLINE)?)?; + } + for (pointer, capacity) in [ + ("/redemption/claims", BATCH_V1_CLAIM_CAPACITY), + ("/redemption/distributes", BATCH_V1_SETTLE_CAPACITY), + ] { + let redeemed = signatures(pointer)?; + let want = if s.settled_version == Some(1) && channels <= capacity { + 1 + } else { + redeemed.len().max(1) + }; + if redeemed.len() != want { + return Err(format!( + "{pointer}: {} transactions for {channels} channels, expected {want}", + redeemed.len() + )); + } + for signature in &redeemed { + let message = settle::decode(&ctx.chain.transaction(signature, SETTLEMENT_DEADLINE)?)?; + if let Some(version) = s.settled_version { + if message.version() != version.to_string() { + return Err(format!( + "{pointer}: {signature} is version {}, expected version {version}", + message.version() + )); + } + } + } + } + paid_once(s, before, &balances(ctx, s, acc)?) +} + +/// Channels one version-1 claim / distribute carries (scheme_batch_settlement_svm.md). +const BATCH_V1_CLAIM_CAPACITY: usize = 18; +const BATCH_V1_SETTLE_CAPACITY: usize = 13; + fn fault_context(case: &Case, acc: &Accounts) -> FaultContext { FaultContext { intent: case.scenario.intent, @@ -476,6 +587,9 @@ fn judge( .map_err(|e| format!("client adapter failed: {}", e.message)) }; match (s.kind, s.expect) { + (Kind::Standard, Expect::Paid { .. }) if s.intent == Intent::X402Batch => { + assert_batch_redeemed(ctx, s, acc, need_client()?, before) + } (Kind::Standard, Expect::Paid { onchain }) => { assert_paid(ctx, s, acc, need_client()?, before, onchain) } diff --git a/rust/crates/conformance/src/interop/scenarios.rs b/rust/crates/conformance/src/interop/scenarios.rs index 0b0d80e07..42465e348 100644 --- a/rust/crates/conformance/src/interop/scenarios.rs +++ b/rust/crates/conformance/src/interop/scenarios.rs @@ -266,6 +266,17 @@ pub struct Scenario { pub servers: Participants, pub pre_create_platform_ata: bool, pub compute_unit_limit: Option, + /// Message version the settled transaction must have, when the scenario + /// pins one (`None`: any accepted version). + pub settled_version: Option, + /// `x402-upto`: message version the client's channel `open` must have. + /// The judge finds the open as the oldest transaction on the settled + /// channel. + pub open_version: Option, + /// `x402-batch`: channels the client opens before the server redeems + /// them all at once. Each is paid by its deposit, and the first one by a + /// second voucher. + pub batch_channels: Option, } impl Scenario { @@ -281,6 +292,11 @@ impl Scenario { if let Some(actual) = self.actual_amount { return actual.parse().expect("actual amount"); } + if let Some(channels) = self.batch_channels { + // One request per deposit plus a second voucher on the first channel. + let per_request: u64 = self.amount.parse().expect("amount"); + return per_request * (u64::from(channels) + 1); + } let total: u64 = self.amount.parse().expect("amount"); total - self @@ -291,7 +307,7 @@ impl Scenario { } pub fn needs_payment_channels(&self) -> bool { - self.intent == Intent::X402Upto + matches!(self.intent, Intent::X402Upto | Intent::X402Batch) } } @@ -303,6 +319,7 @@ const EXACT_DOC: &str = "x402/specs/schemes/exact/scheme_exact.md"; const EXACT_SVM_DOC: &str = "x402/specs/schemes/exact/scheme_exact_svm.md"; const UPTO_DOC: &str = "x402/specs/schemes/upto/scheme_upto.md"; const UPTO_SVM_DOC: &str = "x402/specs/schemes/upto/scheme_upto_svm.md"; +const BATCH_SVM_DOC: &str = "x402/specs/schemes/batch-settlement/scheme_batch_settlement_svm.md"; const fn spec(doc: &'static str, section: &'static str, quote: &'static str) -> Spec { Spec { @@ -358,8 +375,31 @@ const BASE: Scenario = Scenario { servers: Participants::All, pre_create_platform_ata: false, compute_unit_limit: None, + settled_version: None, + open_version: None, + batch_channels: None, }; +const ONLY_RUST_BATCH: Participants = Participants::Only( + &["rust"], + "x402 batch-settlement is implemented only by the Rust SDK in pay-kit", +); + +const ONLY_RUST_V1_UPTO_CLIENT: Participants = Participants::Only( + &["rust"], + "only the Rust upto client builds a version-1 channel open; the Go, Python, Swift and Kotlin upto clients build version 0 only", +); + +const X402_V1_UPTO_SERVERS: Participants = Participants::Only( + &["rust", "typescript"], + "only the Rust and TypeScript upto servers advertise transactionVersions [0, 1] and accept a version-1 open; the Go and Python upto servers accept version 0 only", +); + +const X402_V1_SDKS: Participants = Participants::Only( + &["rust", "typescript"], + "only the Rust and TypeScript x402 adapters build version-1 transactions and advertise transactionVersions [0, 1]; the other SDKs build version 0 only (harness/expectations FINDINGS txv1-*)", +); + const ONLY_TS_CLIENT_COMPUTE: Participants = Participants::Only( &["typescript"], "only the TypeScript client adapter can inject a compute budget (MPP_HARNESS_COMPUTE_UNIT_LIMIT)", @@ -621,6 +661,17 @@ pub const SCENARIOS: &[Scenario] = &[ network: SOLANA_DEVNET, ..BASE }, + Scenario { + id: "x402-exact-v1", + intent: Intent::X402Exact, + description: "The sponsor advertises extra.transactionVersions [0, 1] and the client builds version 1 (SIMD-0385): the payment settles on chain as a version-1 transaction carrying its compute budget in the message config.", + spec: spec(EXACT_SVM_DOC, "1.5 Transaction Versions (MUST)", "The client MUST intersect the advertised versions (`[0]` when the field is absent) with the versions it and its signer support, then build the highest version in that intersection."), + network: SOLANA_DEVNET, + settled_version: Some(1), + clients: X402_V1_SDKS, + servers: X402_V1_SDKS, + ..BASE + }, Scenario { id: "x402-exact-network-mismatch", intent: Intent::X402Exact, @@ -703,6 +754,19 @@ pub const SCENARIOS: &[Scenario] = &[ expect: Expect::NoCredential, ..BASE }, + // ── x402 batch-settlement ── + Scenario { + id: "x402-batch-v1-redeem", + intent: Intent::X402Batch, + description: "The client opens five channels (each paid by its deposit) and pays a second voucher on the first; the server then redeems them all. More than four channels claimed in one transaction proves the version-1 capacity: one version-1 claim and one version-1 distribute, and payTo receives all six charges.", + spec: spec(BATCH_SVM_DOC, "Facilitator-built transactions and batching capacity", "The facilitator MAY build any message version the network supports."), + network: SOLANA_DEVNET, + settled_version: Some(1), + batch_channels: Some(5), + clients: ONLY_RUST_BATCH, + servers: ONLY_RUST_BATCH, + ..BASE + }, // ── x402 upto (harness/src/intents/x402-upto.ts) ── Scenario { id: "x402-upto-basic", @@ -717,6 +781,23 @@ pub const SCENARIOS: &[Scenario] = &[ settlement_header: "x-payment-settlement-signature", ..BASE }, + Scenario { + id: "x402-upto-v1", + intent: Intent::X402Upto, + description: "The server advertises transactionVersions [0, 1]: the client opens the channel with a version-1 transaction, the server's facilitator runs its open + settle + distribute readiness simulation and broadcasts the open, then settles the metered 50000 with a version-1 settle_and_seal and distribute.", + spec: spec(UPTO_SVM_DOC, "PaymentPayload", "Its message version MUST be one advertised in `extra.transactionVersions`"), + network: SOLANA_DEVNET, + price: "0.10", + amount: "100000", + actual_amount: Some("50000"), + resource_path: "/usage", + settlement_header: "x-payment-settlement-signature", + settled_version: Some(1), + open_version: Some(1), + clients: ONLY_RUST_V1_UPTO_CLIENT, + servers: X402_V1_UPTO_SERVERS, + ..BASE + }, Scenario { id: "x402-upto-zero-actual", intent: Intent::X402Upto, diff --git a/rust/crates/conformance/src/interop/settle.rs b/rust/crates/conformance/src/interop/settle.rs index 52fefb01a..ab44d1ca4 100644 --- a/rust/crates/conformance/src/interop/settle.rs +++ b/rust/crates/conformance/src/interop/settle.rs @@ -24,6 +24,23 @@ pub struct Message { } impl Message { + /// The message version: `"legacy"`, `"0"` or `"1"`. + pub fn version(&self) -> &'static str { + match self.msg { + VersionedMessage::Legacy(_) => "legacy", + VersionedMessage::V0(_) => "0", + VersionedMessage::V1(_) => "1", + } + } + + /// The channel an `x402-upto` settlement closes: account 1 (`channel`) of + /// its `settle_and_seal`, which follows the Ed25519 verify when the + /// metered amount is non-zero. + pub fn upto_channel(&self, actual: u64) -> Option<&str> { + let settle = self.instructions().get(usize::from(actual != 0))?; + settle.accounts.get(1).map(|index| self.account(*index)) + } + fn account(&self, index: u8) -> &str { self.keys .get(index as usize) @@ -279,17 +296,22 @@ fn upto_shape(c: &mut Checker<'_>, scenario: &Scenario, acc: &Accounts) { let m = c.m; let actual = scenario.primary_delta(); let ixs = m.instructions(); - let expected_len = if actual == 0 { 5 } else { 6 }; - if ixs.len() != expected_len { + let verify_len = usize::from(actual != 0); + // The payee and treasury ATA creates are optional: the spec has the + // facilitator confirm those accounts are usable before `open` (readiness + // step 8), so a facilitator may rely on them existing (the TypeScript + // one does) or create them idempotently (the Rust one does). + let with_creates = ixs.len() == verify_len + 4; + if !with_creates && ixs.len() != verify_len + 2 { c.problems.push(format!( - "x402-upto settlement has {} instructions, expected {expected_len}", - ixs.len() + "x402-upto settlement has {} instructions, expected {} or {}", + ixs.len(), + verify_len + 2, + verify_len + 4 )); return; } - let (settle, create_payee, create_treasury, create_recipient, distribute) = if actual == 0 { - (&ixs[0], &ixs[1], &ixs[2], &ixs[3], &ixs[4]) - } else { + if actual != 0 { let verify = &ixs[0]; c.check(m.program(verify) == ED25519_PROGRAM, || { "first instruction is not an Ed25519 verify".into() @@ -312,7 +334,12 @@ fn upto_shape(c: &mut Checker<'_>, scenario: &Scenario, acc: &Accounts) { c.check(u64_le(&verify.data, 112 + 2 + 32) == Some(actual), || { format!("voucher cumulative amount != {actual}") }); - (&ixs[1], &ixs[2], &ixs[3], &ixs[4], &ixs[5]) + } + let rest = &ixs[verify_len..]; + let (settle, creates, distribute) = if with_creates { + (&rest[0], Some((&rest[1], &rest[2])), &rest[3]) + } else { + (&rest[0], None, &rest[1]) }; c.check(m.program(settle) == PAYMENT_CHANNELS_PROGRAM, || { "settle_and_seal is not a payment-channels instruction".into() @@ -333,21 +360,18 @@ fn upto_shape(c: &mut Checker<'_>, scenario: &Scenario, acc: &Accounts) { let pay_to = acc.upto_pay_to.pubkey.as_str(); let recipient_ata = ata(pay_to, mint, program); let treasury_ata = ata(PAYMENT_CHANNEL_TREASURY_OWNER, mint, program); - for (ix, owner, ata_addr, what) in [ - (create_payee, pay_to, recipient_ata.as_str(), "payee"), - ( - create_treasury, - PAYMENT_CHANNEL_TREASURY_OWNER, - treasury_ata.as_str(), - "treasury", - ), - ( - create_recipient, - pay_to, - recipient_ata.as_str(), - "recipient", - ), - ] { + let creates = creates.map(|(create_payee, create_treasury)| { + [ + (create_payee, pay_to, recipient_ata.as_str(), "payee"), + ( + create_treasury, + PAYMENT_CHANNEL_TREASURY_OWNER, + treasury_ata.as_str(), + "treasury", + ), + ] + }); + for (ix, owner, ata_addr, what) in creates.into_iter().flatten() { let ok = m.program(ix) == ATA_PROGRAM && ix.data.first() == Some(&1) && c.ata_accounts_match(ix, ata_addr, owner, mint, program); diff --git a/rust/crates/conformance/src/main.rs b/rust/crates/conformance/src/main.rs index 1d1b5dd8b..684b28877 100644 --- a/rust/crates/conformance/src/main.rs +++ b/rust/crates/conformance/src/main.rs @@ -440,6 +440,22 @@ fn case_show(root: &Path, id: &str) -> ExitCode { .unwrap_or_default(), vector.file ); + if let Some(alternatives) = vector.expect()["alsoConformant"].as_array() { + let verdicts: Vec = alternatives + .iter() + .map(|alt| match alt["rejectCode"].as_str() { + Some(code) => format!("reject {code}"), + None => alt["outcome"].as_str().unwrap_or_default().to_string(), + }) + .collect(); + println!( + "also conformant: {} ({})\n", + verdicts.join(", "), + vector.expect()["alsoConformantReason"] + .as_str() + .unwrap_or_default() + ); + } if let Some(d) = vector.raw["description"].as_str() { println!("{d}\n"); } diff --git a/rust/crates/conformance/src/mutate.rs b/rust/crates/conformance/src/mutate.rs index dbcc8dfdf..b2e7574ac 100644 --- a/rust/crates/conformance/src/mutate.rs +++ b/rust/crates/conformance/src/mutate.rs @@ -165,6 +165,14 @@ pub enum Mutation { /// Version 1: remove the header `loadedAccountsDataSizeLimit` (budgeted /// zero bytes). V1DropLoadedAccountsDataSizeLimit, + /// Version 1: set the header `loadedAccountsDataSizeLimit`. Whether a + /// value below the runtime maximum is a reject depends on the suite's + /// rule, so `expected` is `None`: cases using it are authored. + V1LoadedAccountsDataSizeLimit { bytes: u32 }, + /// Version 1: set the header `heapSize` (a RequestHeapFrame in the + /// header). Sponsors refuse it as they refuse RequestHeapFrame on + /// version 0. + V1HeapSize { bytes: u32 }, /// Replace the n-th Memo instruction's text with `len` hex characters, /// to move the serialized size across a version's limit. Whether that is /// a reject depends on the format, so `expected` is `None`. @@ -235,6 +243,7 @@ impl Mutation { V1DropComputeUnitLimit | V1DropLoadedAccountsDataSizeLimit, Suite::Charge | Suite::X402Exact | Suite::Session, ) => Some(InvalidPayload), + (V1HeapSize { .. }, Suite::X402Exact) => Some(InvalidPayload), (AddLookupTable, Suite::Charge | Suite::X402Exact | Suite::Session) => { Some(InvalidPayload) } @@ -363,6 +372,12 @@ impl Mutation { Mutation::V1DropLoadedAccountsDataSizeLimit => { "version-1 header loadedAccountsDataSizeLimit removed".into() } + Mutation::V1LoadedAccountsDataSizeLimit { bytes } => { + format!("version-1 header loadedAccountsDataSizeLimit set to {bytes}") + } + Mutation::V1HeapSize { bytes } => { + format!("version-1 header heapSize set to {bytes}") + } Mutation::PadMemo { memo, len } => { format!("memo #{memo} replaced with {len} hex characters") } @@ -426,7 +441,9 @@ impl Mutation { | Mutation::V1PriorityFee { .. } | Mutation::V1Budget { .. } | Mutation::V1DropComputeUnitLimit - | Mutation::V1DropLoadedAccountsDataSizeLimit => { + | Mutation::V1DropLoadedAccountsDataSizeLimit + | Mutation::V1LoadedAccountsDataSizeLimit { .. } + | Mutation::V1HeapSize { .. } => { let mut config = v1_config(&tx.message) .ok_or_else(|| format!("{self:?} needs a version-1 message"))?; match self { @@ -439,6 +456,10 @@ impl Mutation { config.priority_fee = Some(*lamports); } Mutation::V1DropComputeUnitLimit => config.compute_unit_limit = None, + Mutation::V1LoadedAccountsDataSizeLimit { bytes } => { + config.loaded_accounts_data_size_limit = Some(*bytes) + } + Mutation::V1HeapSize { bytes } => config.heap_size = Some(*bytes), _ => config.loaded_accounts_data_size_limit = None, } let mut out = compile_as(MessageFormat::V1, &decompile(&tx.message)?, config)?; @@ -764,7 +785,9 @@ impl Mutation { | Mutation::V1PriorityFee { .. } | Mutation::V1Budget { .. } | Mutation::V1DropComputeUnitLimit - | Mutation::V1DropLoadedAccountsDataSizeLimit => { + | Mutation::V1DropLoadedAccountsDataSizeLimit + | Mutation::V1LoadedAccountsDataSizeLimit { .. } + | Mutation::V1HeapSize { .. } => { unreachable!("handled above") } } diff --git a/rust/crates/conformance/src/realize.rs b/rust/crates/conformance/src/realize.rs index 86ae3f51e..d2be85cb6 100644 --- a/rust/crates/conformance/src/realize.rs +++ b/rust/crates/conformance/src/realize.rs @@ -30,6 +30,7 @@ use solana_pay_kit::core::store::{ }; use solana_pay_kit::mpp::client::{ build_charge_transaction_with_options, BuildChargeTransactionOptions, ComputeBudgetOptions, + PayerFundedAtaCreation, }; use solana_pay_kit::mpp::protocol::core::{ base64url_decode, base64url_encode, compute_challenge_id, Base64UrlJson, @@ -524,6 +525,9 @@ async fn charge_build(input: &Value) -> Result { external_id: charge.external_id.clone(), compute_budget: budget, max_tx_version: signer_max_version(input)?, + // The vectors pin the spec's client-paid shape, which includes split + // ATA creation (RULINGS C5); the kit declines it by default. + payer_funded_ata_creation: PayerFundedAtaCreation::Include, ..Default::default() }; let recipient = charge @@ -990,8 +994,27 @@ pub(crate) fn canonical_bytes(input: &Value) -> Result { // ── expectation ──────────────────────────────────────────────────────────── -/// Build the `expect` block, enforcing the case's contract with the kit. +/// Build the `expect` block, enforcing the case's contract with the kit, and +/// append the verdicts the specs also allow (`alsoConformant`). pub fn expectation(case: &Case, input: &Value, observed: &Observed) -> Result { + let mut expect = primary_expectation(case, input, observed)?; + if let Some(also) = &case.also_conformant { + expect["alsoConformant"] = also + .verdicts + .iter() + .map(|alt| match alt { + crate::case::Alternative::Accept => json!({ "outcome": "accept" }), + crate::case::Alternative::Reject(code) => { + json!({ "outcome": "reject", "rejectCode": code.as_str() }) + } + }) + .collect(); + expect["alsoConformantReason"] = json!(also.reason); + } + Ok(expect) +} + +fn primary_expectation(case: &Case, input: &Value, observed: &Observed) -> Result { match &case.provenance { Provenance::Generated => match (&case.expect, observed) { (Expect::Accept(pin), Observed::Accept(output)) => { diff --git a/rust/crates/conformance/src/realize/batch.rs b/rust/crates/conformance/src/realize/batch.rs index 834183f65..fbe34543b 100644 --- a/rust/crates/conformance/src/realize/batch.rs +++ b/rust/crates/conformance/src/realize/batch.rs @@ -12,6 +12,12 @@ //! whose channel store holds `batchServerChannel`, verifies and reserves //! `x402PaymentHeader` against the chain state of `rpcFixtures`. A //! `batchCorrective` input is the client-side check of a corrective 402. +//! `batchVerdictFromStore: true` marks a vector whose verdict rests on the +//! store record alone (the charged or accepted cumulative, a close-pending +//! mark): a stateless facilitator never sees it (RULINGS B1), so a testee +//! whose only verify entry point is one reports `unsupported-mode`. +//! `batchServer.transactionVersions` is the facilitator's own accepted +//! set; a vector whose verdict depends on it states it. //! - **build-transaction**: the client builds the payload `batchClient` //! names against `batchClient.requirements`; the judge checks the build //! against the spec's structural rules and the Rust server's verifier. @@ -639,7 +645,30 @@ pub async fn judge_build(vector: &Vector, artifact: &str) -> Result<(), Failure> )); } } - if c.get("openSlot") + // Phase 1: "The client MAY use `extra.recentBlockhash` and + // `extra.recentSlot` ... If either hint is stale, the client MUST fetch a + // fresh value". The Rust kit takes the slot from its caller + // (`batchClient.openSlot`); an SDK that fetches the cluster slot or uses + // the hint is as conformant. Any slot the program's open-slot window + // accepts against the fixture cluster's slot is judged correct. + let cluster_slot = input["rpcFixtures"]["slot"] + .as_u64() + .filter(|_| operation == "deposit"); + if let Some(cluster) = cluster_slot { + let open = config.open_slot; + if open > cluster || cluster - open > pc::OPEN_SLOT_WINDOW { + return Err(fail_at( + "payload.channelConfig.openSlot", + Some(&json!(format!( + "a slot in [{}, {cluster}]", + cluster.saturating_sub(pc::OPEN_SLOT_WINDOW) + ))), + Some(&json!(open)), + "the channel must open at a slot inside the program's open-slot window of the cluster slot", + )); + } + } else if c + .get("openSlot") .and_then(Value::as_u64) .is_some_and(|slot| slot != config.open_slot) { @@ -1182,10 +1211,15 @@ pub mod fx { // ── chain state ── pub fn token_account(owner: &str, state: u8) -> Value { + token_account_holding(owner, state, 1_000_000_000) + } + + /// [`token_account`] holding `amount` base units. + pub fn token_account_holding(owner: &str, state: u8, amount: u64) -> Value { let mut data = Vec::with_capacity(165); data.extend_from_slice(pubkey(keys::MINT).as_ref()); data.extend_from_slice(pubkey(owner).as_ref()); - data.extend_from_slice(&1_000_000_000u64.to_le_bytes()); + data.extend_from_slice(&amount.to_le_bytes()); data.extend_from_slice(&[0u8; 36]); // delegate: None data.push(state); data.extend_from_slice(&[0u8; 12]); // is_native: None @@ -1285,6 +1319,8 @@ pub mod fx { MissingReceiver, /// The payer's return ATA is frozen (state 2). FrozenPayer, + /// The payer's ATA holds a single base unit, short of any deposit. + UnfundedPayer, } /// `rpcFixtures`: the mint, the settlement ATAs and, when given, the @@ -1306,7 +1342,12 @@ pub mod fx { if atas == Atas::MissingReceiver && owner == keys::X402_PAY_TO { continue; } - accounts.insert(ata(&owner), token_account(&owner, state)); + let amount = if atas == Atas::UnfundedPayer && owner == payer() { + 1 + } else { + 1_000_000_000 + }; + accounts.insert(ata(&owner), token_account_holding(&owner, state, amount)); } if let Some((config, account)) = channel { accounts.insert( diff --git a/rust/crates/conformance/src/realize/session.rs b/rust/crates/conformance/src/realize/session.rs index 32e16f7aa..4fc5da538 100644 --- a/rust/crates/conformance/src/realize/session.rs +++ b/rust/crates/conformance/src/realize/session.rs @@ -15,9 +15,10 @@ //! is the sponsor's key when `server.feePayer` is set. Nothing in the input //! is a precomputed verdict: the testee parses `credential` with its SDK's //! wire types and hands it to the SDK's server. -//! - build: `sessionOpenBuild` = `{ request, salt, server, challenge }`: +//! - build: `sessionOpenBuild` = `{ request, salt, deposit, server, challenge }`: //! `request` is the challenge's `SessionRequest`, `salt` the channel salt -//! the client's builder takes; `server` / `challenge` are for the judge +//! the client's builder takes, `deposit` the deposit its caller +//! authorizes; `server` / `challenge` are for the judge //! only. `signerSecretKey` is the payer, `sessionSignerSecretKey` the //! voucher key the client authorizes. //! @@ -34,12 +35,14 @@ use solana_hash::Hash; use solana_instruction::{AccountMeta, Instruction}; use solana_pay_kit::core::payment_channels as pc; use solana_pay_kit::core::store::{ - ChannelState, ChannelStore, MemoryChannelStore, CHANNEL_STATE_SCHEMA_VERSION, + ChannelState, ChannelStore, MemoryChannelStore, ObservedLifecycle, OnchainObservation, + CHANNEL_STATE_SCHEMA_VERSION, }; use solana_pay_kit::core::tx::{ComputeBudget, TxV1Mode, TxVersion}; use solana_pay_kit::mpp::client::session::{ create_payment_channel_session_opener, derive_payment_channel_open, - DerivePaymentChannelOpenParams, PaymentChannelOpenOptions, PaymentChannelSessionOpenOptions, + DerivePaymentChannelOpenParams, OpenBlockhash, PaymentChannelOpenOptions, + PaymentChannelSessionOpenOptions, SessionOpenAuthorization, }; use solana_pay_kit::mpp::protocol::intents::session::{ SessionAction, SessionAuthentication, SessionRequest, SignedVoucher, UsePayload, VoucherData, @@ -486,7 +489,7 @@ pub fn stored_channel(channel: &Value) -> Result { }; let highest = channel.get("highestVoucher"); let proof = channel.get("authentication").filter(|v| !v.is_null()); - Ok(ChannelState { + let mut state = ChannelState { channel_id: text("channelId")?, authorized_signer: text("authorizedSigner")?, deposit: number("escrowedAmount")?, @@ -537,7 +540,26 @@ pub fn stored_channel(channel: &Value) -> Result { lifecycle: None, schema_version: CHANNEL_STATE_SCHEMA_VERSION, extra: Default::default(), - }) + }; + // The record is the server's view of a channel it confirmed onchain just + // now: `status` and `closureStartedAt` are what that read showed. + let now = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .map_err(|e| e.to_string())? + .as_secs(); + let lifecycle = match (state.sealed, state.close_requested_at) { + (true, started_at) => ObservedLifecycle::Terminal { started_at }, + (false, Some(started_at)) => ObservedLifecycle::Closing { started_at }, + (false, None) => ObservedLifecycle::Open, + }; + state.record_onchain_observation( + OnchainObservation { + slot: None, + lifecycle, + }, + now, + ); + Ok(state) } /// A signed voucher JSON (`SignedVoucher` on the wire). @@ -737,9 +759,27 @@ async fn open_for_request(request: &SessionRequest, build: &OpenBuild) -> Result }; let session = MemorySigner::from_bytes(&keys::keypair_bytes(voucher_seed)).map_err(|e| e.to_string())?; + // The harness client deposits what the server suggests unless the case + // picks a deposit, and trusts the kit server's operator. + let deposit = match build.deposit { + Some(deposit) => deposit, + None => request + .suggested_deposit + .as_deref() + .or(request.minimum_deposit.as_deref()) + .ok_or("challenge without a deposit")? + .parse() + .map_err(|e| format!("suggestedDeposit: {e}"))?, + }; + let authorization = match request.method_details.operator.as_deref() { + Some(operator) => SessionOpenAuthorization::operator_signed( + deposit, + Pubkey::from_str(operator).map_err(|e| e.to_string())?, + ), + None => SessionOpenAuthorization::client_signed(deposit), + }; let open_options = PaymentChannelOpenOptions { salt: Some(SALT), - deposit: build.deposit, open_slot: build.open_slot, compute_budget: build .budget @@ -758,6 +798,7 @@ async fn open_for_request(request: &SessionRequest, build: &OpenBuild) -> Result request, payer: client(), authorized_signer: Pubkey::from_str(operator_key).map_err(|e| e.to_string())?, + authorization: &authorization, options: open_options.clone(), }) .map_err(|e| format!("derive open: {e}"))?; @@ -771,11 +812,15 @@ async fn open_for_request(request: &SessionRequest, build: &OpenBuild) -> Result ) } }; + // The kit server's challenge carries the pinned blockhash. + let blockhash = + OpenBlockhash::from_client_cluster(Hash::from_str(BLOCKHASH).map_err(|e| e.to_string())?); let opened = create_payment_channel_session_opener( request, &payer, Box::new(session), - None, + blockhash, + &authorization, PaymentChannelSessionOpenOptions { open: open_options, authentication, @@ -1593,6 +1638,9 @@ pub struct BuildRecipe { pub authorized: Authorized, /// Edits of the challenge `SessionRequest` JSON. pub edits: Vec, + /// The latest blockhash of the client's cluster (`rpcFixtures`), when it + /// is not the challenged one. + pub client_blockhash: Option<&'static str>, } pub fn build_input(recipe: &BuildRecipe) -> Result { @@ -1611,6 +1659,15 @@ pub fn build_input(recipe: &BuildRecipe) -> Result { "sessionOpenBuild": { "request": request, "salt": SALT.to_string(), + // The deposit the caller authorizes (draft-solana-session-00 + // leaves it to the client); the harness client takes the + // server's suggestion. + "deposit": recipe + .server + .suggested_deposit + .or(recipe.server.minimum_deposit) + .unwrap_or(1_000) + .to_string(), "server": recipe.server.json(), "challenge": { "id": CHALLENGE_ID, @@ -1622,6 +1679,9 @@ pub fn build_input(recipe: &BuildRecipe) -> Result { if recipe.server.sponsored { input["sessionServerFeePayerSecretKey"] = keys::secret_json(OPERATOR_SEED); } + if let Some(blockhash) = recipe.client_blockhash { + input["rpcFixtures"] = json!({ "recentBlockhash": blockhash }); + } Ok(input) } @@ -1683,11 +1743,19 @@ pub async fn build(input: &Value) -> Result { let payer = signer_from(input, "signerSecretKey")?; let session = signer_from(input, "sessionSignerSecretKey")?; let salt = u64_field(params, "salt")?; + let deposit = u64_field(params, "deposit")?.ok_or("sessionOpenBuild.deposit missing")?; + let fixtures = crate::fixture_rpc::Fixtures::from_input(input)?; + let (rpc, _log) = crate::fixture_rpc::rpc_client(&fixtures); + let blockhash = match OpenBlockhash::verify(&rpc, &request).await { + Ok(blockhash) => blockhash, + Err(e) => return Ok(reject_build(e.to_string())), + }; let opened = create_payment_channel_session_opener( &request, &payer, Box::new(session), - None, + blockhash, + &SessionOpenAuthorization::client_signed(deposit), PaymentChannelSessionOpenOptions { open: PaymentChannelOpenOptions { salt, diff --git a/rust/crates/conformance/src/realize/session_open.rs b/rust/crates/conformance/src/realize/session_open.rs index bb2840e9a..fa85f2062 100644 --- a/rust/crates/conformance/src/realize/session_open.rs +++ b/rust/crates/conformance/src/realize/session_open.rs @@ -15,8 +15,8 @@ use serde_json::{json, Value}; use solana_pay_kit::core::store::MemoryChannelStore; use solana_pay_kit::core::tx::{TxV1Mode, TxVersion}; use solana_pay_kit::mpp::client::session::{ - create_payment_channel_session_opener, PaymentChannelOpenOptions, - PaymentChannelSessionOpenOptions, + create_payment_channel_session_opener, OpenBlockhash, PaymentChannelOpenOptions, + PaymentChannelSessionOpenOptions, SessionOpenAuthorization, }; use solana_pay_kit::mpp::protocol::intents::session::{OpenPayload, SessionAction}; use solana_pay_kit::mpp::server::session::{SessionConfig, SessionServer, VoucherSigner}; @@ -104,11 +104,25 @@ async fn build_open(server_value: &Value) -> Result { .map_err(|e| e.to_string())?; let session = MemorySigner::from_bytes(&keys::keypair_bytes(SESSION_SIGNER_SEED)) .map_err(|e| e.to_string())?; + // The kit server's challenge carries the pinned blockhash. + let blockhash = OpenBlockhash::from_client_cluster( + BLOCKHASH.parse().map_err(|e| format!("blockhash: {e:?}"))?, + ); let opened = create_payment_channel_session_opener( &request, &payer, Box::new(session), - None, + blockhash, + // The harness client deposits what the server suggests. + &SessionOpenAuthorization::client_signed( + request + .suggested_deposit + .as_deref() + .or(request.minimum_deposit.as_deref()) + .ok_or("challenge without a deposit")? + .parse() + .map_err(|e| format!("suggestedDeposit: {e}"))?, + ), PaymentChannelSessionOpenOptions { open: PaymentChannelOpenOptions { salt: Some(SALT), diff --git a/rust/crates/conformance/src/realize/upto.rs b/rust/crates/conformance/src/realize/upto.rs index 3c3f21109..86324e84c 100644 --- a/rust/crates/conformance/src/realize/upto.rs +++ b/rust/crates/conformance/src/realize/upto.rs @@ -163,7 +163,9 @@ impl Route { if let Some(memo) = self.memo() { extra["memo"] = json!(memo); } - if let Some(versions) = &self.versions { + // What the server advertises: nothing for `[0]` (the kit's + // `advertised` rule), as for x402 exact. + if let Some(versions) = self.versions.as_ref().filter(|v| v.as_slice() != [0]) { extra["transactionVersions"] = json!(versions); } json!({ diff --git a/rust/crates/conformance/src/run/judge.rs b/rust/crates/conformance/src/run/judge.rs index ea0442206..eb801611d 100644 --- a/rust/crates/conformance/src/run/judge.rs +++ b/rust/crates/conformance/src/run/judge.rs @@ -91,8 +91,47 @@ fn expect_same( } } -/// `judgeVector`: the vector's `expect` block against the result. +/// `judgeVector`: the vector's `expect` block against the result. A result +/// that misses the primary verdict passes when it matches one of the +/// verdicts the specs also allow (`expect.alsoConformant`: an outcome and, +/// for a reject, its code). An accepted build is still judged on its +/// artifact by the driver. pub fn judge_expect(vector: &Vector, result: &Value) -> Result { + let primary = judge_primary(vector, result); + let Err(mut failure) = primary else { + return primary; + }; + let Some(alternatives) = vector.expect()["alsoConformant"].as_array() else { + return Err(failure); + }; + let outcome = result["outcome"].as_str().unwrap_or_default(); + let code = result.get("rejectCode").and_then(Value::as_str); + let matched = alternatives.iter().any(|alt| { + alt["outcome"].as_str() == Some(outcome) + && (outcome != "reject" || alt["rejectCode"].as_str() == code) + }); + if matched && result.get("id").and_then(Value::as_str) == Some(vector.id.as_str()) { + return Ok(Verdict::Pass); + } + failure.message = format!( + "{}\n(also conformant: {}; {})", + failure.message, + alternatives + .iter() + .map(|alt| match alt["rejectCode"].as_str() { + Some(code) => format!("reject {code}"), + None => alt["outcome"].as_str().unwrap_or_default().to_string(), + }) + .collect::>() + .join(", "), + vector.expect()["alsoConformantReason"] + .as_str() + .unwrap_or_default() + ); + Err(failure) +} + +fn judge_primary(vector: &Vector, result: &Value) -> Result { let actual_id = result.get("id"); if actual_id.and_then(Value::as_str) != Some(vector.id.as_str()) { return Err(Failure::at( @@ -906,6 +945,32 @@ mod tests { ); } + #[test] + fn also_conformant_verdicts_pass_and_others_do_not() { + // Primary reject channel-state; payload-type is also conformant. + let v = vector("batch-verify-voucher-server-mode-config-reject"); + let primary = json!({"id": v.id, "outcome": "reject", "rejectCode": "channel-state"}); + assert_eq!(judge_expect(&v, &primary).unwrap(), Verdict::Pass); + let alternative = json!({"id": v.id, "outcome": "reject", "rejectCode": "payload-type"}); + assert_eq!(judge_expect(&v, &alternative).unwrap(), Verdict::Pass); + let other = json!({"id": v.id, "outcome": "reject", "rejectCode": "invalid-payload"}); + let failure = judge_expect(&v, &other).unwrap_err(); + assert!(failure + .message + .contains("also conformant: reject payload-type")); + let accepted = json!({"id": v.id, "outcome": "accept"}); + assert!(judge_expect(&v, &accepted).is_err()); + // Primary reject; accept is also conformant (sponsor fee policy). + let v = vector("x402-exact-verify-priority-fee-over-cap-reject"); + let accepted = json!({"id": v.id, "outcome": "accept"}); + assert_eq!(judge_expect(&v, &accepted).unwrap(), Verdict::Pass); + let wrong = json!({"id": v.id, "outcome": "reject", "rejectCode": "invalid-payload"}); + assert!(judge_expect(&v, &wrong).is_err()); + // An alternative never excuses a result for another vector. + let foreign = json!({"id": "another-vector", "outcome": "accept"}); + assert!(judge_expect(&v, &foreign).is_err()); + } + #[test] fn reject_code_is_pinned() { let v = vector("charge-verify-wrong-amount-reject"); diff --git a/rust/crates/conformance/src/run/vectors.rs b/rust/crates/conformance/src/run/vectors.rs index e853fb4ff..301c0df72 100644 --- a/rust/crates/conformance/src/run/vectors.rs +++ b/rust/crates/conformance/src/run/vectors.rs @@ -236,12 +236,31 @@ pub fn validate(vector: &Value) -> Result<(), String> { { return Err("expect.outcome must be accept or reject".into()); } + let known: Vec<&str> = RejectCode::ALL.iter().map(|c| c.as_str()).collect(); if let Some(code) = expect.get("rejectCode") { - let known: Vec<&str> = RejectCode::ALL.iter().map(|c| c.as_str()).collect(); if !one_of(code, &known) { return Err("expect.rejectCode is not in the shared vocabulary".into()); } } + if let Some(alternatives) = expect.get("alsoConformant") { + let valid = alternatives.as_array().is_some_and(|alts| { + !alts.is_empty() + && alts.iter().all(|alt| match alt["outcome"].as_str() { + Some("accept") => alt.get("rejectCode").is_none(), + Some("reject") => alt.get("rejectCode").is_some_and(|c| one_of(c, &known)), + _ => false, + }) + }); + if !valid + || !expect + .get("alsoConformantReason") + .is_some_and(Value::is_string) + { + return Err( + "expect.alsoConformant must be a non-empty array of {outcome: accept} / {outcome: reject, rejectCode} with an alsoConformantReason".into(), + ); + } + } Ok(()) } diff --git a/rust/crates/harness-bins/Cargo.toml b/rust/crates/harness-bins/Cargo.toml index ea8bf8d59..a78501f0e 100644 --- a/rust/crates/harness-bins/Cargo.toml +++ b/rust/crates/harness-bins/Cargo.toml @@ -39,3 +39,11 @@ path = "src/bin/x402_harness_upto_client.rs" [[bin]] name = "x402_harness_upto_server" path = "src/bin/x402_harness_upto_server.rs" + +[[bin]] +name = "x402_harness_batch_client" +path = "src/bin/x402_harness_batch_client.rs" + +[[bin]] +name = "x402_harness_batch_server" +path = "src/bin/x402_harness_batch_server.rs" diff --git a/rust/crates/harness-bins/src/bin/mpp_harness_client.rs b/rust/crates/harness-bins/src/bin/mpp_harness_client.rs index d05ee6d59..becf8ea5d 100644 --- a/rust/crates/harness-bins/src/bin/mpp_harness_client.rs +++ b/rust/crates/harness-bins/src/bin/mpp_harness_client.rs @@ -22,7 +22,7 @@ fn write_stdout_line(line: &str) { } } use solana_pay_kit::mpp::client::{ - build_credential_header_with_options, BuildChargeTransactionOptions, + build_credential_header_with_options, BuildChargeTransactionOptions, PayerFundedAtaCreation, }; use solana_pay_kit::mpp::solana_rpc_client::rpc_client::RpcClient; use solana_pay_kit::mpp::{ @@ -58,10 +58,12 @@ async fn main() -> Result<(), Box> { let rpc = RpcClient::new(rpc_url); // The client's configuration: the cluster it pays on, the amount it was // asked to pay and who it pays. The kit refuses a challenge that - // disagrees with any of them. Split ATA rent is funded from the client - // wallet on servers without a fee payer, which is the kit's default (the - // spec requires it). + // disagrees with any of them. The harness server is trusted to name split + // recipients, so split ATA rent is funded from the client wallet on + // servers without a fee payer (the spec requires it; the kit declines it + // unless asked). let options = BuildChargeTransactionOptions { + payer_funded_ata_creation: PayerFundedAtaCreation::Include, expected_network: env::var("MPP_HARNESS_NETWORK").ok(), max_amount_base_units: env::var("MPP_HARNESS_AMOUNT") .ok() diff --git a/rust/crates/harness-bins/src/bin/x402_harness_batch_client.rs b/rust/crates/harness-bins/src/bin/x402_harness_batch_client.rs new file mode 100644 index 000000000..4b760e53a --- /dev/null +++ b/rust/crates/harness-bins/src/bin/x402_harness_batch_client.rs @@ -0,0 +1,181 @@ +//! Interop client for x402 `batch-settlement`. +//! +//! Opens `X402_HARNESS_BATCH_CHANNELS` channels against the server (each paid +//! by its `deposit`, which carries the first voucher), pays a second request on +//! the first channel with a plain voucher, then asks the server to redeem +//! every channel (`POST /redeem`) and reports the deposit and redemption +//! signatures for the runner to check on chain. + +use std::{collections::HashMap, env}; + +use serde_json::json; +use solana_pay_kit::solana_keychain::memory::MemorySigner; +use solana_pay_kit::x402::{ + client::batch_settlement::{ + build_deposit, encode_payment_header, parse_challenge, resolve_terms, BatchChannel, + }, + protocol::schemes::batch_settlement::{ + BatchPayload, BatchRequirements, BatchSettlementResponse, BatchVoucher, + }, + PAYMENT_RESPONSE_HEADER, PAYMENT_SIGNATURE_HEADER, +}; +use solana_rpc_client::rpc_client::RpcClient; + +type BoxError = Box; + +const DEFAULT_CHANNELS: u8 = 1; +/// Requests each deposit escrows, so a channel never needs a top-up here. +const DEPOSIT_REQUESTS: u64 = 10; + +#[tokio::main] +async fn main() -> Result<(), BoxError> { + let target_url = read_required_env("X402_HARNESS_TARGET_URL")?; + let rpc_url = read_required_env("X402_HARNESS_RPC_URL")?; + let signer = read_memory_signer("X402_HARNESS_CLIENT_SECRET_KEY")?; + let channels: u8 = env::var("X402_HARNESS_BATCH_CHANNELS") + .ok() + .map(|v| v.parse()) + .transpose()? + .unwrap_or(DEFAULT_CHANNELS); + + let http = reqwest::Client::new(); + let rpc = RpcClient::new(rpc_url); + + let challenge = http.get(&target_url).send().await?; + let headers = response_headers(challenge.headers())?; + let body = challenge.text().await?; + let (requirements, _) = parse_challenge(&headers, Some(&body)) + .ok_or("server did not return a supported batch-settlement challenge")?; + let terms = resolve_terms(&rpc, &requirements, None)?; + + let mut deposits = Vec::new(); + let mut first: Option<(BatchChannel, BatchVoucher)> = None; + let mut last_status = 0u16; + for _ in 0..channels { + let blockhash = rpc.get_latest_blockhash()?; + let open_slot = rpc.get_slot()?; + let (channel, payload) = build_deposit( + &signer, + &requirements, + &terms, + terms.amount * DEPOSIT_REQUESTS, + blockhash, + open_slot, + ) + .await?; + let voucher = submitted_voucher(&payload)?; + let (status, response) = pay(&http, &target_url, &requirements, payload).await?; + last_status = status; + let response = response.ok_or_else(|| format!("deposit answered {status}"))?; + deposits.push(response.transaction.clone()); + if first.is_none() { + let mut channel = channel; + channel.apply_payment_response(&response, &requirements, &voucher)?; + first = Some((channel, voucher)); + } + } + + // A second, offchain voucher on the first channel. + if let Some((channel, _)) = &first { + let payload = channel.voucher_payload(&signer, terms.amount).await?; + let (status, response) = pay(&http, &target_url, &requirements, payload).await?; + last_status = status; + response.ok_or_else(|| format!("voucher answered {status}"))?; + } + + let redeem_url = redeem_url(&target_url)?; + let redeemed = http.post(&redeem_url).send().await?; + let redeem_status = redeemed.status(); + let redemption: serde_json::Value = redeemed.json().await?; + let ok = last_status == 200 && redeem_status.is_success(); + + println!( + "{}", + serde_json::to_string(&json!({ + "type": "result", + "implementation": "rust", + "role": "client", + "ok": ok, + "status": if ok { 200 } else { redeem_status.as_u16() }, + "responseHeaders": HashMap::::new(), + "responseBody": { + "ok": ok, + "paid": ok, + "deposits": deposits, + "redemption": redemption, + }, + "settlement": deposits.first(), + }))? + ); + Ok(()) +} + +/// Send one paid request; returns the status and the decoded `PAYMENT-RESPONSE`. +async fn pay( + http: &reqwest::Client, + url: &str, + requirements: &BatchRequirements, + payload: BatchPayload, +) -> Result<(u16, Option), BoxError> { + let header = encode_payment_header(requirements, payload)?; + let response = http + .get(url) + .header(PAYMENT_SIGNATURE_HEADER, header) + .send() + .await?; + let status = response.status().as_u16(); + let settlement = response + .headers() + .get(PAYMENT_RESPONSE_HEADER) + .and_then(|value| value.to_str().ok()) + .map(decode_settlement) + .transpose()?; + Ok((status, settlement.filter(|s| s.success))) +} + +fn decode_settlement(value: &str) -> Result { + let bytes = base64::Engine::decode(&base64::engine::general_purpose::STANDARD, value)?; + Ok(serde_json::from_slice(&bytes)?) +} + +fn submitted_voucher(payload: &BatchPayload) -> Result { + match payload { + BatchPayload::Deposit { + voucher: Some(voucher), + .. + } => Ok(voucher.clone()), + _ => Err("a client-signed deposit carries its first voucher".into()), + } +} + +/// `POST /redeem` on the server behind `target_url` (the proxy forwards it). +fn redeem_url(target_url: &str) -> Result { + let after_scheme = target_url + .find("://") + .map(|i| i + 3) + .ok_or("target URL has no scheme")?; + let path_start = target_url[after_scheme..] + .find('/') + .map(|i| after_scheme + i) + .unwrap_or(target_url.len()); + Ok(format!("{}/redeem", &target_url[..path_start])) +} + +fn response_headers( + headers: &reqwest::header::HeaderMap, +) -> Result, BoxError> { + headers + .iter() + .map(|(name, value)| Ok((name.as_str().to_string(), value.to_str()?.to_string()))) + .collect() +} + +fn read_required_env(name: &str) -> Result { + env::var(name).map_err(|_| format!("{name} is required").into()) +} + +fn read_memory_signer(name: &str) -> Result { + let raw = read_required_env(name)?; + let bytes: Vec = serde_json::from_str(&raw)?; + Ok(MemorySigner::from_bytes(&bytes)?) +} diff --git a/rust/crates/harness-bins/src/bin/x402_harness_batch_server.rs b/rust/crates/harness-bins/src/bin/x402_harness_batch_server.rs new file mode 100644 index 000000000..301296083 --- /dev/null +++ b/rust/crates/harness-bins/src/bin/x402_harness_batch_server.rs @@ -0,0 +1,268 @@ +//! Interop server for x402 `batch-settlement`. +//! +//! Serves the paid resource through the scheme's verify / reserve / commit +//! steps (as the axum gate does), remembers every channel it served, and on +//! `POST /redeem` runs its out-of-band redemption over all of them: one +//! `claim` pass then one `settle` (distribute) pass. Redemption is built as +//! transaction v1, so the claim and distribute pack up to the version-1 +//! capacity. + +use std::{ + collections::{BTreeSet, HashMap}, + env, + io::{BufRead, BufReader, Write}, + net::{TcpListener, TcpStream}, + sync::{Arc, Mutex}, + thread, +}; + +use serde_json::json; +use solana_pay_kit::solana_keychain::{memory::MemorySigner, TransactionSigner}; +use solana_pay_kit::x402::{ + server::{BatchAccess, BatchConfig, X402BatchSettlement}, + PAYMENT_SIGNATURE_HEADER, +}; + +type BoxError = Box; + +const DEFAULT_RESOURCE_PATH: &str = "/protected"; +const HEALTH_PATH: &str = "/health"; +const REDEEM_PATH: &str = "/redeem"; +const TOKEN_DECIMALS: u8 = 6; + +struct BatchHarnessState { + batch: X402BatchSettlement, + price: String, + resource_path: String, + /// Channels this server served, in the order it first saw them. + channels: Mutex>, + runtime: tokio::runtime::Runtime, +} + +fn main() -> Result<(), BoxError> { + let state = Arc::new(read_state()?); + let listener = TcpListener::bind("127.0.0.1:0")?; + let port = listener.local_addr()?.port(); + + println!( + "{}", + serde_json::to_string(&json!({ + "type": "ready", + "implementation": "rust", + "role": "server", + "port": port, + "capabilities": ["batch-settlement"], + }))? + ); + + for stream in listener.incoming() { + match stream { + Ok(stream) => { + let state = Arc::clone(&state); + thread::spawn(move || { + if let Err(error) = handle_connection(stream, &state) { + eprintln!("harness rust batch server error: {error}"); + } + }); + } + Err(error) => eprintln!("harness rust batch server accept error: {error}"), + } + } + Ok(()) +} + +fn read_state() -> Result { + let rpc_url = read_required_env("X402_HARNESS_RPC_URL")?; + // Surfpool runs a payment-channels build whose treasury owner is patched + // to the mainnet constant, so the cluster label is `localnet`, not devnet + // (see the upto harness server). + let cluster = "localnet".to_string(); + let mint = env::var("X402_HARNESS_MINT") + .unwrap_or_else(|_| "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU".to_string()); + let pay_to = read_required_env("X402_HARNESS_PAY_TO")?; + let fee_payer: Arc = + Arc::new(read_memory_signer("X402_HARNESS_FACILITATOR_SECRET_KEY")?); + let price = + normalize_price(&env::var("X402_HARNESS_PRICE").unwrap_or_else(|_| "0.001".into()))?; + let resource_path = env::var("X402_HARNESS_RESOURCE_PATH") + .unwrap_or_else(|_| DEFAULT_RESOURCE_PATH.to_string()); + + let mut config = BatchConfig::new(pay_to, cluster, fee_payer); + config.currency = mint; + config.decimals = TOKEN_DECIMALS; + config.rpc_url = Some(rpc_url); + config.resource = resource_path.clone(); + config.description = Some("Surfpool-backed batch-settlement endpoint".to_string()); + config.program_id = env::var("PAYMENT_CHANNELS_PROGRAM_ID").ok(); + let batch = X402BatchSettlement::new(config)? + // Accept and advertise version 1, and build redemptions as version 1. + // Surfpool executes version 1 but does not expose the `enable_tx_v1` + // feature account, so `Auto` would read it as inactive. + .with_tx_v1(solana_pay_kit::core::tx::TxV1Mode::On); + + Ok(BatchHarnessState { + batch, + price, + resource_path, + channels: Mutex::new(BTreeSet::new()), + runtime: tokio::runtime::Runtime::new()?, + }) +} + +fn handle_connection(mut stream: TcpStream, state: &BatchHarnessState) -> Result<(), BoxError> { + let mut reader = BufReader::new(stream.try_clone()?); + let mut request_line = String::new(); + reader.read_line(&mut request_line)?; + if request_line.trim().is_empty() { + return Ok(()); + } + let mut headers = HashMap::new(); + loop { + let mut line = String::new(); + reader.read_line(&mut line)?; + let trimmed = line.trim_end_matches(['\r', '\n']); + if trimmed.is_empty() { + break; + } + if let Some((name, value)) = trimmed.split_once(':') { + headers.insert(name.to_ascii_lowercase(), value.trim().to_string()); + } + } + let mut parts = request_line.split_whitespace(); + let method = parts.next().unwrap_or_default(); + let path = parts.next().unwrap_or_default(); + + match (method, path) { + ("GET", HEALTH_PATH) => write_json(&mut stream, 200, &[], &json!({ "ok": true })), + ("POST", REDEEM_PATH) => match redeem(state) { + Ok(body) => write_json(&mut stream, 200, &[], &body), + Err(error) => write_json( + &mut stream, + 500, + &[], + &json!({ "error": "redeem_failed", "message": error.to_string() }), + ), + }, + ("GET", path) if path == state.resource_path => { + match headers.get(&PAYMENT_SIGNATURE_HEADER.to_ascii_lowercase()) { + Some(header) => match serve(state, header) { + Ok((name, value)) => write_json( + &mut stream, + 200, + &[(name.as_str(), value.as_str())], + &json!({ "ok": true, "paid": true }), + ), + Err(error) => challenge( + &mut stream, + state, + &json!({ "error": "payment_invalid", "message": error.to_string() }), + ), + }, + None => challenge(&mut stream, state, &json!({ "error": "payment_required" })), + } + } + _ => write_json(&mut stream, 404, &[], &json!({ "error": "not_found" })), + } +} + +/// Verify, reserve, serve and commit one paid request, returning the +/// `PAYMENT-RESPONSE` header. +fn serve(state: &BatchHarnessState, header: &str) -> Result<(String, String), BoxError> { + let access = state + .runtime + .block_on(state.batch.verify_and_reserve_payment(header, &state.price))?; + let settlement = match access { + BatchAccess::Serve(outcome) | BatchAccess::Resume(outcome) => { + let channel_id = outcome.channel_id.clone(); + state + .runtime + .block_on(state.batch.mark_handler_succeeded(&outcome))?; + let settlement = state + .runtime + .block_on(state.batch.finish_commit(&outcome))?; + state + .channels + .lock() + .map_err(|_| "channel set poisoned")? + .insert(channel_id); + settlement + } + BatchAccess::Replay(settlement, _) => settlement, + BatchAccess::InProgress => return Err("authorization in progress".into()), + BatchAccess::Control(_) => return Err("refunds are not part of this scenario".into()), + }; + Ok(state.batch.settlement_header(&settlement)?) +} + +/// Redeem every served channel: claim its latest voucher, then distribute. +fn redeem(state: &BatchHarnessState) -> Result { + let channels: Vec = state + .channels + .lock() + .map_err(|_| "channel set poisoned")? + .iter() + .cloned() + .collect(); + let claims = state.runtime.block_on(state.batch.claim(&channels))?; + let distributes = state.runtime.block_on(state.batch.settle(&channels))?; + Ok(json!({ + "channels": channels, + "claims": claims, + "distributes": distributes, + })) +} + +fn challenge( + stream: &mut TcpStream, + state: &BatchHarnessState, + body: &serde_json::Value, +) -> Result<(), BoxError> { + let (name, value) = state + .batch + .payment_required_header(&state.price, Some(&state.resource_path))?; + write_json(stream, 402, &[(name.as_str(), value.as_str())], body) +} + +fn write_json( + stream: &mut TcpStream, + status: u16, + headers: &[(&str, &str)], + body: &serde_json::Value, +) -> Result<(), BoxError> { + let body = serde_json::to_vec(body)?; + let reason = match status { + 200 => "OK", + 402 => "Payment Required", + 404 => "Not Found", + _ => "Internal Server Error", + }; + write!(stream, "HTTP/1.1 {status} {reason}\r\n")?; + write!(stream, "content-type: application/json\r\n")?; + write!(stream, "content-length: {}\r\n", body.len())?; + write!(stream, "connection: close\r\n")?; + for (name, value) in headers { + write!(stream, "{name}: {value}\r\n")?; + } + write!(stream, "\r\n")?; + stream.write_all(&body)?; + stream.flush()?; + Ok(()) +} + +fn read_required_env(name: &str) -> Result { + env::var(name).map_err(|_| format!("{name} is required").into()) +} + +fn read_memory_signer(name: &str) -> Result { + let raw = read_required_env(name)?; + let bytes: Vec = serde_json::from_str(&raw)?; + Ok(MemorySigner::from_bytes(&bytes)?) +} + +fn normalize_price(price: &str) -> Result { + let amount = price.trim().strip_prefix('$').unwrap_or(price.trim()); + if amount.is_empty() || !amount.chars().all(|c| c.is_ascii_digit() || c == '.') { + return Err(format!("invalid price: {price}").into()); + } + Ok(amount.to_string()) +} diff --git a/rust/crates/harness-bins/src/bin/x402_harness_server.rs b/rust/crates/harness-bins/src/bin/x402_harness_server.rs index 1cd7f1755..78fe3ebfa 100644 --- a/rust/crates/harness-bins/src/bin/x402_harness_server.rs +++ b/rust/crates/harness-bins/src/bin/x402_harness_server.rs @@ -146,7 +146,11 @@ fn read_state() -> Result max_age: Some(60), fee_payer_key: Some(fee_payer.pubkey().to_string()), payment_identifier: PaymentIdentifierPolicy::NotAdvertised, - })?, + })? + // Accept and advertise version 1, as the reference facilitators do. + // Surfpool executes version 1 but does not expose the `enable_tx_v1` + // feature account, so `Auto` would read it as inactive. + .with_tx_v1(solana_pay_kit::core::tx::TxV1Mode::On), fee_payer, routes, settlement_header: env::var("X402_HARNESS_SETTLEMENT_HEADER") diff --git a/rust/crates/harness-bins/src/bin/x402_harness_upto_server.rs b/rust/crates/harness-bins/src/bin/x402_harness_upto_server.rs index 37bed5da6..1ab841f05 100644 --- a/rust/crates/harness-bins/src/bin/x402_harness_upto_server.rs +++ b/rust/crates/harness-bins/src/bin/x402_harness_upto_server.rs @@ -123,7 +123,11 @@ fn read_state( withdraw_delay: 900, fee_payer_signer, receiver_authorizer_signer: Some(receiver_authorizer_signer), - })?; + })? + // Accept and advertise version 1, as the reference facilitators do. + // Surfpool executes version 1 but does not expose the `enable_tx_v1` + // feature account, so `Auto` would read it as inactive. + .with_tx_v1(solana_pay_kit::core::tx::TxV1Mode::On); Ok(UptoHarnessState { upto, diff --git a/rust/crates/kit/Cargo.toml b/rust/crates/kit/Cargo.toml index 656c3c4b6..459237ae1 100644 --- a/rust/crates/kit/Cargo.toml +++ b/rust/crates/kit/Cargo.toml @@ -193,12 +193,12 @@ async-trait = "0.1" redis = { version = "0.32.5", optional = true, features = ["tokio-rustls-comp", "connection-manager"] } # OpenTelemetry (feature `otel`) — optional. -opentelemetry = { version = "0.31", optional = true } -opentelemetry_sdk = { version = "0.31", features = ["logs"], optional = true } -opentelemetry-otlp = { version = "0.31", default-features = false, features = ["http-proto", "reqwest-blocking-client", "trace", "metrics", "logs"], optional = true } -opentelemetry-appender-tracing = { version = "0.31", optional = true } -opentelemetry-semantic-conventions = { version = "0.31", optional = true } -tracing-opentelemetry = { version = "0.32", optional = true } +opentelemetry = { version = "0.33", optional = true } +opentelemetry_sdk = { version = "0.33", features = ["logs"], optional = true } +opentelemetry-otlp = { version = "0.33", default-features = false, features = ["http-proto", "reqwest-blocking-client", "trace", "metrics", "logs"], optional = true } +opentelemetry-appender-tracing = { version = "0.33", optional = true } +opentelemetry-semantic-conventions = { version = "0.33", optional = true } +tracing-opentelemetry = { version = "0.34", optional = true } tracing-subscriber = { version = "0.3", features = ["env-filter"], optional = true } # Errors diff --git a/rust/crates/kit/examples/vector_runner.rs b/rust/crates/kit/examples/vector_runner.rs index d66eabf02..57e96b175 100644 --- a/rust/crates/kit/examples/vector_runner.rs +++ b/rust/crates/kit/examples/vector_runner.rs @@ -43,6 +43,7 @@ use solana_pay_kit::core::store::{ use solana_pay_kit::core::tx::{accepted_versions, TxVersion}; use solana_pay_kit::mpp::client::{ build_charge_transaction_with_options, BuildChargeTransactionOptions, ComputeBudgetOptions, + PayerFundedAtaCreation, }; use solana_pay_kit::mpp::protocol::core::{base64url_decode, compute_challenge_id, Base64UrlJson}; use solana_pay_kit::mpp::protocol::intents::session::{ @@ -335,6 +336,9 @@ async fn charge_build(input: &Value) -> Result { let mut options = BuildChargeTransactionOptions { external_id: charge.external_id.clone(), max_tx_version: signer_max_version(input)?, + // The vectors pin the spec's client-paid shape, which includes split + // ATA creation (RULINGS C5); the kit declines it by default. + payer_funded_ata_creation: PayerFundedAtaCreation::Include, ..Default::default() }; let mut budget = ComputeBudgetOptions::default(); diff --git a/rust/crates/kit/examples/vector_runner/session.rs b/rust/crates/kit/examples/vector_runner/session.rs index d62dcf023..5ae6ebde1 100644 --- a/rust/crates/kit/examples/vector_runner/session.rs +++ b/rust/crates/kit/examples/vector_runner/session.rs @@ -21,12 +21,13 @@ use std::str::FromStr; use serde_json::{json, Map, Value}; use solana_pay_kit::core::store::{ - ChannelState, ChannelStore, MemoryChannelStore, ProcessedUse, CHANNEL_STATE_SCHEMA_VERSION, + ChannelState, ChannelStore, MemoryChannelStore, ObservedLifecycle, OnchainObservation, + ProcessedUse, CHANNEL_STATE_SCHEMA_VERSION, }; use solana_pay_kit::core::tx::{TxV1Mode, TxVersion}; use solana_pay_kit::mpp::client::session::{ - create_payment_channel_session_opener, PaymentChannelOpenOptions, - PaymentChannelSessionOpenOptions, + create_payment_channel_session_opener, OpenBlockhash, PaymentChannelOpenOptions, + PaymentChannelSessionOpenOptions, SessionOpenAuthorization, }; use solana_pay_kit::mpp::protocol::intents::session::{ SessionAction, SessionAuthentication, SessionRequest, SignedVoucher, UsePayload, @@ -232,7 +233,7 @@ fn stored_channel(channel: &Value) -> Result { }; let highest = channel.get("highestVoucher"); let proof = channel.get("authentication").filter(|v| !v.is_null()); - Ok(ChannelState { + let mut state = ChannelState { channel_id: text("channelId")?, authorized_signer: text("authorizedSigner")?, deposit: number("escrowedAmount")?, @@ -283,7 +284,26 @@ fn stored_channel(channel: &Value) -> Result { lifecycle: None, schema_version: CHANNEL_STATE_SCHEMA_VERSION, extra: Default::default(), - }) + }; + // The record is the server's view of a channel it confirmed onchain just + // now: `status` and `closureStartedAt` are what that read showed. + let now = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .map_err(|e| e.to_string())? + .as_secs(); + let lifecycle = match (state.sealed, state.close_requested_at) { + (true, started_at) => ObservedLifecycle::Terminal { started_at }, + (false, Some(started_at)) => ObservedLifecycle::Closing { started_at }, + (false, None) => ObservedLifecycle::Open, + }; + state.record_onchain_observation( + OnchainObservation { + slot: None, + lifecycle, + }, + now, + ); + Ok(state) } /// The shared code for a kit session server error (mirrors `code_for` in @@ -548,11 +568,21 @@ async fn build(input: &Value) -> Result { .map_err(|e| refuse(format!("invalid challenge: {e}")))?; let payer = signer_from(input, "signerSecretKey")?; let session = signer_from(input, "sessionSignerSecretKey")?; + let rpc_url = input + .get("rpcUrl") + .and_then(Value::as_str) + .ok_or("driver did not inject input.rpcUrl")?; + let rpc = solana_rpc_client::rpc_client::RpcClient::new(rpc_url.to_string()); + let blockhash = OpenBlockhash::verify(&rpc, &request) + .await + .map_err(|e| refuse(e.to_string()))?; + let deposit = u64_field(params, "deposit")?.ok_or("sessionOpenBuild.deposit missing")?; let opened = create_payment_channel_session_opener( &request, &payer, Box::new(session), - None, + blockhash, + &SessionOpenAuthorization::client_signed(deposit), PaymentChannelSessionOpenOptions { open: PaymentChannelOpenOptions { salt: u64_field(params, "salt")?, diff --git a/rust/crates/kit/src/client/mod.rs b/rust/crates/kit/src/client/mod.rs index e84562085..e3f63296f 100644 --- a/rust/crates/kit/src/client/mod.rs +++ b/rust/crates/kit/src/client/mod.rs @@ -156,8 +156,10 @@ impl PayKitClient { } let origin = response_url.origin().ascii_serialization(); let headers = response_headers(response.headers()); - let body = response.bytes().await?; - let body = std::str::from_utf8(&body).ok(); + let body = read_challenge_body(response).await?; + let body = body + .as_deref() + .and_then(|body| std::str::from_utf8(body).ok()); let (offers, mut rejections) = self.collect_offers(&headers, body, &origin); if offers.is_empty() { return if rejections.is_empty() { @@ -286,6 +288,31 @@ impl PayKitClient { } } +/// Largest 402 body the client reads, after content decoding. Only x402 v1 +/// carries its offers in the body, and a challenge set is a few KiB; a body +/// past this is dropped unread and the offers in the headers still apply. +const MAX_CHALLENGE_BODY_BYTES: usize = 64 * 1024; + +/// The 402 body, or `None` when it is larger than +/// [`MAX_CHALLENGE_BODY_BYTES`]. Counting decoded chunks bounds a compressed +/// body by what it inflates to, not by what crossed the wire. +async fn read_challenge_body(mut response: Response) -> Result>, reqwest::Error> { + if response + .content_length() + .is_some_and(|length| length > MAX_CHALLENGE_BODY_BYTES as u64) + { + return Ok(None); + } + let mut body = Vec::new(); + while let Some(chunk) = response.chunk().await? { + if body.len() + chunk.len() > MAX_CHALLENGE_BODY_BYTES { + return Ok(None); + } + body.extend_from_slice(&chunk); + } + Ok(Some(body)) +} + /// Builder for [`PayKitClient`]. #[derive(Default)] pub struct PayKitClientBuilder { @@ -1452,6 +1479,120 @@ mod tests { task.abort(); } + /// A response body that never ends. + struct EndlessBody; + + impl http_body::Body for EndlessBody { + type Data = axum::body::Bytes; + type Error = std::convert::Infallible; + + fn poll_frame( + self: std::pin::Pin<&mut Self>, + _cx: &mut std::task::Context<'_>, + ) -> std::task::Poll, Self::Error>>> { + std::task::Poll::Ready(Some(Ok(http_body::Frame::data( + axum::body::Bytes::from_static(&[b' '; 16 * 1024]), + )))) + } + } + + /// Serve a 402 whose body is `body`, plus the x402 offer in the + /// `PAYMENT-REQUIRED` header when `header` is set. + async fn challenge_body_server( + header: Option, + body: fn() -> axum::body::Body, + ) -> (String, Arc) { + let saw_payment = Arc::new(AtomicBool::new(false)); + let seen = saw_payment.clone(); + let app = Router::new().route( + "/report", + get(move |headers: HeaderMap| { + let header = header.clone(); + let seen = seen.clone(); + async move { + if headers.contains_key("payment-signature") { + seen.store(true, Ordering::SeqCst); + return (StatusCode::OK, "paid").into_response(); + } + let mut response = axum::response::Response::new(body()); + *response.status_mut() = StatusCode::PAYMENT_REQUIRED; + if let Some(header) = header { + response + .headers_mut() + .insert("payment-required", header.parse().unwrap()); + } + response + } + }), + ); + (format!("{}/report", serve(app).await), saw_payment) + } + + async fn x402_test_client() -> PayKitClient { + PayKitClient::builder() + .signer(test_signer()) + .rpc_url(live_rpc().await) + .accept([ClientProtocol::X402]) + .build() + .unwrap() + } + + fn endless() -> axum::body::Body { + axum::body::Body::new(EndlessBody) + } + + #[tokio::test] + async fn an_endless_challenge_body_is_not_buffered() { + let (url, saw_payment) = challenge_body_server(None, endless).await; + let client = x402_test_client().await; + let result = + tokio::time::timeout(std::time::Duration::from_secs(10), client.get(url).send()) + .await + .expect("the client stops reading an oversized 402 body"); + assert!(matches!(result, Err(ClientError::NoSupportedChallenge))); + assert!(!saw_payment.load(Ordering::SeqCst)); + } + + #[tokio::test] + async fn header_offers_are_paid_past_an_oversized_body() { + let (url, saw_payment) = + challenge_body_server(Some(x402_challenge_header()), endless).await; + let client = x402_test_client().await; + let response = + tokio::time::timeout(std::time::Duration::from_secs(10), client.get(url).send()) + .await + .expect("the client stops reading an oversized 402 body") + .unwrap(); + assert_eq!(response.status(), StatusCode::OK); + assert!(saw_payment.load(Ordering::SeqCst)); + } + + #[tokio::test] + async fn an_oversized_body_offer_is_ignored_and_a_small_one_is_paid() { + fn body_offer(padding: usize) -> axum::body::Body { + let header = x402_challenge_header(); + let decoded = base64::engine::general_purpose::STANDARD + .decode(header) + .unwrap(); + let mut envelope: serde_json::Value = serde_json::from_slice(&decoded).unwrap(); + envelope["padding"] = serde_json::json!(" ".repeat(padding)); + axum::body::Body::from(serde_json::to_vec(&envelope).unwrap()) + } + let (url, saw_payment) = challenge_body_server(None, || body_offer(0)).await; + let response = x402_test_client().await.get(url).send().await.unwrap(); + assert_eq!(response.status(), StatusCode::OK); + assert!(saw_payment.load(Ordering::SeqCst)); + + let (url, saw_payment) = + challenge_body_server(None, || body_offer(MAX_CHALLENGE_BODY_BYTES)).await; + let error = x402_test_client().await.get(url).send().await.unwrap_err(); + assert!( + matches!(error, ClientError::NoSupportedChallenge), + "{error}" + ); + assert!(!saw_payment.load(Ordering::SeqCst)); + } + /// Serve a single-offer x402 402 whose paid retry is recorded. async fn x402_offer_server( accept: serde_json::Value, diff --git a/rust/crates/kit/src/core/batch_verify.rs b/rust/crates/kit/src/core/batch_verify.rs index 4297c6679..edc7c916f 100644 --- a/rust/crates/kit/src/core/batch_verify.rs +++ b/rust/crates/kit/src/core/batch_verify.rs @@ -20,10 +20,12 @@ //! message under any key whose scalar the signer knows, no crafted key //! needed, while `verify_strict` rejects it outright. A mixed-order `R` can //! also pass when its deterministic batch coefficient annihilates the torsion -//! component. [`is_degenerate`] therefore screens every batch input for weak -//! keys and requires `R` to be torsion-free before the batch equation runs at -//! all. The per-signature fallback on a failing batch restores `verify_strict` -//! too. +//! component, and so can any signature under a mixed-order verifying key +//! `A = a·B + T` once its coefficient annihilates `T`. [`is_degenerate`] +//! therefore requires both the key and `R` to be torsion-free before the batch +//! equation runs at all; anything else is decided by `verify_strict` alone, +//! the check the onchain Ed25519 precompile applies. The per-signature +//! fallback on a failing batch restores `verify_strict` too. use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::mpsc; @@ -147,14 +149,17 @@ fn worker_loop(rx: mpsc::Receiver, max_batch: usize, window: Duration) { } /// Whether `job` can pass the raw batch equation while failing -/// `verify_strict`: a non-prime-order `R` or a small-order verifying key. +/// `verify_strict`: a non-prime-order `R`, or a verifying key with a torsion +/// component (small-order or mixed-order). /// /// `ed25519_dalek::verify_batch` checks one randomly weighted aggregate /// equation. `R = identity` (order 1, small-order) and /// `s = H(R‖A‖M)·a mod L` satisfies that equation /// for *any* message M, for any key whose private scalar `a` the signer knows /// — no weak/crafted key required. A mixed-order `R` can likewise pass when -/// the transcript-derived coefficient kills its torsion component. +/// the transcript-derived coefficient kills its torsion component, and so can +/// a signature under a mixed-order key `A = a·B + T`, whose residual is a +/// multiple of `T`. /// `verify_strict` rejects these through its small-order checks or exact /// per-signature equation; batching must exclude them before trusting the /// aggregate equation, or a holder of a legitimate signing key (e.g. the payer, in @@ -166,6 +171,12 @@ fn is_degenerate(key: &VerifyingKey, signature: &Signature) -> bool { if key.is_weak() { return true; } + if !CompressedEdwardsY(key.to_bytes()) + .decompress() + .is_some_and(|point| point.is_torsion_free()) + { + return true; + } match CompressedEdwardsY(*signature.r_bytes()).decompress() { Some(point) => point.is_small_order() || !point.is_torsion_free(), // Doesn't even decompress to a curve point; verify_strict would also @@ -184,13 +195,15 @@ fn verify_and_reply(batch: Vec) { return; } - // Reject degenerate jobs before batch verification runs, so one can never - // ride a passing batch to acceptance. Cheap relative to the multiscalar - // multiplication it guards: one point decompression per job. + // Decide degenerate jobs with `verify_strict` alone before batch + // verification runs, so one can never ride a passing batch to acceptance. + // Cheap relative to the multiscalar multiplication it guards: two point + // decompressions per job. let mut candidates = Vec::with_capacity(batch.len()); for job in batch { if is_degenerate(&job.key, &job.signature) { - let _ = job.reply.send(false); + let ok = job.key.verify_strict(&job.message, &job.signature).is_ok(); + let _ = job.reply.send(ok); } else { candidates.push(job); } @@ -313,6 +326,99 @@ mod tests { Signature::from_components(r_bytes, s.to_bytes()) } + /// A verifying key `A = a·B + T` with an order-2 component `T`, and a + /// signature under it with an honest `R = r·B` and `s = r + k·a`. The + /// exact equation leaves `k·T`, so `verify_strict` (and the onchain + /// precompile) reject it exactly when `k` is odd. + fn mixed_order_key_signature( + scalar: Scalar, + message: &[u8], + nonce: u64, + ) -> (VerifyingKey, Signature) { + let point = scalar * ED25519_BASEPOINT_POINT + EIGHT_TORSION[4]; + let key = VerifyingKey::from_bytes(&point.compress().to_bytes()) + .expect("a mixed-order point is a valid key encoding"); + let r = Scalar::from(nonce); + let r_bytes = (r * ED25519_BASEPOINT_POINT).compress().to_bytes(); + let mut hasher = Sha512::new(); + hasher.update(r_bytes); + hasher.update(key.as_bytes()); + hasher.update(message); + let h = Scalar::from_bytes_mod_order_wide(&hasher.finalize().into()); + let s = r + h * scalar; + (key, Signature::from_components(r_bytes, s.to_bytes())) + } + + fn reply_for(jobs: Vec<(Vec, VerifyingKey, Signature)>) -> Vec { + let mut replies = Vec::new(); + let batch = jobs + .into_iter() + .map(|(message, key, signature)| { + let (reply, rx) = oneshot::channel(); + replies.push(rx); + Job { + message, + key, + signature, + reply, + } + }) + .collect(); + verify_and_reply(batch); + replies + .into_iter() + .map(|mut rx| rx.try_recv().expect("every job is answered")) + .collect() + } + + #[test] + fn mixed_order_key_never_rides_a_passing_batch() { + let honest_signer = keypair(11); + let honest_message = b"paid request".to_vec(); + let honest = honest_signer.sign(&honest_message); + let scalar = Scalar::from(0x5eed_u64); + let message = b"free request".to_vec(); + let (key, forged) = (1..=4096) + .map(|nonce| mixed_order_key_signature(scalar, &message, nonce)) + .find(|(key, signature)| { + key.verify_strict(&message, signature).is_err() + && ed25519_dalek::verify_batch( + &[honest_message.as_slice(), message.as_slice()], + &[honest, *signature], + &[honest_signer.verifying_key(), *key], + ) + .is_ok() + }) + .expect("a batch coefficient should annihilate the key's torsion"); + assert!(!key.is_weak()); + assert!(is_degenerate(&key, &forged)); + + let replies = reply_for(vec![ + (honest_message, honest_signer.verifying_key(), honest), + (message, key, forged), + ]); + assert_eq!(replies, [true, false]); + } + + #[test] + fn mixed_order_key_signature_valid_under_verify_strict_still_passes() { + let honest_signer = keypair(12); + let honest_message = b"paid request".to_vec(); + let honest = honest_signer.sign(&honest_message); + let scalar = Scalar::from(0x5eed_u64); + let message = b"also paid".to_vec(); + let (key, valid) = (1..=64) + .map(|nonce| mixed_order_key_signature(scalar, &message, nonce)) + .find(|(key, signature)| key.verify_strict(&message, signature).is_ok()) + .expect("an even challenge leaves no torsion residual"); + + let replies = reply_for(vec![ + (honest_message, honest_signer.verifying_key(), honest), + (message, key, valid), + ]); + assert_eq!(replies, [true, true]); + } + #[test] fn forged_signature_is_internally_consistent() { // Sanity check on the forgery construction itself: R really is the diff --git a/rust/crates/kit/src/core/payment_channel/mod.rs b/rust/crates/kit/src/core/payment_channel/mod.rs index 17fcc3cdc..f4fcf5c17 100644 --- a/rust/crates/kit/src/core/payment_channel/mod.rs +++ b/rust/crates/kit/src/core/payment_channel/mod.rs @@ -1,5 +1,7 @@ //! Versioned payment-channel ABIs and instruction builders. +pub mod payer_refund; +pub(crate) mod token_account; pub mod v1; pub mod v2; diff --git a/rust/crates/kit/src/core/payment_channel/payer_refund.rs b/rust/crates/kit/src/core/payment_channel/payer_refund.rs new file mode 100644 index 000000000..504f6c9ac --- /dev/null +++ b/rust/crates/kit/src/core/payment_channel/payer_refund.rs @@ -0,0 +1,334 @@ +//! Whether a sealed `distribute` refunds the payer or forfeits the refund. +//! +//! On a sealed channel the payment-channels program pays `deposit - settled` +//! back to the payer's associated token account, unless the payer already +//! withdrew it. It never fails on an unusable refund account: a missing, +//! uninitialized, frozen, reassigned or extension-bearing one has the refund +//! redirected to the protocol treasury, and the channel closes in the same +//! instruction. A server cranking that `distribute` checks the account first +//! and, when it cannot be paid, lands only the seal and defers the +//! distribute: the payer can still `withdraw_payer` or repair the account, +//! and a later pass distributes once it can be paid. +//! +//! The deferral is bounded. A payer must not hold the merchant's settled +//! revenue and the sponsor's rent in escrow by keeping its account unusable, +//! so once the channel has been sealed for its grace period the distribute +//! runs anyway and the program's redirect to the treasury is accepted. + +use solana_pubkey::Pubkey; + +use super::token_account::{decode_token_account, TOKEN_ACCOUNT_FROZEN, TOKEN_ACCOUNT_INITIALIZED}; +use super::v1::find_associated_token_address; + +/// Evidence that a sealed `distribute` of [`Self::channel`] may run: no +/// refund is due, the payer's token account can take it, or the deferral +/// deadline passed. Only [`payer_refund`] issues one. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct DistributeClearance { + channel: Pubkey, +} + +impl DistributeClearance { + /// The channel this clearance was issued for. + pub fn channel(&self) -> &Pubkey { + &self.channel + } +} + +/// What to do with a sealed channel's `distribute`. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum PayerRefund { + /// Distribute: the payer's refund, if any, is paid. + Clear(DistributeClearance), + /// A refund is due and `payer_token_account` cannot receive it: land only + /// the seal and distribute on a later pass, at the latest at `until` + /// (unix seconds). + Deferred { + refund: u64, + payer_token_account: Pubkey, + reason: String, + until: i64, + }, + /// The deferral deadline passed with the account still unusable: + /// distribute anyway, and the program redirects `refund` to the treasury. + Forfeit { + clearance: DistributeClearance, + refund: u64, + payer_token_account: Pubkey, + reason: String, + }, +} + +impl PayerRefund { + /// The clearance to distribute now, `None` while deferred. + pub fn clearance(self) -> Option { + match self { + Self::Clear(clearance) | Self::Forfeit { clearance, .. } => Some(clearance), + Self::Deferred { .. } => None, + } + } +} + +/// When a deferred distribute stops waiting for the payer's account. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct RefundDeadline { + /// When the channel was sealed (unix seconds); the time of this close for + /// a channel it seals. The program records no seal time, so a server + /// keeps the one it observed first. + pub sealed_at: i64, + /// The channel's grace period, in seconds. + pub grace_period: u32, +} + +impl RefundDeadline { + /// The first time the distribute runs whatever the account's state. + pub fn until(&self) -> i64 { + self.sealed_at.saturating_add(i64::from(self.grace_period)) + } +} + +/// An account as fetched from the cluster. +#[derive(Debug, Clone, Copy)] +pub struct ObservedAccount<'a> { + /// The program that owns the account. + pub owner: Pubkey, + pub data: &'a [u8], +} + +/// The channel fields a sealed `distribute` decides the refund from. +#[derive(Debug, Clone, Copy)] +pub struct SealedRefundTerms { + pub channel: Pubkey, + pub payer: Pubkey, + pub mint: Pubkey, + pub token_program: Pubkey, + pub deposit: u64, + /// The watermark the channel is sealed at. + pub settled: u64, + pub payer_withdrawn_at: i64, +} + +impl SealedRefundTerms { + /// The payer's refund account, which `payer_token_account` must be the + /// fetch of. + pub fn payer_token_account(&self) -> Pubkey { + find_associated_token_address(&self.payer, &self.mint, &self.token_program).0 + } + + /// The refund a sealed `distribute` pays the payer: zero once the payer + /// withdrew it or the deposit is fully settled. + pub fn refund_due(&self) -> u64 { + if self.payer_withdrawn_at != 0 { + return 0; + } + self.deposit.saturating_sub(self.settled) + } +} + +/// Decide what a sealed `distribute` under `terms` may do at `now` (unix +/// seconds). `payer_token_account` is the account at +/// [`SealedRefundTerms::payer_token_account`], `None` when it does not exist. +pub fn payer_refund( + terms: &SealedRefundTerms, + payer_token_account: Option>, + deadline: RefundDeadline, + now: i64, +) -> PayerRefund { + let clearance = DistributeClearance { + channel: terms.channel, + }; + let refund = terms.refund_due(); + let Some(reason) = (refund > 0) + .then(|| unpayable_reason(terms, payer_token_account)) + .flatten() + else { + return PayerRefund::Clear(clearance); + }; + let payer_token_account = terms.payer_token_account(); + let until = deadline.until(); + if now >= until { + return PayerRefund::Forfeit { + clearance, + refund, + payer_token_account, + reason: reason.to_string(), + }; + } + PayerRefund::Deferred { + refund, + payer_token_account, + reason: reason.to_string(), + until, + } +} + +/// Why the payer's refund account cannot take a refund, `None` when it can. +fn unpayable_reason( + terms: &SealedRefundTerms, + payer_token_account: Option>, +) -> Option<&'static str> { + let blocked = Some; + let Some(account) = payer_token_account else { + return blocked("does not exist"); + }; + if account.owner != terms.token_program { + return blocked("is not owned by the channel's token program"); + } + let Some(decoded) = decode_token_account(account.data) else { + return blocked("is not an initialized token account"); + }; + if decoded.state == TOKEN_ACCOUNT_FROZEN { + return blocked("is frozen"); + } + if decoded.state != TOKEN_ACCOUNT_INITIALIZED { + return blocked("is not initialized"); + } + if decoded.mint != terms.mint || decoded.owner != terms.payer { + return blocked("is not held by the payer for the channel's mint"); + } + if decoded.unsupported_extension.is_some() { + return blocked("carries a token account extension the program will not pay into"); + } + None +} + +#[cfg(test)] +mod tests { + use super::super::token_account::TOKEN_ACCOUNT_LEN; + use super::*; + + fn terms() -> SealedRefundTerms { + SealedRefundTerms { + channel: Pubkey::new_unique(), + payer: Pubkey::new_unique(), + mint: Pubkey::new_unique(), + token_program: Pubkey::new_unique(), + deposit: 1_000, + settled: 400, + payer_withdrawn_at: 0, + } + } + + fn token_account(mint: &Pubkey, owner: &Pubkey, state: u8) -> Vec { + let mut data = vec![0u8; TOKEN_ACCOUNT_LEN]; + data[..32].copy_from_slice(mint.as_ref()); + data[32..64].copy_from_slice(owner.as_ref()); + data[108] = state; + data + } + + const SEALED_AT: i64 = 1_000_000; + const GRACE: u32 = 900; + const DEADLINE: RefundDeadline = RefundDeadline { + sealed_at: SEALED_AT, + grace_period: GRACE, + }; + + fn decide(terms: &SealedRefundTerms, account: Option>) -> PayerRefund { + payer_refund(terms, account, DEADLINE, SEALED_AT) + } + + fn observed(terms: &SealedRefundTerms, data: &[u8]) -> PayerRefund { + decide( + terms, + Some(ObservedAccount { + owner: terms.token_program, + data, + }), + ) + } + + #[test] + fn an_unusable_refund_account_defers_a_due_refund() { + let terms = terms(); + let blocked = |outcome: PayerRefund| { + assert!( + matches!( + outcome, + PayerRefund::Deferred { refund: 600, until, .. } + if until == SEALED_AT + i64::from(GRACE) + ), + "{outcome:?}" + ) + }; + blocked(decide(&terms, None)); + blocked(observed( + &terms, + &token_account(&terms.mint, &terms.payer, TOKEN_ACCOUNT_FROZEN), + )); + blocked(observed( + &terms, + &token_account(&terms.mint, &terms.payer, 0), + )); + blocked(observed( + &terms, + &token_account( + &terms.mint, + &Pubkey::new_unique(), + TOKEN_ACCOUNT_INITIALIZED, + ), + )); + blocked(observed(&terms, &[])); + blocked(decide( + &terms, + Some(ObservedAccount { + owner: Pubkey::new_unique(), + data: &token_account(&terms.mint, &terms.payer, TOKEN_ACCOUNT_INITIALIZED), + }), + )); + } + + #[test] + fn a_live_account_or_no_refund_clears_the_distribute() { + let terms = terms(); + let live = token_account(&terms.mint, &terms.payer, TOKEN_ACCOUNT_INITIALIZED); + assert!( + matches!(observed(&terms, &live), PayerRefund::Clear(c) if c.channel == terms.channel) + ); + for terms in [ + SealedRefundTerms { + settled: 1_000, + ..terms + }, + SealedRefundTerms { + payer_withdrawn_at: 1, + ..terms + }, + ] { + assert!(matches!(decide(&terms, None), PayerRefund::Clear(_))); + } + } + + /// The deferral is bounded: from the deadline on, an account still + /// unusable no longer holds the payout, and the refund is forfeited. + #[test] + fn a_deferral_ends_at_the_grace_deadline() { + let terms = terms(); + let until = DEADLINE.until(); + let at = |now: i64| payer_refund(&terms, None, DEADLINE, now); + assert!(matches!(at(until - 1), PayerRefund::Deferred { .. })); + assert!(at(until - 1).clearance().is_none()); + match at(until) { + PayerRefund::Forfeit { + clearance, refund, .. + } => { + assert_eq!(clearance.channel, terms.channel); + assert_eq!(refund, 600); + } + other => panic!("expected forfeit, got {other:?}"), + } + assert!(at(until + 10).clearance().is_some()); + // A payable account clears at any time, before or after the deadline. + let live = token_account(&terms.mint, &terms.payer, TOKEN_ACCOUNT_INITIALIZED); + let account = Some(ObservedAccount { + owner: terms.token_program, + data: &live, + }); + for now in [SEALED_AT, until + 10] { + assert!(matches!( + payer_refund(&terms, account, DEADLINE, now), + PayerRefund::Clear(_) + )); + } + } +} diff --git a/rust/crates/kit/src/core/payment_channel/token_account.rs b/rust/crates/kit/src/core/payment_channel/token_account.rs new file mode 100644 index 000000000..c174a24cb --- /dev/null +++ b/rust/crates/kit/src/core/payment_channel/token_account.rs @@ -0,0 +1,93 @@ +//! The SPL token account layout shared by Token and Token-2022, read as the +//! payment-channels program reads a payout destination. + +use solana_pubkey::Pubkey; + +/// Base length of an SPL token account. Token-2022 appends its extensions +/// after the same fixed layout, so one decoder covers both programs. +pub(crate) const TOKEN_ACCOUNT_LEN: usize = 165; + +/// `AccountState::Initialized`, at offset 108. +pub(crate) const TOKEN_ACCOUNT_INITIALIZED: u8 = 1; + +/// `AccountState::Frozen`: the account cannot receive or send. +pub(crate) const TOKEN_ACCOUNT_FROZEN: u8 = 2; + +/// `AccountType::Account`, the discriminant a Token-2022 account carries at +/// offset 165 before its extensions. +pub(crate) const TOKEN_ACCOUNT_TYPE: u8 = 2; + +/// `ExtensionType::ImmutableOwner`. +/// +/// The only account extension a settlement destination may carry. It is inert +/// — it fixes the owner, nothing else — and every associated token account has +/// it, so requiring its absence would reject ordinary ATAs. +pub(crate) const EXTENSION_IMMUTABLE_OWNER: u16 = 7; + +/// The fields of an SPL token account this server cares about. +pub(crate) struct TokenAccount { + pub(crate) mint: Pubkey, + pub(crate) owner: Pubkey, + pub(crate) state: u8, + /// An account extension this server will not settle through, if any. + pub(crate) unsupported_extension: Option, +} + +/// Decode a token account, or `None` when the data is too short to be one — +/// which is what an uninitialized (or non-token) account looks like. +/// +/// Token-2022 appends a type byte and a TLV extension list after the same +/// 165-byte base. Those extensions are not cosmetic: one can withhold part of a +/// transfer, require a memo to precede it, block it from a CPI, or move the +/// balance out of the classic ledger entirely — so an account carrying one is +/// reported rather than silently accepted as a payout destination. +pub(crate) fn decode_token_account(data: &[u8]) -> Option { + if data.len() < TOKEN_ACCOUNT_LEN { + return None; + } + Some(TokenAccount { + mint: Pubkey::try_from(&data[0..32]).ok()?, + owner: Pubkey::try_from(&data[32..64]).ok()?, + state: data[108], + unsupported_extension: unsupported_account_extension(data), + }) +} + +/// The first account extension outside the allowlist, if the account has one. +/// +/// A malformed or truncated TLV is reported as unsupported rather than skipped: +/// this decides whether to accept an escrow, so anything it cannot read is +/// something it should not settle through. +fn unsupported_account_extension(data: &[u8]) -> Option { + // A classic SPL Token account is exactly the base length and has no + // extension list at all. + if data.len() == TOKEN_ACCOUNT_LEN { + return None; + } + if data[TOKEN_ACCOUNT_LEN] != TOKEN_ACCOUNT_TYPE { + return Some(u16::from(data[TOKEN_ACCOUNT_LEN])); + } + let mut cursor = TOKEN_ACCOUNT_LEN + 1; + while cursor < data.len() { + // A run of zero padding is the end of the list, not an extension. + if data[cursor..].iter().all(|byte| *byte == 0) { + return None; + } + let Some(header) = data.get(cursor..cursor + 4) else { + return Some(u16::MAX); + }; + let extension = u16::from_le_bytes([header[0], header[1]]); + let length = usize::from(u16::from_le_bytes([header[2], header[3]])); + if extension != EXTENSION_IMMUTABLE_OWNER { + return Some(extension); + } + let Some(next) = cursor.checked_add(4).and_then(|c| c.checked_add(length)) else { + return Some(u16::MAX); + }; + if next > data.len() { + return Some(u16::MAX); + } + cursor = next; + } + None +} diff --git a/rust/crates/kit/src/core/payment_channel/v1.rs b/rust/crates/kit/src/core/payment_channel/v1.rs index d246050fa..525c982a3 100644 --- a/rust/crates/kit/src/core/payment_channel/v1.rs +++ b/rust/crates/kit/src/core/payment_channel/v1.rs @@ -919,12 +919,24 @@ pub async fn build_open_payment_channel_tx_with_options( data: memo.as_bytes().to_vec(), }); } + // A version-1 open must carry its budget in the header. Without one the + // builder budgets the runtime default (200,000 units per instruction), + // which an open with both memos would put over the 400,000 a sponsor + // accepts for an open, so the default is capped at that ceiling. + let budget = match (options.version, options.compute_budget) { + (TxVersion::V1, None) => { + let mut budget = ComputeBudget::runtime_default(instructions.len()); + budget.unit_limit = budget.unit_limit.min(OPEN_MAX_COMPUTE_UNIT_LIMIT); + Some(budget) + } + (_, budget) => budget, + }; let mut tx = crate::core::tx::build_unsigned( options.version, fee_payer, &instructions, recent_blockhash, - options.compute_budget.as_ref(), + budget.as_ref(), )?; crate::core::signing::sign_versioned_transaction_slot(signer, &mut tx) .await @@ -1000,6 +1012,10 @@ impl MemoPolicy<'_> { /// 1. An optional ComputeBudget prefix: at most one `SetComputeUnitLimit` and /// at most one `SetComputeUnitPrice`, limit before price, each within /// [`OPEN_MAX_COMPUTE_UNIT_LIMIT`] / [`MAX_COMPUTE_UNIT_PRICE_MICROLAMPORTS`]. +/// The sponsor pays the priority fee, so the fee itself (limit times price, +/// the runtime default limit when none is declared, or the version-1 +/// header fee) is held to +/// [`MAX_SPONSORED_PRIORITY_FEE_LAMPORTS`](crate::core::tx::MAX_SPONSORED_PRIORITY_FEE_LAMPORTS). /// 2. Exactly one instruction on `program_id` whose first data byte is /// `discriminator`. /// 3. A suffix of at most [`OPEN_MAX_LIGHTHOUSE_INSTRUCTIONS`] Lighthouse @@ -1194,6 +1210,18 @@ pub fn scan_channel_tx_layout<'tx>( "{label} transaction must carry exactly one binding Memo" ))); } + // Each field within its ceiling still lets the largest limit pair with the + // largest price, and an undeclared limit is priced at the runtime default + // for every instruction. Checked once the layout is known to be canonical. + crate::core::tx::check_priority_fee( + &tx.message, + crate::core::tx::MAX_SPONSORED_PRIORITY_FEE_LAMPORTS, + ) + .map_err(|e| { + Error::Other(format!( + "{label} transaction compute unit price exceeds the sponsored fee maximum: {e}" + )) + })?; Ok(primary) } @@ -1531,6 +1559,30 @@ mod tests { .await } + /// A version-1 open built without an explicit budget stays within the + /// 400,000 units a sponsor accepts, even with both memos (three + /// instructions, whose runtime default would be 600,000). + #[tokio::test] + async fn a_default_version_1_open_budget_stays_within_the_open_cap() { + let open = build_open(&OpenTxOptions { + memo: Some("invoice-42".into()), + binding_memo: Some("binding".into()), + version: TxVersion::V1, + ..Default::default() + }) + .await + .expect("version-1 open"); + let tx = crate::core::tx::decode(&open.transaction).unwrap(); + let solana_message::VersionedMessage::V1(message) = &tx.message else { + panic!("version-1 message expected"); + }; + assert_eq!(message.instructions.len(), 3); + assert_eq!( + message.config.compute_unit_limit, + Some(OPEN_MAX_COMPUTE_UNIT_LIMIT) + ); + } + #[tokio::test] async fn open_tx_carries_the_memo_only_when_requested() { // The bare open is what every pay-kit server verifies; a declared diff --git a/rust/crates/kit/src/core/settlement/worker.rs b/rust/crates/kit/src/core/settlement/worker.rs index 3ab852be3..c12f5a23d 100644 --- a/rust/crates/kit/src/core/settlement/worker.rs +++ b/rust/crates/kit/src/core/settlement/worker.rs @@ -12,6 +12,8 @@ //! Each flush signs with the **operator** (fee-payer + Delegated authority), //! **sends without preflight** (does not wait for confirmation — the signature //! is returned to callers immediately), then a background task confirms/retries. +//! A packed transaction that fails on-chain applied nothing, so its channels +//! are re-sent one per transaction: one failing channel cannot fail the rest. //! Un-settled channels remain the caller's store's responsibility to reconcile. //! //! Broadcast is behind the [`Broadcaster`] trait so the actor is unit-testable @@ -256,7 +258,7 @@ fn spawn_flush( .acquire_owned() .await .expect("settlement semaphore is never closed"); - settle_group(group, &cfg, broadcaster.clone(), trigger).await; + settle_group(group, &cfg, broadcaster.clone(), &sem, trigger).await; } }); } @@ -301,8 +303,9 @@ fn regroup( async fn settle_group( group: Vec, - cfg: &SettlementConfig, + cfg: &Arc, broadcaster: Arc, + sem: &Arc, trigger: &'static str, ) { let started = Instant::now(); @@ -344,26 +347,7 @@ async fn settle_group( .unwrap_or(0), ); - // Build + sign + broadcast. - let result: SettlementResult = async { - let blockhash = broadcaster.latest_blockhash().await?; - let mut tx = build_unsigned( - cfg.tx_version, - &cfg.operator, - &flat, - blockhash, - cfg.compute_budget.as_ref(), - ) - .map_err(|e| format!("settle build failed: {e}"))?; - crate::core::signing::sign_versioned_transaction_slot( - cfg.operator_signer.as_ref(), - &mut tx, - ) - .await - .map_err(|e| format!("settle signing failed: {e}"))?; - broadcaster.send(&tx).await - } - .await; + let result = sign_and_send(cfg, broadcaster.as_ref(), &flat).await; match &result { Ok(sig) => { @@ -398,20 +382,67 @@ async fn settle_group( // Reply to every channel in the group with the (shared) tx signature; // units awaiting confirmation get the confirmation outcome instead. + let packed = group.len() > 1; let (confirming, immediate): (Vec<_>, Vec<_>) = group .into_iter() .partition(|u| u.await_confirmation && result.is_ok()); + // Kept to re-send alone should the packed transaction fail on-chain. + let replied: Vec<(String, Vec)> = if packed && result.is_ok() { + immediate + .iter() + .map(|u| (u.channel_id.clone(), u.instructions.clone())) + .collect() + } else { + Vec::new() + }; for u in immediate { let _ = u.reply.send(result.clone()); } // Background confirm (best-effort; store is the durable source of truth). if let Ok(sig) = result { - let attempts = cfg.confirm_attempts; + let cfg = Arc::clone(cfg); + let sem = Arc::clone(sem); tokio::spawn(async move { - let outcome = confirm_settlement(broadcaster.as_ref(), &sig, attempts).await; - for u in confirming { - let _ = u.reply.send(outcome.clone()); + let outcome = + confirm_settlement(broadcaster.as_ref(), &sig, cfg.confirm_attempts).await; + match outcome { + // A transaction is atomic, so nothing in it applied: one + // unit failing deterministically (a channel its payer + // already closed, an unredeemable voucher) must not fail + // the others packed with it. Each is re-sent alone and + // answers with its own outcome. + Err(ConfirmFailure::OnChain(error)) if packed => { + tracing::warn!( + tx = %sig, + error = %error, + channels = confirming.len() + replied.len(), + "packed settlement failed on-chain; settling each channel alone", + ); + for unit in confirming { + let outcome = + settle_alone(&cfg, broadcaster.as_ref(), &sem, &unit.instructions) + .await; + let _ = unit.reply.send(outcome); + } + for (channel_id, instructions) in replied { + if let Err(error) = + settle_alone(&cfg, broadcaster.as_ref(), &sem, &instructions).await + { + tracing::warn!( + channel = %channel_id, + error = %error, + "settlement failed alone (store will reconcile)", + ); + } + } + } + outcome => { + let outcome = outcome.map_err(ConfirmFailure::into_message); + for u in confirming { + let _ = u.reply.send(outcome.clone()); + } + } } }); } @@ -420,12 +451,70 @@ async fn settle_group( .await } +/// Build, sign and broadcast one settlement transaction. +async fn sign_and_send( + cfg: &SettlementConfig, + broadcaster: &dyn Broadcaster, + instructions: &[Instruction], +) -> SettlementResult { + let blockhash = broadcaster.latest_blockhash().await?; + let mut tx = build_unsigned( + cfg.tx_version, + &cfg.operator, + instructions, + blockhash, + cfg.compute_budget.as_ref(), + ) + .map_err(|e| format!("settle build failed: {e}"))?; + crate::core::signing::sign_versioned_transaction_slot(cfg.operator_signer.as_ref(), &mut tx) + .await + .map_err(|e| format!("settle signing failed: {e}"))?; + broadcaster.send(&tx).await +} + +/// Settle one unit in its own transaction and wait for its outcome. Its send +/// holds an in-flight permit, like every flush transaction's. +async fn settle_alone( + cfg: &SettlementConfig, + broadcaster: &dyn Broadcaster, + sem: &Arc, + instructions: &[Instruction], +) -> SettlementResult { + let sig = { + let _permit = sem + .clone() + .acquire_owned() + .await + .expect("settlement semaphore is never closed"); + sign_and_send(cfg, broadcaster, instructions).await? + }; + confirm_settlement(broadcaster, &sig, cfg.confirm_attempts) + .await + .map_err(ConfirmFailure::into_message) +} + +/// Why a sent settlement did not confirm. +enum ConfirmFailure { + /// It landed and failed: none of its instructions applied. + OnChain(String), + /// Not confirmed within the window; it may still land. + Unconfirmed(String), +} + +impl ConfirmFailure { + fn into_message(self) -> String { + match self { + Self::OnChain(message) | Self::Unconfirmed(message) => message, + } + } +} + /// Poll `sig` until it is confirmed, fails on-chain, or `attempts` run out. async fn confirm_settlement( broadcaster: &dyn Broadcaster, sig: &str, attempts: u32, -) -> SettlementResult { +) -> Result { let send_policy = SKIP_PREFLIGHT_SEND; for _ in 0..attempts { match broadcaster.confirm(sig).await { @@ -450,7 +539,9 @@ async fn confirm_settlement( error = %err, "settlement failed on-chain (store will reconcile)", ); - return Err(format!("settlement {sig} failed on-chain: {err}")); + return Err(ConfirmFailure::OnChain(format!( + "settlement {sig} failed on-chain: {err}" + ))); } Err(e) => { tracing::debug!(tx = %sig, error = %e, "confirm poll error"); @@ -465,7 +556,9 @@ async fn confirm_settlement( skip_preflight = send_policy.skip_preflight, "settlement not confirmed in window", ); - Err(format!("settlement {sig} was not confirmed in its window")) + Err(ConfirmFailure::Unconfirmed(format!( + "settlement {sig} was not confirmed in its window" + ))) } /// Production broadcaster backed by the shared asynchronous RPC pipeline. @@ -563,6 +656,14 @@ mod tests { seq: Mutex, /// When set, every confirmation reports this on-chain failure. confirm_failure: Mutex>, + /// A transaction touching this account fails on-chain. + poison: Mutex>, + /// Sends in progress, and the most seen at once. + sending: std::sync::atomic::AtomicUsize, + max_sending: std::sync::atomic::AtomicUsize, + /// How long each send takes. + send_delay: Mutex, + failing: Mutex>, } #[async_trait] impl Broadcaster for MockBroadcaster { @@ -570,15 +671,35 @@ mod tests { Ok(Hash::new_from_array([9u8; 32])) } async fn send(&self, tx: &VersionedTransaction) -> Result { + use std::sync::atomic::Ordering::SeqCst; + let now = self.sending.fetch_add(1, SeqCst) + 1; + self.max_sending.fetch_max(now, SeqCst); + let delay = *self.send_delay.lock().unwrap(); + tokio::time::sleep(delay).await; + self.sending.fetch_sub(1, SeqCst); self.sent .lock() .unwrap() .push(tx.message.instructions().len()); let mut seq = self.seq.lock().unwrap(); *seq += 1; - Ok(format!("sig{seq}")) + let sig = format!("sig{seq}"); + let keys = tx.message.static_account_keys(); + if self + .poison + .lock() + .unwrap() + .iter() + .any(|poison| keys.contains(poison)) + { + self.failing.lock().unwrap().insert(sig.clone()); + } + Ok(sig) } - async fn confirm(&self, _sig: &str) -> Result { + async fn confirm(&self, sig: &str) -> Result { + if self.failing.lock().unwrap().contains(sig) { + return Ok(ConfirmOutcome::Failed("InstructionError(0)".to_string())); + } Ok(match self.confirm_failure.lock().unwrap().clone() { Some(error) => ConfirmOutcome::Failed(error), None => ConfirmOutcome::Confirmed, @@ -655,6 +776,99 @@ mod tests { ); } + /// One channel whose settlement fails on-chain fails the transaction it + /// was packed into; the others are re-sent alone and land. + #[tokio::test] + async fn a_failing_channel_does_not_fail_the_channels_packed_with_it() { + let (h, bc) = handle(4, 50); + let poison = unit_instructions(1)[0].accounts[0].pubkey; + *bc.poison.lock().unwrap() = vec![poison]; + + let mut tasks = Vec::new(); + for i in 0..3u64 { + let h = h.clone(); + tasks.push(tokio::spawn(async move { + h.settle_confirmed(format!("c{i}"), unit_instructions(i)) + .await + })); + } + let outcomes: Vec<_> = join_settlements(tasks).await; + assert!(outcomes[0].is_ok(), "{:?}", outcomes[0]); + assert!( + outcomes[1] + .as_ref() + .is_err_and(|e| e.contains("failed on-chain")), + "{:?}", + outcomes[1] + ); + assert!(outcomes[2].is_ok(), "{:?}", outcomes[2]); + // The packed attempt, then one transaction per channel. + assert_eq!(bc.sent.lock().unwrap().clone(), vec![3, 1, 1, 1]); + + // Positive control: without a failing channel the pack lands as one. + bc.poison.lock().unwrap().clear(); + bc.sent.lock().unwrap().clear(); + let mut tasks = Vec::new(); + for i in 10..13u64 { + let h = h.clone(); + tasks.push(tokio::spawn(async move { + h.settle_confirmed(format!("c{i}"), unit_instructions(i)) + .await + })); + } + assert!(join_settlements(tasks).await.iter().all(Result::is_ok)); + assert_eq!(bc.sent.lock().unwrap().clone(), vec![3]); + } + + /// Re-sending each channel of a failed pack alone still counts against + /// `max_in_flight_tx`: two packs failing at once never send more than + /// the bound together. + #[tokio::test] + async fn settling_alone_stays_within_the_in_flight_bound() { + let bc = Arc::new(MockBroadcaster::default()); + *bc.send_delay.lock().unwrap() = Duration::from_millis(30); + let mut cfg = SettlementConfig::new( + Pubkey::new_from_array([0xAA; 32]), + Arc::new(TestSigner(Pubkey::new_from_array([0xAA; 32]))), + ); + cfg.max_voucher_settlements_per_tx = 2; + cfg.linger = Duration::from_millis(5_000); + cfg.max_in_flight_tx = 1; + let h = spawn(cfg, bc.clone()); + // One failing channel in each of two packs. + *bc.poison.lock().unwrap() = vec![ + unit_instructions(0)[0].accounts[0].pubkey, + unit_instructions(2)[0].accounts[0].pubkey, + ]; + let mut tasks = Vec::new(); + for i in 0..4u64 { + let h = h.clone(); + tasks.push(tokio::spawn(async move { + h.settle_confirmed(format!("c{i}"), unit_instructions(i)) + .await + })); + } + let outcomes = join_settlements(tasks).await; + assert!(outcomes[1].is_ok() && outcomes[3].is_ok(), "{outcomes:?}"); + // Two packs, then each of the four channels alone. + assert_eq!(bc.sent.lock().unwrap().len(), 6); + assert_eq!( + bc.max_sending.load(std::sync::atomic::Ordering::SeqCst), + 1, + "never more sends at once than max_in_flight_tx" + ); + } + + async fn join_settlements( + tasks: Vec>, + ) -> Vec { + let mut out = Vec::new(); + for task in tasks { + out.push(task.await.unwrap()); + } + out + } + #[tokio::test] async fn timer_flushes_partial_batch() { let (h, bc) = handle(10, 120); // cap high → only the timer flushes diff --git a/rust/crates/kit/src/core/store.rs b/rust/crates/kit/src/core/store.rs index 2f9cf13e7..55aa3fc84 100644 --- a/rust/crates/kit/src/core/store.rs +++ b/rust/crates/kit/src/core/store.rs @@ -401,8 +401,10 @@ pub enum PendingClaim { /// /// It is also the floor for how long a [`Store`] keeps charge records and /// [`ConsumedSignatures`] claims: an MPP server accepting push credentials -/// refuses any challenge that expires later than this from now, so a paid -/// signature cannot outlive its replay record. +/// refuses any challenge that expires later than this from now, and any +/// pushed transaction confirmed longer ago than this, so a paid signature +/// cannot outlive its replay record. A store that loses its records (an +/// in-memory store across a restart) still reopens that window. pub const DEFAULT_CHARGE_RECORD_RETENTION: Duration = Duration::from_secs(24 * 60 * 60); /// How long a charge record may sit in [`ChargeRecordState::Reserved`] @@ -1331,6 +1333,23 @@ pub enum ObservedLifecycle { Terminal { started_at: Option }, } +impl ObservedLifecycle { + /// The lifecycle a confirmed read of a payment-channel account shows, + /// from its `status` and `closure_started_at` fields. `now` stands in + /// for a close the account reports without a start time. + pub fn of_channel(status: u8, closure_started_at: i64, now: u64) -> Self { + const OPEN: u8 = 0; + const CLOSING: u8 = 2; + let started_at = (closure_started_at != 0 || status != OPEN) + .then(|| u64::try_from(closure_started_at).unwrap_or(now).max(1)); + match (status, started_at) { + (OPEN | CLOSING, Some(started_at)) => Self::Closing { started_at }, + (OPEN, None) => Self::Open, + (_, started_at) => Self::Terminal { started_at }, + } + } +} + /// One onchain read of a channel; see [`ChannelState::record_onchain_observation`]. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct OnchainObservation { diff --git a/rust/crates/kit/src/core/tx/mod.rs b/rust/crates/kit/src/core/tx/mod.rs index c645d0855..0371d24ff 100644 --- a/rust/crates/kit/src/core/tx/mod.rs +++ b/rust/crates/kit/src/core/tx/mod.rs @@ -28,9 +28,9 @@ pub use build::{ pub use policy::{ advertised, check_envelope, check_envelope_without_legacy, check_priority_fee, check_reported_version, check_reported_version_without_legacy, check_v0_budget_caps, - check_v1_budget_caps, check_v1_budget_caps_with, highest, negotiate, require_budget_prefix, - require_presigned, require_static_accounts, tx_v1_active, LoadedDataLimitRule, TxV1Mode, - MAX_SPONSORED_PRIORITY_FEE_LAMPORTS, TX_V1_FEATURE_GATE, + check_v1_budget_caps, check_v1_budget_caps_with, highest, negotiate, reject_v1_heap_request, + require_budget_prefix, require_presigned, require_static_accounts, tx_v1_active, + LoadedDataLimitRule, TxV1Mode, MAX_SPONSORED_PRIORITY_FEE_LAMPORTS, TX_V1_FEATURE_GATE, }; pub use version::{accepted_versions, TxLimits, TxVersion, DEFAULT_ACCEPTED_VERSIONS}; pub use wire::{decode, decode_bytes, encode, serialize, serialized_size}; diff --git a/rust/crates/kit/src/core/tx/policy.rs b/rust/crates/kit/src/core/tx/policy.rs index 20f6e1152..3dd782775 100644 --- a/rust/crates/kit/src/core/tx/policy.rs +++ b/rust/crates/kit/src/core/tx/policy.rs @@ -183,6 +183,21 @@ pub fn check_v1_budget_caps_with( Ok(Some(declared)) } +/// Reject a version-1 message that requests a heap size. A sponsor bounds +/// the compute a co-signed transaction may buy; version 0 refuses +/// `RequestHeapFrame` for the same reason (x402 scheme_*_svm.md §2.2.1: other +/// ComputeBudget instruction types "SHOULD be rejected"). Other versions pass. +pub fn reject_v1_heap_request(message: &VersionedMessage) -> Result<()> { + if let VersionedMessage::V1(v1) = message { + if v1.config.heap_size.is_some() { + return Err(Error::Other( + "version 1 transaction config must not request a heap size".into(), + )); + } + } + Ok(()) +} + /// Version-0 (and legacy) counterpart of [`check_v1_budget_caps`] for a /// message a server co-signs: every ComputeBudget instruction carries no /// accounts, no opcode is duplicated or unsupported (a loaded-data limit diff --git a/rust/crates/kit/src/core/tx/version.rs b/rust/crates/kit/src/core/tx/version.rs index ec4a02bb5..df63ff90d 100644 --- a/rust/crates/kit/src/core/tx/version.rs +++ b/rust/crates/kit/src/core/tx/version.rs @@ -100,9 +100,13 @@ impl TxVersion { /// /// A legacy (unprefixed) message is policed as version 0: it shares the /// 1232-byte packet limit, carries its compute budget as ComputeBudget - /// instructions, and cannot reference address lookup tables. Servers keep - /// accepting legacy messages from existing clients for backward - /// compatibility whenever they accept version 0; the kit never builds or + /// instructions, and cannot reference address lookup tables. Whether a + /// legacy message is accepted at all is the protocol's call: the x402 + /// sponsors keep accepting it from existing clients whenever they accept + /// version 0 (scheme_exact_svm.md §1.5, via [`super::check_envelope`]), + /// while the MPP charge and session servers refuse it ("servers MUST NOT + /// advertise \"legacy\" and MUST reject a legacy message", via + /// [`super::check_envelope_without_legacy`]). The kit never builds or /// advertises legacy itself. pub fn of(message: &VersionedMessage) -> Result { match message { diff --git a/rust/crates/kit/src/core/tx_pipeline.rs b/rust/crates/kit/src/core/tx_pipeline.rs index 853ab368f..36b48f4ce 100644 --- a/rust/crates/kit/src/core/tx_pipeline.rs +++ b/rust/crates/kit/src/core/tx_pipeline.rs @@ -99,6 +99,13 @@ pub enum TxPipelineError { FinalizationTimeout { signature: Signature }, #[error("RPC submission and confirmation failed for transaction {signature}")] SubmissionFailed { signature: Signature }, + #[error("transaction {signature} failed simulation: {reason}")] + SimulationFailed { + signature: Signature, + reason: String, + }, + #[error("simulation of transaction {signature} could not be completed")] + SimulationUnavailable { signature: Signature }, #[error("transaction submission guard rejected the attempt")] SubmissionGuardRejected, #[error("confirmed account read failed after bounded retries")] @@ -201,7 +208,9 @@ impl TxPipeline { /// already been verified locally, then await confirmed commitment. /// /// Only this API skips preflight. Callers must not pass arbitrary client - /// transactions without first performing byte-exact validation. + /// transactions without first performing byte-exact validation, and a + /// client transaction the server pays the fee for goes through + /// [`Self::simulate`] and [`Self::submit_simulated`] instead. pub async fn submit_verified( &self, transaction: &VersionedTransaction, @@ -376,6 +385,32 @@ impl TxPipeline { min_context_slot: u64, expected_owner: Pubkey, ) -> PipelineResult>> { + self.read_owned_account_at(address, "finalized", min_context_slot, expected_owner) + .await + .map(|(data, _)| data) + } + + /// Read program state at confirmed commitment from a bank at or after + /// `min_context_slot`, with the slot of the bank that answered, so the + /// caller can refuse to let an older view replace a newer one. Ownership + /// is checked on the same observation; a missing account returns `None`. + pub async fn read_confirmed_owned_account_data_at( + &self, + address: Pubkey, + min_context_slot: u64, + expected_owner: Pubkey, + ) -> PipelineResult<(Option>, u64)> { + self.read_owned_account_at(address, "confirmed", min_context_slot, expected_owner) + .await + } + + async fn read_owned_account_at( + &self, + address: Pubkey, + commitment: &str, + min_context_slot: u64, + expected_owner: Pubkey, + ) -> PipelineResult<(Option>, u64)> { let response: solana_rpc_client_api::response::Response< Option, > = self @@ -385,7 +420,7 @@ impl TxPipeline { RpcRequest::GetAccountInfo, serde_json::json!([ address.to_string(), { - "commitment": "finalized", + "commitment": commitment, "minContextSlot": min_context_slot, "encoding": "base64", } @@ -393,11 +428,12 @@ impl TxPipeline { ) .await .map_err(|_| TxPipelineError::AccountReadFailed)?; - if response.context.slot < min_context_slot { + let slot = response.context.slot; + if slot < min_context_slot { return Err(TxPipelineError::AccountReadFailed); } let Some(account) = response.value else { - return Ok(None); + return Ok((None, slot)); }; let account = account .to_account() @@ -405,7 +441,7 @@ impl TxPipeline { if account.owner.to_bytes() != expected_owner.to_bytes() { return Err(TxPipelineError::AccountOwnerMismatch { address }); } - Ok(Some(account.data)) + Ok((Some(account.data), slot)) } /// Read one account at confirmed commitment, optionally requiring the RPC @@ -590,6 +626,82 @@ impl TxPipeline { } } +/// A signed transaction whose exact bytes executed successfully in a +/// simulation against confirmed state, or whose signature already landed. +/// +/// Only [`TxPipeline::simulate`] issues one and +/// [`TxPipeline::submit_simulated`] takes it. A sponsor that co-signs a +/// client's transaction pays its fee even when it fails on-chain, and a +/// shape check cannot show that the client can fund it, so such a +/// transaction is broadcast only through this proof. +#[derive(Debug, Clone)] +pub struct SimulatedTransaction { + transaction: VersionedTransaction, +} + +impl SimulatedTransaction { + /// The simulated transaction. + pub fn transaction(&self) -> &VersionedTransaction { + &self.transaction + } +} + +impl TxPipeline { + /// Simulate the fully signed `transaction` at confirmed commitment with + /// signature verification and its own recent blockhash. + /// + /// A failed simulation of a transaction whose signature has already + /// landed (a retry whose first response was lost) still yields the proof: + /// rebroadcasting it cannot charge its fee payer again. + pub async fn simulate( + &self, + transaction: VersionedTransaction, + ) -> PipelineResult { + let signature = *transaction + .signatures + .first() + .ok_or(TxPipelineError::MissingSignature)?; + let unavailable = TxPipelineError::SimulationUnavailable { signature }; + let encoded = crate::core::tx::encode(&transaction).map_err(|_| unavailable.clone())?; + let response: serde_json::Value = self + .inner + .rpc + .send( + RpcRequest::SimulateTransaction, + serde_json::json!([encoded, { + "encoding": "base64", + "commitment": "confirmed", + "sigVerify": true, + "replaceRecentBlockhash": false, + }]), + ) + .await + .map_err(|_| unavailable.clone())?; + let value = response.get("value").ok_or(unavailable)?; + match value.get("err") { + None | Some(serde_json::Value::Null) => Ok(SimulatedTransaction { transaction }), + Some(error) => { + if self.landed_slot(signature).await?.is_some() { + return Ok(SimulatedTransaction { transaction }); + } + Err(TxPipelineError::SimulationFailed { + signature, + reason: error.to_string(), + }) + } + } + } + + /// [`Self::submit_verified`] for a transaction that passed + /// [`Self::simulate`]. + pub async fn submit_simulated( + &self, + simulated: &SimulatedTransaction, + ) -> PipelineResult { + self.submit_verified(&simulated.transaction).await + } +} + async fn run_confirmation_tracker( rpc: Arc, config: TxPipelineConfig, @@ -1357,4 +1469,91 @@ mod tests { rpc.abort(); } } + + mod simulation { + use super::*; + + /// `simulateTransaction` reports `simulation_err`; the signature has + /// landed when `landed` is set. Counts every `sendTransaction`. + async fn simulating_rpc( + simulation_err: Value, + landed: bool, + ) -> (String, Arc, tokio::task::JoinHandle<()>) { + let sends = Arc::new(AtomicUsize::new(0)); + let counter = Arc::clone(&sends); + let app = Router::new().route( + "/", + post(move |Json(request): Json| { + let simulation_err = simulation_err.clone(); + let counter = Arc::clone(&counter); + async move { + let result = match request["method"].as_str().unwrap() { + "simulateTransaction" => { + assert_eq!(request["params"][1]["sigVerify"], true); + assert_eq!(request["params"][1]["replaceRecentBlockhash"], false); + json!({ "context": { "slot": 9 }, "value": { "err": simulation_err } }) + } + "getSignatureStatuses" => { + let status = landed.then(|| { + json!({ + "slot": 8, "confirmations": null, "err": null, + "confirmationStatus": "finalized", "status": { "Ok": null } + }) + }); + json!({ "context": { "slot": 9 }, "value": [status] }) + } + "sendTransaction" => { + counter.fetch_add(1, Ordering::SeqCst); + json!(Signature::default().to_string()) + } + method => panic!("unexpected RPC method {method}"), + }; + Json(json!({ "jsonrpc": "2.0", "id": request["id"], "result": result })) + } + }), + ); + let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap(); + let url = format!("http://{}", listener.local_addr().unwrap()); + let server = tokio::spawn(async move { axum::serve(listener, app).await.unwrap() }); + (url, sends, server) + } + + fn transaction() -> VersionedTransaction { + VersionedTransaction { + signatures: vec![Signature::new_unique()], + message: solana_message::VersionedMessage::Legacy(solana_message::Message::new( + &[], + Some(&Pubkey::new_unique()), + )), + } + } + + #[tokio::test] + async fn a_failing_simulation_yields_no_proof() { + let failure = json!({ "InstructionError": [0, { "Custom": 1 }] }); + let (url, sends, rpc) = simulating_rpc(failure, false).await; + let pipeline = TxPipeline::new(url, test_config()); + let error = pipeline.simulate(transaction()).await.unwrap_err(); + assert!( + matches!(error, TxPipelineError::SimulationFailed { .. }), + "{error:?}" + ); + assert_eq!(sends.load(Ordering::SeqCst), 0); + rpc.abort(); + } + + #[tokio::test] + async fn a_clean_or_already_landed_simulation_is_a_proof() { + for (simulation_err, landed) in + [(Value::Null, false), (json!("AlreadyProcessed"), true)] + { + let (url, _, rpc) = simulating_rpc(simulation_err, landed).await; + let pipeline = TxPipeline::new(url, test_config()); + let tx = transaction(); + let simulated = pipeline.simulate(tx.clone()).await.unwrap(); + assert_eq!(simulated.transaction().signatures, tx.signatures); + rpc.abort(); + } + } + } } diff --git a/rust/crates/kit/src/gate.rs b/rust/crates/kit/src/gate.rs index af57a449c..48b33b0c1 100644 --- a/rust/crates/kit/src/gate.rs +++ b/rust/crates/kit/src/gate.rs @@ -31,7 +31,7 @@ use std::sync::{Arc, Mutex}; -use axum::body::{to_bytes, Body, HttpBody}; +use axum::body::{to_bytes, Body}; use axum::extract::{FromRequestParts, Request, State}; use axum::handler::Handler; use axum::http::request::Parts; @@ -62,9 +62,6 @@ const PAYMENT_RECEIPT_HEADER: &str = "Payment-Receipt"; /// Marks a response whose authorization was already charged and served. const PAYMENT_REPLAY_HEADER: HeaderName = HeaderName::from_static("payment-replay"); -/// Avoid turning the channel store into an unbounded response-body cache. -const MAX_CACHED_RESPONSE_BYTES: u64 = 1024 * 1024; - /// Error returned when a [`PayKit`] can't be built from its config. #[derive(Debug)] pub enum PayKitError { @@ -997,20 +994,96 @@ async fn upto_gate_middleware( reference: open.channel_id.to_string(), }); req.extensions_mut().insert(charge); + // The channel is open from here on: if this request future is dropped + // (a client disconnect, a timeout layer) before the settlement below is + // spawned, the guard settles what was metered so the escrow and the fee + // payer's rent are not left in an open channel nothing remembers. + let open = OpenedUpto::new(&upto, open, cell.clone(), UPTO_SETTLEMENT_RETRY); // A lazy body may meter while it is polled, after the handler future has // returned, so the charge is read only once the body is complete. let metered = buffer_metered_response(next.run(req).await).await; // Recover from poisoning so a handler that panicked *after* recording a // charge still settles the amount it consumed (not a silent zero refund). - let actual = (*cell.lock().unwrap_or_else(|e| e.into_inner())).unwrap_or(0); + let actual = metered_charge(&cell); let metered = metered.map(|mut resp| { prevent_shared_caching(&mut resp); resp }); - ServedUpto::settle(&upto, open, actual, metered, UPTO_SETTLEMENT_RETRY) - .respond(&upto) - .await + ServedUpto::settle( + &upto, + open.into_open(), + actual, + metered, + UPTO_SETTLEMENT_RETRY, + ) + .respond(&upto) + .await +} + +/// The amount a handler metered, zero when it metered nothing. +fn metered_charge(cell: &Mutex>) -> u64 { + (*cell.lock().unwrap_or_else(|e| e.into_inner())).unwrap_or(0) +} + +/// An `upto` channel opened for a request whose settlement is not yet +/// spawned. Dropped without [`OpenedUpto::into_open`], it spawns the +/// settlement of what was metered so far, so a cancelled request cannot +/// strand the channel. +struct OpenedUpto { + upto: Arc, + open: Option, + cell: Arc>>, + retry: UptoSettlementRetry, +} + +impl OpenedUpto { + fn new( + upto: &Arc, + open: crate::x402::server::VerifiedUptoOpen, + cell: Arc>>, + retry: UptoSettlementRetry, + ) -> Self { + Self { + upto: Arc::clone(upto), + open: Some(open), + cell, + retry, + } + } + + /// Hand the open to the caller, which now owns its settlement. + fn into_open(mut self) -> crate::x402::server::VerifiedUptoOpen { + self.open.take().expect("taken only here") + } +} + +impl Drop for OpenedUpto { + fn drop(&mut self) { + let Some(open) = self.open.take() else { + return; + }; + let actual = metered_charge(&self.cell); + let upto = Arc::clone(&self.upto); + let retry = self.retry; + let channel = open.channel_id; + match tokio::runtime::Handle::try_current() { + Ok(runtime) => { + tracing::warn!( + channel = %channel, + actual, + "upto request dropped before settlement; settling what was metered" + ); + runtime.spawn(async move { + settle_served_upto(&upto, open, actual, retry).await; + }); + } + Err(_) => tracing::error!( + channel = %channel, + "upto request dropped outside a runtime; the channel is left open" + ), + } + } } /// A served `upto` request whose settlement already runs on its own task, so @@ -1567,35 +1640,15 @@ fn exact_memo(method: &Method, resource: &str) -> String { format!("{method} {}", bs58::encode(digest).into_string()) } -/// Answer a request whose authorization was already charged and served. -/// -/// The payment result is authoritative and is returned verbatim. When the -/// original resource response was cached, restore that representation too. +/// Answer a request whose authorization was already charged and served with +/// its settlement result only. The resource is never replayed: the voucher +/// that reaches this path is public once a claim publishes it or a corrective +/// 402 returns it, so it proves nothing about who sent the original request. fn replayed_response( batch: &X402BatchSettlement, settlement: &crate::x402::batch_settlement::BatchSettlementResponse, - cached: Option<&crate::core::store::CachedUpstreamResponse>, ) -> Response { - let mut resp = if let Some(cached) = cached { - let status = StatusCode::from_u16(cached.status).unwrap_or(StatusCode::OK); - let mut response = (status, cached.body.clone()).into_response(); - if let Some(content_type) = &cached.content_type { - if let Ok(value) = HeaderValue::from_str(content_type) { - response.headers_mut().insert(header::CONTENT_TYPE, value); - } - } - for (name, value) in &cached.headers { - if let (Ok(name), Ok(value)) = ( - HeaderName::from_bytes(name.as_bytes()), - HeaderValue::from_str(value), - ) { - response.headers_mut().append(name, value); - } - } - response - } else { - StatusCode::OK.into_response() - }; + let mut resp = StatusCode::OK.into_response(); prevent_shared_caching(&mut resp); resp.headers_mut() .insert(PAYMENT_REPLAY_HEADER, HeaderValue::from_static("true")); @@ -1603,80 +1656,6 @@ fn replayed_response( resp } -/// Headers whose meaning belongs to the stored representation rather than to -/// this particular transport hop or payment attempt. -fn is_replayable_response_header(name: &HeaderName) -> bool { - matches!( - name.as_str(), - "accept-ranges" - | "cache-control" - | "content-security-policy" - | "content-security-policy-report-only" - | "content-disposition" - | "content-encoding" - | "content-language" - | "content-location" - | "content-range" - | "cross-origin-embedder-policy" - | "cross-origin-opener-policy" - | "cross-origin-resource-policy" - | "etag" - | "expires" - | "last-modified" - | "location" - | "permissions-policy" - | "referrer-policy" - | "reporting-endpoints" - | "strict-transport-security" - | "vary" - | "x-content-type-options" - | "x-frame-options" - | "x-permitted-cross-domain-policies" - | "x-xss-protection" - ) -} - -/// Buffer a small, finite handler response so an authorization replay can -/// return the same representation. Streaming and large responses pass through -/// untouched and retain settlement-only replay semantics. -async fn cacheable_response( - response: Response, -) -> Result<(Response, Option), axum::Error> { - let size = response.body().size_hint(); - if size - .upper() - .is_none_or(|upper| upper > MAX_CACHED_RESPONSE_BYTES) - { - return Ok((response, None)); - } - - let (parts, body) = response.into_parts(); - let bytes = to_bytes(body, MAX_CACHED_RESPONSE_BYTES as usize).await?; - let content_type = parts - .headers - .get(header::CONTENT_TYPE) - .and_then(|value| value.to_str().ok()) - .map(ToOwned::to_owned); - let headers = parts - .headers - .iter() - .filter(|(name, _)| is_replayable_response_header(name)) - .filter_map(|(name, value)| { - value - .to_str() - .ok() - .map(|value| (name.as_str().to_owned(), value.to_owned())) - }) - .collect(); - let cached = crate::core::store::CachedUpstreamResponse { - status: parts.status.as_u16(), - content_type, - headers, - body: bytes.to_vec(), - }; - Ok((Response::from_parts(parts, Body::from(bytes)), Some(cached))) -} - /// High-throughput gate for x402 `batch-settlement`, under the scheme's /// `authorization` payment flow. /// @@ -1749,8 +1728,8 @@ async fn batch_gate_middleware( // Already charged and served. The client lost the response, not the // payment, so it gets the original result — never a second charge and // never a second execution. - BatchAccess::Replay(settlement, cached) => { - return replayed_response(&batch, &settlement, cached.as_ref()); + BatchAccess::Replay(settlement, _) => { + return replayed_response(&batch, &settlement); } // Another in-flight request owns this authorization. The retryable @@ -1771,7 +1750,7 @@ async fn batch_gate_middleware( // unfinished. Finishing it is the one safe continuation. BatchAccess::Resume(outcome) => { return match batch.finish_commit(&outcome).await { - Ok(settlement) => replayed_response(&batch, &settlement, None), + Ok(settlement) => replayed_response(&batch, &settlement), Err(e) => { tracing::error!(error = %e, "batch-settlement commit could not be resumed"); ( @@ -1834,17 +1813,6 @@ async fn batch_gate_middleware( return resp; } - let (mut resp, cached) = match cacheable_response(resp).await { - Ok(response) => response, - Err(error) => { - tracing::warn!(channel = %channel_id, error = %error, "could not buffer handler response for replay"); - ( - (StatusCode::BAD_GATEWAY, "resource response body failed").into_response(), - None, - ) - } - }; - // The crash boundary: past this point a retry may only finish the charge. // // A marker that fails to write is not a reason to abandon the charge. This @@ -1863,15 +1831,6 @@ async fn batch_gate_middleware( match commit_served_request(&batch, &outcome, &channel_id).await { Ok(settlement) => { - if let Some(cached) = cached { - if let Err(error) = batch.cache_response(&outcome, cached).await { - tracing::warn!( - channel = %channel_id, - error = %error, - "batch-settlement response cache write failed" - ); - } - } attach_settlement_header(&batch, &settlement, &mut resp); resp } @@ -2006,7 +1965,7 @@ where #[cfg(test)] mod tests { use super::*; - use axum::body::Body; + use axum::body::{Body, HttpBody}; use axum::Router; use tower::ServiceExt; // oneshot @@ -2981,6 +2940,50 @@ mod tests { ); } + /// A request dropped after its channel opened but before its settlement + /// was spawned still settles: the channel stays reserved by the spawned + /// settlement instead of being forgotten with the request future. + #[tokio::test(flavor = "multi_thread")] + async fn a_request_dropped_after_the_open_still_settles_its_channel() { + let pay = upto_paykit(); + let upto = pay.x402_upto().expect("signer enables upto").clone(); + let retry = UptoSettlementRetry { + inline_attempts: 2, + background_attempts: 1, + base_delay: std::time::Duration::from_millis(200), + }; + let channel = solana_pubkey::Pubkey::new_unique(); + let cell = Arc::new(Mutex::new(Some(300))); + drop(OpenedUpto::new( + &upto, + upto.test_open(channel, 1_000), + cell, + retry, + )); + assert!( + upto.is_in_flight(&channel), + "the dropped request's settlement holds the channel" + ); + for _ in 0..100 { + if !upto.is_in_flight(&channel) { + break; + } + tokio::time::sleep(std::time::Duration::from_millis(50)).await; + } + assert!(!upto.is_in_flight(&channel)); + + // Positive control: handed on for settlement, the guard spawns nothing. + let channel = solana_pubkey::Pubkey::new_unique(); + let opened = OpenedUpto::new( + &upto, + upto.test_open(channel, 1_000), + Arc::new(Mutex::new(None)), + retry, + ); + drop(opened.into_open()); + assert!(!upto.is_in_flight(&channel)); + } + /// A client disconnect during the inline retries drops the request future; /// the settlement keeps running and keeps the channel reserved. #[tokio::test(flavor = "multi_thread")] @@ -3143,6 +3146,110 @@ mod tests { responses } + /// The latest voucher of a channel is public (a claim publishes it, a + /// corrective 402 returns it), so presenting it again must not return + /// the payer's response body, and text a client put in its channel + /// config must not be able to request the corrective snapshot. + #[tokio::test(flavor = "multi_thread")] + async fn batch_replay_and_corrective_402_do_not_leak_the_payers_response() { + use crate::x402::batch_settlement::errors as codes; + + // A fresh challenge reads a blockhash; the corrective one reads none. + let (rpc_url, _) = mock_rpc(false).await; + let pay = exact_paykit(rpc_url, Some(test_signer())); + let (channel_id, header) = batch_paid_request(&pay).await; + let handler = || async { "victim-secret" }; + let app: Router = Router::new().route("/orders", paid_batch_post(handler, "0.001", &pay)); + let post = |header: String| { + let app = app.clone(); + async move { + app.oneshot( + Request::builder() + .method("POST") + .uri("/orders") + .header(PAYMENT_SIGNATURE_HEADER, header) + .body(Body::empty()) + .unwrap(), + ) + .await + .unwrap() + } + }; + let body_of = |resp: Response| async move { + String::from_utf8(to_bytes(resp.into_body(), 1 << 20).await.unwrap().to_vec()).unwrap() + }; + let edited = |edit: &dyn Fn(&mut serde_json::Value)| { + use base64::Engine as _; + let engine = base64::engine::general_purpose::STANDARD; + let mut value: serde_json::Value = + serde_json::from_slice(&engine.decode(&header).unwrap()).unwrap(); + edit(&mut value); + engine.encode(serde_json::to_vec(&value).unwrap()) + }; + let challenge_of = |resp: &Response| -> serde_json::Value { + use base64::Engine as _; + let encoded = resp.headers()["payment-required"].to_str().unwrap(); + serde_json::from_slice( + &base64::engine::general_purpose::STANDARD + .decode(encoded) + .unwrap(), + ) + .unwrap() + }; + + let served = post(header.clone()).await; + assert_eq!(served.status(), StatusCode::OK); + assert_eq!(body_of(served).await, "victim-secret"); + + // Resending the committed voucher replays the settlement only. + let replay = post(header.clone()).await; + assert_eq!(replay.status(), StatusCode::OK); + assert_eq!(replay.headers()[PAYMENT_REPLAY_HEADER], "true"); + assert!(!body_of(replay).await.contains("victim-secret")); + + // A mismatch code planted in a client-supplied field is not the + // server's mismatch: no snapshot, and the raised code is reported. + let injected = post(edited(&|value| { + value["payload"]["channelConfig"]["receiver"] = + codes::INVALID_CUMULATIVE_AMOUNT_MISMATCH.into(); + })) + .await; + assert_eq!(injected.status(), StatusCode::PAYMENT_REQUIRED); + let challenge = challenge_of(&injected); + assert_eq!(challenge["error"], codes::INVALID_CHANNEL_STATE); + assert!(challenge["accepts"][0]["extra"] + .get("voucherState") + .is_none()); + + // Positive control: a genuine mismatch still resynchronizes the client. + let skipped = { + use ed25519_dalek::Signer as _; + let channel = channel_id.parse().unwrap(); + let message = crate::core::payment_channels::voucher_message_bytes( + &channel, + 5_000, + crate::x402::batch_settlement::VOUCHER_EXPIRES_AT, + ) + .unwrap(); + let key = ed25519_dalek::SigningKey::from_bytes(&[22u8; 32]); + bs58::encode(key.sign(&message).to_bytes()).into_string() + }; + let stale = post(edited(&|value| { + value["payload"]["voucher"]["maxClaimableAmount"] = "5000".into(); + value["payload"]["voucher"]["signature"] = skipped.clone().into(); + })) + .await; + assert_eq!(stale.status(), StatusCode::PAYMENT_REQUIRED); + let challenge = challenge_of(&stale); + assert_eq!( + challenge["error"], + codes::INVALID_CUMULATIVE_AMOUNT_MISMATCH + ); + assert!(challenge["accepts"][0]["extra"] + .get("channelState") + .is_some()); + } + /// A state-changing handler that answers with a redirect is charged, so /// the same voucher cannot run it a second time for free. #[tokio::test(flavor = "multi_thread")] @@ -3171,10 +3278,12 @@ mod tests { let responses = post_twice(app, &header).await; assert_eq!(responses[0].status(), StatusCode::SEE_OTHER); assert!(responses[0].headers().contains_key(PAYMENT_RESPONSE_HEADER)); - // The retry replays the committed redirect instead of re-running it. - assert_eq!(responses[1].status(), StatusCode::SEE_OTHER); + // The retry replays the committed settlement instead of re-running + // the handler; the representation itself is not replayed. + assert_eq!(responses[1].status(), StatusCode::OK); assert_eq!(responses[1].headers()[PAYMENT_REPLAY_HEADER], "true"); - assert_eq!(responses[1].headers()[header::LOCATION], "/orders/created"); + assert!(responses[1].headers().contains_key(PAYMENT_RESPONSE_HEADER)); + assert!(!responses[1].headers().contains_key(header::LOCATION)); assert_eq!(executions.load(Ordering::SeqCst), 1); let state = pay @@ -3209,9 +3318,7 @@ mod tests { let app: Router = Router::new().route("/orders", paid_batch_post(handler, "0.001", &pay)); let responses = post_twice(app, &header).await; - assert!(responses - .iter() - .all(|r| r.status() == StatusCode::SERVICE_UNAVAILABLE)); + assert_eq!(responses[0].status(), StatusCode::SERVICE_UNAVAILABLE); assert_eq!(responses[1].headers()[PAYMENT_REPLAY_HEADER], "true"); assert_eq!(executions.load(Ordering::SeqCst), 1); let state = pay @@ -4148,62 +4255,4 @@ mod tests { assert!(!resp.headers().contains_key(PAYMENT_RESPONSE_HEADER)); assert_eq!(served.load(std::sync::atomic::Ordering::SeqCst), 0); } - - #[tokio::test] - async fn batch_response_cache_keeps_representation_headers_only() { - let mut response = (StatusCode::TEMPORARY_REDIRECT, "moved").into_response(); - response - .headers_mut() - .insert(header::LOCATION, HeaderValue::from_static("/destination")); - response.headers_mut().insert( - header::CONTENT_DISPOSITION, - HeaderValue::from_static("attachment; filename=report.txt"), - ); - response.headers_mut().insert( - HeaderName::from_static("content-security-policy"), - HeaderValue::from_static("default-src 'none'"), - ); - response.headers_mut().insert( - HeaderName::from_static("x-content-type-options"), - HeaderValue::from_static("nosniff"), - ); - response.headers_mut().insert( - HeaderName::from_static("x-frame-options"), - HeaderValue::from_static("DENY"), - ); - response - .headers_mut() - .insert(header::CONNECTION, HeaderValue::from_static("close")); - response.headers_mut().insert( - HeaderName::from_static("payment-response"), - HeaderValue::from_static("attempt-specific"), - ); - - let (_, cached) = cacheable_response(response).await.unwrap(); - let cached = cached.expect("small finite response is cached"); - assert_eq!(cached.status, StatusCode::TEMPORARY_REDIRECT.as_u16()); - assert!(cached - .headers - .contains(&("location".to_string(), "/destination".to_string()))); - assert!(cached.headers.contains(&( - "content-disposition".to_string(), - "attachment; filename=report.txt".to_string() - ))); - assert!(cached.headers.contains(&( - "content-security-policy".to_string(), - "default-src 'none'".to_string() - ))); - assert!(cached - .headers - .contains(&("x-content-type-options".to_string(), "nosniff".to_string()))); - assert!(cached - .headers - .contains(&("x-frame-options".to_string(), "DENY".to_string()))); - assert!(!cached.headers.iter().any(|(name, _)| name == "connection")); - assert!(!cached - .headers - .iter() - .any(|(name, _)| name == "payment-response")); - assert_eq!(cached.body, b"moved"); - } } diff --git a/rust/crates/kit/src/mpp/client/charge.rs b/rust/crates/kit/src/mpp/client/charge.rs index 98a688582..a7bce44c4 100644 --- a/rust/crates/kit/src/mpp/client/charge.rs +++ b/rust/crates/kit/src/mpp/client/charge.rs @@ -86,10 +86,11 @@ pub struct BuildChargeTransactionOptions { pub expected_recipient: Option, /// What to do when the signer is the fee payer and a split sets /// `ataCreationRequired`. The charge spec says the client MUST include - /// the ATA creation, so the default funds it; [`PayerFundedAtaCreation::Decline`] - /// refuses the whole challenge instead (never a transaction without it). - /// The rent is not counted against `max_amount_base_units`, so callers - /// that auto-pay untrusted challenges should decline, as `PayKitClient` does. + /// the ATA creation, and the rent is spent on top of `amount`, outside + /// `max_amount_base_units`. The default, [`PayerFundedAtaCreation::Decline`], + /// refuses the whole challenge (never a transaction without the creation); + /// [`PayerFundedAtaCreation::Include`] funds it for a server the caller + /// trusts to name split recipients. pub payer_funded_ata_creation: PayerFundedAtaCreation, /// Bounded compute-unit price/limit for the prepared /// transaction. Defaults match the historical hardcoded budget (1 @@ -103,15 +104,15 @@ pub struct BuildChargeTransactionOptions { /// /// The charge spec obliges the client: when it pays the fees it "MUST include /// one for each split whose entry sets `ataCreationRequired: true`". The rent -/// is spent on top of the charged amount, so a wallet that will not fund it -/// declines the challenge. There is no variant that builds the transaction -/// without the creation instruction. +/// is spent on top of the charged amount and goes to accounts the challenge +/// names, so a wallet declines unless its caller opts in. There is no variant +/// that builds the transaction without the creation instruction. #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] pub enum PayerFundedAtaCreation { - /// Include the ATA creation instructions and fund their rent (spec default). - #[default] + /// Include the ATA creation instructions and fund their rent. Include, /// Refuse the challenge with [`Error::PayerFundedAtaCreationDeclined`]. + #[default] Decline, } @@ -2789,7 +2790,10 @@ mod tests { USDC_MINT, RECIPIENT, &md, - &BuildChargeTransactionOptions::default(), + &BuildChargeTransactionOptions { + payer_funded_ata_creation: PayerFundedAtaCreation::Include, + ..Default::default() + }, ) .await .unwrap_err(); @@ -4184,19 +4188,64 @@ mod tests { .count() } - // RULINGS C5: with the client as fee payer, `ataCreationRequired` obliges - // the client to include the creation. Regression: the default used to - // refuse the challenge. + // The rent for split ATAs the client funds sits outside any amount cap + // and goes to accounts the challenge names, so the default declines + // (RULINGS C5: declining is conformant), even with an amount cap set. #[tokio::test] - async fn build_charge_includes_payer_funded_split_ata_by_default() { + async fn build_charge_declines_payer_funded_split_ata_by_default() { let signer = make_signer(); let rpc = dummy_rpc(); let md = ata_split_details(None); - let payload = + let err = build_charge_transaction(signer.as_ref(), &rpc, "1000000", USDC_MINT, RECIPIENT, &md) .await - .unwrap(); + .unwrap_err(); + assert!( + matches!(err, crate::mpp::Error::PayerFundedAtaCreationDeclined), + "{err:?}" + ); + let err = build_charge_transaction_with_options( + signer.as_ref(), + &rpc, + "1000000", + USDC_MINT, + RECIPIENT, + &md, + BuildChargeTransactionOptions { + max_amount_base_units: Some(1_000_000), + ..Default::default() + }, + ) + .await + .unwrap_err(); + assert!( + matches!(err, crate::mpp::Error::PayerFundedAtaCreationDeclined), + "{err:?}" + ); + } + + // RULINGS C5: a caller that opts in gets every flagged creation. + #[tokio::test] + async fn build_charge_includes_payer_funded_split_ata_on_opt_in() { + let signer = make_signer(); + let rpc = dummy_rpc(); + let md = ata_split_details(None); + + let payload = build_charge_transaction_with_options( + signer.as_ref(), + &rpc, + "1000000", + USDC_MINT, + RECIPIENT, + &md, + BuildChargeTransactionOptions { + payer_funded_ata_creation: PayerFundedAtaCreation::Include, + ..Default::default() + }, + ) + .await + .unwrap(); assert_eq!(ata_create_count(&payload), 8); } diff --git a/rust/crates/kit/src/mpp/client/http_stream.rs b/rust/crates/kit/src/mpp/client/http_stream.rs index 01f9d7a75..861a79dc5 100644 --- a/rust/crates/kit/src/mpp/client/http_stream.rs +++ b/rust/crates/kit/src/mpp/client/http_stream.rs @@ -35,13 +35,26 @@ struct PartialSseEvent { retry: Option, } +/// Longest SSE line [`SseDecoder`] buffers while waiting for its newline. +pub const MAX_SSE_LINE_BYTES: usize = 1024 * 1024; + +/// Largest event [`SseDecoder`] assembles from its `data` lines. +pub const MAX_SSE_EVENT_BYTES: usize = 1024 * 1024; + +/// Largest commit-endpoint response [`HttpCommitTransport`] reads. +const MAX_COMMIT_RESPONSE_BYTES: usize = 64 * 1024; + /// Incremental SSE decoder. /// /// Feed raw HTTP chunks with [`push_chunk`](Self::push_chunk). It returns all /// complete events decoded from that chunk and retains partial data internally. +/// A line longer than [`MAX_SSE_LINE_BYTES`] or an event larger than +/// [`MAX_SSE_EVENT_BYTES`] is an error, so a stream cannot grow the buffer +/// without bound. #[derive(Default)] pub struct SseDecoder { - buffer: String, + /// Bytes of the line in progress; never holds a newline. + buffer: Vec, current: PartialSseEvent, } @@ -51,32 +64,44 @@ impl SseDecoder { } pub fn push_chunk(&mut self, chunk: &[u8]) -> Result> { - let text = std::str::from_utf8(chunk) - .map_err(|e| Error::Other(format!("SSE chunk is not valid UTF-8: {e}")))?; - self.buffer.push_str(text); - let mut events = vec![]; - while let Some(index) = self.buffer.find('\n') { - let mut line = self.buffer.drain(..=index).collect::(); - if line.ends_with('\n') { + let mut rest = chunk; + // Only the new bytes are scanned for a newline, and a line is decoded + // once it is complete, so a character split across chunks is intact. + while let Some(index) = rest.iter().position(|byte| *byte == b'\n') { + self.extend_line(&rest[..index])?; + rest = &rest[index + 1..]; + let mut line = std::mem::take(&mut self.buffer); + if line.last() == Some(&b'\r') { line.pop(); } - if line.ends_with('\r') { - line.pop(); - } - if let Some(event) = self.process_line(&line)? { + if let Some(event) = self.process_line(&decode_line(line)?)? { events.push(event); } } + self.extend_line(rest)?; Ok(events) } + fn extend_line(&mut self, bytes: &[u8]) -> Result<()> { + if self.buffer.len() + bytes.len() > MAX_SSE_LINE_BYTES { + return Err(Error::Other(format!( + "SSE line exceeds {MAX_SSE_LINE_BYTES} bytes" + ))); + } + self.buffer.extend_from_slice(bytes); + Ok(()) + } + /// Flush an incomplete final event, if any, at EOF. pub fn finish(&mut self) -> Result> { let mut events = vec![]; if !self.buffer.is_empty() { - let line = std::mem::take(&mut self.buffer); - if let Some(event) = self.process_line(line.trim_end_matches('\r'))? { + let mut line = std::mem::take(&mut self.buffer); + if line.last() == Some(&b'\r') { + line.pop(); + } + if let Some(event) = self.process_line(&decode_line(line)?)? { events.push(event); } } @@ -102,6 +127,11 @@ impl SseDecoder { match field { "event" => self.current.event = Some(value.to_string()), "data" => { + if self.current.data.len() + value.len() + 1 > MAX_SSE_EVENT_BYTES { + return Err(Error::Other(format!( + "SSE event data exceeds {MAX_SSE_EVENT_BYTES} bytes" + ))); + } if !self.current.data.is_empty() { self.current.data.push('\n'); } @@ -135,6 +165,28 @@ impl SseDecoder { } } +fn decode_line(line: Vec) -> Result { + String::from_utf8(line).map_err(|e| Error::Other(format!("SSE line is not valid UTF-8: {e}"))) +} + +/// Read at most `limit` bytes of `response`, failing past it. +async fn read_capped(mut response: reqwest::Response, limit: usize) -> Result> { + let mut body = Vec::new(); + while let Some(chunk) = response + .chunk() + .await + .map_err(|e| Error::Other(format!("commit response read failed: {e}")))? + { + if body.len() + chunk.len() > limit { + return Err(Error::Other(format!( + "commit response exceeds {limit} bytes" + ))); + } + body.extend_from_slice(&chunk); + } + Ok(body) +} + /// Parsed metered SSE event. #[derive(Debug, Clone, PartialEq)] pub enum MeteredSseEvent { @@ -367,15 +419,17 @@ impl CommitTransport for HttpCommitTransport { .map_err(|e| Error::Other(format!("commit request failed: {e}")))?; let status = response.status(); if !status.is_success() { - let body = response.text().await.unwrap_or_default(); + let body = read_capped(response, MAX_COMMIT_RESPONSE_BYTES) + .await + .map(|body| String::from_utf8_lossy(&body).into_owned()) + .unwrap_or_default(); return Err(Error::Other(format!( "commit endpoint returned {status}: {body}" ))); } - response - .json::() - .await + let body = read_capped(response, MAX_COMMIT_RESPONSE_BYTES).await?; + serde_json::from_slice::(&body) .map_err(|e| Error::Other(format!("invalid commit receipt: {e}"))) }) } @@ -503,6 +557,10 @@ mod tests { Box::new(MemorySigner::from_bytes(&kp).unwrap()) } + fn budget() -> super::super::session_consumer::MeteringBudget { + super::super::session_consumer::MeteringBudget::new(10_000, 100_000).unwrap() + } + fn directive(session_id: &str) -> MeteringDirective { MeteringDirective { delivery_id: "stream-1".to_string(), @@ -612,10 +670,66 @@ mod tests { #[test] fn sse_decoder_rejects_invalid_utf8() { - let err = SseDecoder::new().push_chunk(&[0xff]).unwrap_err(); + let err = SseDecoder::new().push_chunk(&[0xff, b'\n']).unwrap_err(); assert!(err.to_string().contains("valid UTF-8")); } + #[test] + fn sse_decoder_keeps_a_character_split_across_chunks() { + let mut decoder = SseDecoder::new(); + let text = "data: caf\u{e9}\n\n".as_bytes(); + let split = text.len() - 3; + assert!(decoder.push_chunk(&text[..split]).unwrap().is_empty()); + let events = decoder.push_chunk(&text[split..]).unwrap(); + assert_eq!(events[0].data, "caf\u{e9}"); + } + + #[test] + fn sse_decoder_bounds_an_unterminated_line() { + let mut decoder = SseDecoder::new(); + let chunk = vec![b'A'; 64 * 1024]; + let mut buffered = 0; + let err = loop { + match decoder.push_chunk(&chunk) { + Ok(events) => { + assert!(events.is_empty()); + buffered += chunk.len(); + assert!(buffered <= MAX_SSE_LINE_BYTES, "line grew past the cap"); + } + Err(err) => break err, + } + }; + assert!(err.to_string().contains("SSE line exceeds"), "{err}"); + + // A line at the cap still decodes. + let mut decoder = SseDecoder::new(); + let mut line = b"data: ".to_vec(); + line.resize(MAX_SSE_LINE_BYTES, b'A'); + assert!(decoder.push_chunk(&line).unwrap().is_empty()); + let events = decoder.push_chunk(b"\n\n").unwrap(); + assert_eq!(events[0].data.len(), MAX_SSE_LINE_BYTES - "data: ".len()); + } + + #[test] + fn sse_decoder_bounds_an_event_built_from_many_lines() { + let mut decoder = SseDecoder::new(); + let mut line = b"data: ".to_vec(); + line.extend(std::iter::repeat_n(b'A', 64 * 1024)); + line.push(b'\n'); + let mut pushed = 0; + let err = loop { + match decoder.push_chunk(&line) { + Ok(events) => { + assert!(events.is_empty()); + pushed += line.len(); + assert!(pushed <= 2 * MAX_SSE_EVENT_BYTES, "event grew past the cap"); + } + Err(err) => break err, + } + }; + assert!(err.to_string().contains("SSE event data exceeds"), "{err}"); + } + #[test] fn parse_metered_sse_events() { let metering = SseEvent { @@ -678,7 +792,7 @@ mod tests { let transport = RecordingTransport { commits: Mutex::new(vec![]), }; - let mut consumer = SessionConsumer::new(session, transport); + let mut consumer = SessionConsumer::new(session, transport, budget()); let mut stream = consumer.metered_sse::(); let directive = directive(&stream.consumer.session().channel_id_str()); @@ -723,7 +837,7 @@ mod tests { let transport = RecordingTransport { commits: Mutex::new(vec![]), }; - let mut consumer = SessionConsumer::new(session, transport); + let mut consumer = SessionConsumer::new(session, transport, budget()); let mut stream = consumer.metered_sse::(); let directive = directive(&stream.consumer.session().channel_id_str()); @@ -748,7 +862,7 @@ mod tests { let transport = RecordingTransport { commits: Mutex::new(vec![]), }; - let mut consumer = SessionConsumer::new(session, transport); + let mut consumer = SessionConsumer::new(session, transport, budget()); let stream = consumer.metered_sse::(); let err = stream.ack().await.unwrap_err(); assert!(err.to_string().contains("mpp.metering")); @@ -777,7 +891,7 @@ mod tests { let transport = RecordingTransport { commits: Mutex::new(vec![]), }; - let mut consumer = SessionConsumer::new(session, transport); + let mut consumer = SessionConsumer::new(session, transport, budget()); let mut stream = consumer.metered_sse::(); let directive = directive(&stream.consumer.session().channel_id_str()); assert_eq!(directive.amount, "1000"); @@ -816,6 +930,38 @@ mod tests { assert_eq!(consumer.session().cumulative, 1000); } + #[tokio::test] + async fn metered_sse_ack_refuses_a_reservation_past_the_budget() { + let session = super::super::session::ActiveSession::new(Pubkey::new_unique(), signer()); + let transport = RecordingTransport { + commits: Mutex::new(vec![]), + }; + let budget = super::super::session_consumer::MeteringBudget::new(500, 1_000).unwrap(); + let mut consumer = SessionConsumer::new(session, transport, budget); + let session_id = consumer.session().channel_id_str(); + let metering = |amount: &str| SseEvent { + event: Some("mpp.metering".to_string()), + data: serde_json::to_string(&MeteringDirective { + amount: amount.to_string(), + ..directive(&session_id) + }) + .unwrap(), + id: None, + retry: None, + }; + + let mut stream = consumer.metered_sse::(); + stream.accept_event(metering("501")).unwrap(); + let err = stream.ack().await.unwrap_err(); + assert!(err.to_string().contains("per-delivery budget"), "{err}"); + assert_eq!(consumer.session().cumulative, 0); + + let mut stream = consumer.metered_sse::(); + stream.accept_event(metering("500")).unwrap(); + assert_eq!(stream.ack().await.unwrap().cumulative, "500"); + assert_eq!(consumer.session().cumulative, 500); + } + #[tokio::test] async fn http_commit_transport_success_and_errors() { let state = CommitServerState::default(); @@ -826,6 +972,10 @@ mod tests { post(|| async { (StatusCode::INTERNAL_SERVER_ERROR, "commit failed") }), ) .route("/commit-invalid-json", post(|| async { "not json" })) + .route( + "/commit-oversized", + post(|| async { " ".repeat(MAX_COMMIT_RESPONSE_BYTES + 1) }), + ) .with_state(state.clone()); let base_url = spawn_app(app).await; @@ -860,10 +1010,17 @@ mod tests { let invalid_json = HttpCommitTransport::new() .with_default_commit_url(format!("{base_url}/commit-invalid-json")) - .commit(&directive, payload) + .commit(&directive, payload.clone()) .await .unwrap_err(); assert!(invalid_json.to_string().contains("invalid commit receipt")); + + let oversized = HttpCommitTransport::new() + .with_default_commit_url(format!("{base_url}/commit-oversized")) + .commit(&directive, payload) + .await + .unwrap_err(); + assert!(oversized.to_string().contains("commit response exceeds")); } #[tokio::test] @@ -901,7 +1058,7 @@ mod tests { let transport = HttpCommitTransport::new() .with_default_commit_url(format!("{base_url}/commit")) .with_authorization("Bearer sdk-test"); - let consumer = SessionConsumer::new(session, transport); + let consumer = SessionConsumer::new(session, transport, budget()); let response = reqwest::Client::new() .get(format!("{base_url}/stream")) .send() @@ -1008,7 +1165,7 @@ mod tests { let transport = HttpCommitTransport::new() .with_default_commit_url(format!("{legitimate_url}/commit")) .with_authorization("Bearer sdk-test"); - let mut consumer = SessionConsumer::new(session, transport); + let mut consumer = SessionConsumer::new(session, transport, budget()); let error = consumer.commit_directive(&directive).await.unwrap_err(); assert!(error.to_string().contains("does not match"), "{error}"); assert!(attacker.commits.lock().unwrap().is_empty()); @@ -1049,6 +1206,7 @@ mod tests { HttpCommitTransport::new() .with_default_commit_url(format!("{redirector}/commit")) .with_authorization("Bearer sdk-test"), + budget(), ); let error = consumer.commit_directive(&directive).await.unwrap_err(); assert!(error.to_string().contains("307"), "{error}"); @@ -1079,6 +1237,7 @@ mod tests { RecordingTransport { commits: Mutex::new(vec![]), }, + budget(), ); let stream = ReqwestMeteredSseStream::<_, Delta>::new(consumer, response); let consumer = stream.into_consumer(); diff --git a/rust/crates/kit/src/mpp/client/mod.rs b/rust/crates/kit/src/mpp/client/mod.rs index a0db49f7a..9e1fcfebc 100644 --- a/rust/crates/kit/src/mpp/client/mod.rs +++ b/rust/crates/kit/src/mpp/client/mod.rs @@ -24,9 +24,9 @@ pub use http_stream::*; pub use session::{ build_open_payment_channel_transaction, create_payment_channel_session_opener, derive_payment_channel_open, BuildOpenPaymentChannelTransactionParams, - DerivePaymentChannelOpenParams, PaymentChannelOpen, PaymentChannelOpenOptions, - PaymentChannelSessionOpen, PaymentChannelSessionOpenOptions, SessionPayout, - DEFAULT_GRACE_PERIOD_SECONDS, + DerivePaymentChannelOpenParams, OpenBlockhash, PaymentChannelOpen, PaymentChannelOpenOptions, + PaymentChannelSessionOpen, PaymentChannelSessionOpenOptions, SessionOpenAuthorization, + SessionPayout, DEFAULT_GRACE_PERIOD_SECONDS, MAX_SESSION_GRACE_PERIOD_SECONDS, }; pub use session_consumer::*; pub use subscription::{ diff --git a/rust/crates/kit/src/mpp/client/session.rs b/rust/crates/kit/src/mpp/client/session.rs index 8668f157a..901dda3b2 100644 --- a/rust/crates/kit/src/mpp/client/session.rs +++ b/rust/crates/kit/src/mpp/client/session.rs @@ -157,7 +157,16 @@ impl ActiveSession { /// Prepare a signed voucher adding `amount` without advancing the watermark. pub async fn prepare_increment(&self, amount: u64) -> Result { - self.prepare_voucher(self.cumulative + amount).await + self.prepare_voucher(self.incremented(amount)?).await + } + + fn incremented(&self, amount: u64) -> Result { + self.cumulative.checked_add(amount).ok_or_else(|| { + Error::Other(format!( + "voucher increment {amount} overflows the cumulative {}", + self.cumulative + )) + }) } /// Record a prepared voucher as accepted by the server. @@ -179,7 +188,7 @@ impl ActiveSession { /// Sign a voucher adding `amount` to the current cumulative. pub async fn sign_increment(&mut self, amount: u64) -> Result { - self.sign_voucher(self.cumulative + amount).await + self.sign_voucher(self.incremented(amount)?).await } /// Build a `SessionAction::Voucher` for an increment without advancing the @@ -383,7 +392,9 @@ pub struct PaymentChannelOpenOptions { /// `None` preserves the core transaction builder's defaults. Explicit /// budgets remain subject to the server's fee-sponsorship policy. pub compute_budget: Option, - pub deposit: Option, + /// Grace period to open with instead of the challenge's + /// `gracePeriodSeconds`. Either is bounded by the authorization's + /// [`SessionOpenAuthorization::max_grace_period`]. pub grace_period: Option, /// Override for the channel's open slot (the program's `openSlot`). /// Defaults to the challenge's `recentSlot`. An override MAY be earlier @@ -422,11 +433,78 @@ impl SessionPayout { } } +/// Longest grace period [`SessionOpenAuthorization`] accepts unless the +/// caller sets another (30 days). The grace period is how long the payer +/// waits, after asking to close, before it can withdraw what was not settled. +pub const MAX_SESSION_GRACE_PERIOD_SECONDS: u32 = 2_592_000; + +/// The escrow terms a caller authorizes for one channel open. +/// +/// A session challenge proposes a deposit, who signs vouchers and how long +/// the payer's exit takes; this decides which of them the client signs. The +/// deposit is the caller's, never the challenge's `suggestedDeposit`; an +/// operator-signed channel, whose operator can settle up to the whole +/// deposit with its own vouchers, needs that operator named here; and the +/// grace period is bounded. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct SessionOpenAuthorization { + deposit: u64, + operator: Option, + max_grace_period: u32, +} + +impl SessionOpenAuthorization { + /// Lock `deposit` base units in a channel whose vouchers the client signs. + /// A challenge asking for operator vouchers is refused. + pub fn client_signed(deposit: u64) -> Self { + Self { + deposit, + operator: None, + max_grace_period: MAX_SESSION_GRACE_PERIOD_SECONDS, + } + } + + /// Lock `deposit` base units and also accept a challenge whose vouchers + /// `operator` signs. That operator can settle up to the whole deposit, so + /// `deposit` is what the caller is prepared to pay it. + pub fn operator_signed(deposit: u64, operator: Pubkey) -> Self { + Self { + operator: Some(operator), + ..Self::client_signed(deposit) + } + } + + /// Replace the grace-period ceiling ([`MAX_SESSION_GRACE_PERIOD_SECONDS`] + /// by default). + pub fn with_max_grace_period(mut self, seconds: u32) -> Result { + if seconds == 0 { + return Err(Error::Other( + "maximum grace period must be greater than zero".to_string(), + )); + } + self.max_grace_period = seconds; + Ok(self) + } + + pub fn deposit(&self) -> u64 { + self.deposit + } + + pub fn operator(&self) -> Option { + self.operator + } + + pub fn max_grace_period(&self) -> u32 { + self.max_grace_period + } +} + #[derive(Debug, Clone)] pub struct DerivePaymentChannelOpenParams<'a> { pub request: &'a SessionRequest, pub payer: Pubkey, pub authorized_signer: Pubkey, + pub authorization: &'a SessionOpenAuthorization, pub options: PaymentChannelOpenOptions, } @@ -458,19 +536,27 @@ pub fn derive_payment_channel_open( "mint", )?; let payee = parse_pubkey(&request.recipient, "recipient")?; - let deposit = match params.options.deposit { - Some(deposit) => deposit, - None => parse_u64_string( - request - .suggested_deposit - .as_deref() - .or(request.minimum_deposit.as_deref()) - .ok_or_else(|| { - Error::Other("session challenge missing suggestedDeposit".to_string()) - })?, - "suggestedDeposit", - )?, - }; + let authorization = params.authorization; + if details.voucher_signer == Some(SessionVoucherSigner::Operator) { + let operator = parse_pubkey( + details.operator.as_deref().ok_or_else(|| { + Error::Other("operator is required for operator vouchers".to_string()) + })?, + "operator", + )?; + if authorization.operator != Some(operator) { + return Err(Error::Other(format!( + "session challenge asks for vouchers signed by operator {operator}, which the \ + caller did not authorize" + ))); + } + if params.authorized_signer != operator { + return Err(Error::Other( + "authorized signer is not the challenge's operator".to_string(), + )); + } + } + let deposit = authorization.deposit; if request .minimum_deposit .as_deref() @@ -485,6 +571,12 @@ pub fn derive_payment_channel_open( .grace_period .or(details.grace_period_seconds) .ok_or_else(|| Error::Other("session challenge missing gracePeriodSeconds".to_string()))?; + if grace_period > authorization.max_grace_period { + return Err(Error::Other(format!( + "session gracePeriodSeconds {grace_period} exceeds the authorized maximum {}", + authorization.max_grace_period + ))); + } let program_id = parse_pubkey(&details.channel_program, "channelProgram")?; crate::mpp::program::channel_deployment::resolve_for_network( program_id, @@ -583,34 +675,69 @@ pub struct BuildOpenPaymentChannelTransactionParams<'a> { pub signer: &'a dyn TransactionSigner, pub authorized_signer: Pubkey, pub fee_payer: Option, - /// Blockhash for the open transaction. `None` (the default) takes the - /// challenge's `recentBlockhash`, which the server requires the compiled - /// message to use; an explicit override is for tests and custom flows - /// that re-issue their own challenge binding. - pub recent_blockhash: Option, + /// Blockhash for the open transaction, checked against the client's own + /// cluster (see [`OpenBlockhash`]). + pub blockhash: OpenBlockhash, + pub authorization: &'a SessionOpenAuthorization, pub options: PaymentChannelOpenOptions, } -/// Resolve the open transaction's blockhash: an explicit override wins, -/// otherwise the challenged `recentBlockhash` is required — the client never -/// fetches its own. -fn resolve_open_blockhash(override_hash: Option, request: &SessionRequest) -> Result { - if let Some(hash) = override_hash { - return Ok(hash); +/// The blockhash a client signs into a channel `open`. +/// +/// A Solana transaction is bound to a cluster only by its blockhash, and the +/// server requires the open to use the challenge's `recentBlockhash`. That +/// value is untrusted: a hash from another cluster would make the signed +/// open valid there rather than on the network the deposit was approved for. +/// The only way to get one from a challenge is [`Self::verify`], which asks +/// the client's own RPC. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct OpenBlockhash(Hash); + +impl OpenBlockhash { + /// The challenge's `recentBlockhash`, once `rpc` (which serves the + /// cluster the client means to pay on) confirms it is live there. + pub async fn verify( + rpc: &solana_rpc_client::rpc_client::RpcClient, + request: &SessionRequest, + ) -> Result { + let challenged = request + .method_details + .recent_blockhash + .as_deref() + .ok_or_else(|| { + Error::Other( + "session challenge is missing recentBlockhash; a new-channel challenge must \ + provide it" + .to_string(), + ) + })?; + // Only the nonblocking client is reachable here: a blocking call + // panics on a current-thread runtime. + crate::core::blockhash::resolve_challenge_blockhash( + rpc.get_inner_client(), + Some(challenged), + ) + .await + .map(Self) + .map_err(|e| match e { + crate::core::blockhash::ChallengeBlockhashError::Invalid(message) => { + Error::Other(format!("invalid challenged recentBlockhash: {message}")) + } + crate::core::blockhash::ChallengeBlockhashError::Rpc(message) => Error::Other(format!( + "could not check the challenged recentBlockhash: {message}" + )), + }) + } + + /// A blockhash the caller fetched from its own cluster. Never pass a + /// value read from the challenge here; use [`Self::verify`]. + pub fn from_client_cluster(hash: Hash) -> Self { + Self(hash) + } + + pub fn hash(&self) -> Hash { + self.0 } - let challenged = request - .method_details - .recent_blockhash - .as_deref() - .ok_or_else(|| { - Error::Other( - "session challenge is missing recentBlockhash; a new-channel challenge must \ - provide it" - .to_string(), - ) - })?; - Hash::from_str(challenged) - .map_err(|e| Error::Other(format!("invalid challenged recentBlockhash: {e}"))) } pub async fn build_open_payment_channel_transaction( @@ -652,11 +779,12 @@ pub async fn build_open_payment_channel_transaction( "fee payer does not match the challenge policy".to_string(), )); } - let recent_blockhash = resolve_open_blockhash(params.recent_blockhash, params.request)?; + let recent_blockhash = params.blockhash.hash(); let open = derive_payment_channel_open(DerivePaymentChannelOpenParams { request: params.request, payer: params.signer.pubkey(), authorized_signer: params.authorized_signer, + authorization: params.authorization, options: params.options, })?; @@ -712,10 +840,10 @@ pub async fn create_payment_channel_session_opener( request: &SessionRequest, payer_signer: &dyn TransactionSigner, session_signer: Box, - recent_blockhash: Option, + blockhash: OpenBlockhash, + authorization: &SessionOpenAuthorization, options: PaymentChannelSessionOpenOptions, ) -> Result { - let recent_blockhash = resolve_open_blockhash(recent_blockhash, request)?; let authorized_signer = match request.method_details.voucher_signer { Some(SessionVoucherSigner::Operator) => parse_pubkey( request.method_details.operator.as_deref().ok_or_else(|| { @@ -743,6 +871,7 @@ pub async fn create_payment_channel_session_opener( request, payer: payer_signer.pubkey(), authorized_signer, + authorization, options: options.open.clone(), })?; // Carry the already chosen salt into the shared builder; deriving twice @@ -754,7 +883,8 @@ pub async fn create_payment_channel_session_opener( signer: payer_signer, authorized_signer, fee_payer: Some(fee_payer), - recent_blockhash: Some(recent_blockhash), + blockhash, + authorization, options: build_options, }) .await?; @@ -865,6 +995,7 @@ mod tests { request, payer: Pubkey::new_unique(), authorized_signer: Pubkey::new_unique(), + authorization: &auth(), options: PaymentChannelOpenOptions { program_id: override_program, ..Default::default() @@ -910,6 +1041,10 @@ mod tests { Hash::new_from_array([7; 32]) } + fn auth() -> SessionOpenAuthorization { + SessionOpenAuthorization::client_signed(1000) + } + fn request(recipient: Pubkey) -> SessionRequest { SessionRequest { amount: "25".into(), @@ -957,6 +1092,7 @@ mod tests { request, payer: Pubkey::new_unique(), authorized_signer: Pubkey::new_unique(), + authorization: &auth(), options: PaymentChannelOpenOptions { salt: Some(7), ..Default::default() @@ -1061,6 +1197,7 @@ mod tests { request, payer: Pubkey::new_unique(), authorized_signer: Pubkey::new_unique(), + authorization: &auth(), options: PaymentChannelOpenOptions { open_slot: Some(42), approved_payout: Some(approved), @@ -1103,6 +1240,7 @@ mod tests { request: &req, payer, authorized_signer: authorized, + authorization: &auth(), options: PaymentChannelOpenOptions { open_slot: Some(42), salt: Some(7), @@ -1118,35 +1256,44 @@ mod tests { assert_eq!(payload.deposit_amount, "1000"); assert_eq!(payload.distribution_splits[0].share_bps, 250); - let mut invalid = req.clone(); - invalid.suggested_deposit = Some("bad".into()); - assert!(derive_payment_channel_open(DerivePaymentChannelOpenParams { - request: &invalid, - payer, - authorized_signer: authorized, - options: PaymentChannelOpenOptions { - open_slot: Some(1), - ..Default::default() - } - }) - .is_err()); - let mut below = req.clone(); - below.suggested_deposit = Some("1".into()); - assert!(derive_payment_channel_open(DerivePaymentChannelOpenParams { - request: &below, - payer, - authorized_signer: authorized, - options: PaymentChannelOpenOptions { - open_slot: Some(1), - ..Default::default() - } - }) - .is_err()); + // The deposit is the caller's, whatever the challenge suggests, and + // still at least minimumDeposit. + let mut suggested = req.clone(); + suggested.suggested_deposit = Some("bad".into()); + let derive_with = |request: &SessionRequest, authorization: &SessionOpenAuthorization| { + derive_payment_channel_open(DerivePaymentChannelOpenParams { + request, + payer, + authorized_signer: authorized, + authorization, + options: PaymentChannelOpenOptions { + open_slot: Some(1), + ..Default::default() + }, + }) + }; + assert_eq!(derive_with(&suggested, &auth()).unwrap().deposit, 1000); + let mut no_suggestion = req.clone(); + no_suggestion.suggested_deposit = None; + no_suggestion.minimum_deposit = None; + assert_eq!( + derive_with(&no_suggestion, &SessionOpenAuthorization::client_signed(7)) + .unwrap() + .deposit, + 7 + ); + assert!( + derive_with(&req, &SessionOpenAuthorization::client_signed(99)) + .unwrap_err() + .to_string() + .contains("below minimumDeposit") + ); // Default options take `openSlot` from the challenged `recentSlot`. let defaulted = derive_payment_channel_open(DerivePaymentChannelOpenParams { request: &req, payer, authorized_signer: authorized, + authorization: &auth(), options: Default::default(), }) .unwrap(); @@ -1156,6 +1303,7 @@ mod tests { request: &req, payer, authorized_signer: authorized, + authorization: &auth(), options: PaymentChannelOpenOptions { open_slot: Some(43), ..Default::default() @@ -1171,6 +1319,7 @@ mod tests { request: &no_slot, payer, authorized_signer: authorized, + authorization: &auth(), options: Default::default() }) .unwrap_err() @@ -1182,19 +1331,7 @@ mod tests { request: &bad_program, payer, authorized_signer: authorized, - options: PaymentChannelOpenOptions { - open_slot: Some(1), - ..Default::default() - } - }) - .is_err()); - let mut no_deposit = req.clone(); - no_deposit.suggested_deposit = None; - no_deposit.minimum_deposit = None; - assert!(derive_payment_channel_open(DerivePaymentChannelOpenParams { - request: &no_deposit, - payer, - authorized_signer: authorized, + authorization: &auth(), options: PaymentChannelOpenOptions { open_slot: Some(1), ..Default::default() @@ -1226,7 +1363,8 @@ mod tests { signer: payer.as_ref(), authorized_signer: payer.pubkey(), fee_payer: None, - recent_blockhash: None, + blockhash: OpenBlockhash::from_client_cluster(test_blockhash()), + authorization: &auth(), options: PaymentChannelOpenOptions { compute_budget: budget, ..Default::default() @@ -1284,13 +1422,13 @@ mod tests { let session_signer = signer(3); let payee = Pubkey::new_unique(); let mut req = request(payee); - // No explicit blockhash: the challenged `recentBlockhash` is used. let tx = build_open_payment_channel_transaction(BuildOpenPaymentChannelTransactionParams { request: &req, signer: payer.as_ref(), authorized_signer: session_signer.pubkey(), fee_payer: None, - recent_blockhash: None, + blockhash: OpenBlockhash::from_client_cluster(test_blockhash()), + authorization: &auth(), options: PaymentChannelOpenOptions { open_slot: Some(42), salt: Some(7), @@ -1304,27 +1442,16 @@ mod tests { crate::mpp::program::payment_channels::decode_transaction(&tx.transaction).unwrap(); assert_eq!(*decoded.message.recent_blockhash(), test_blockhash()); - // A new-channel challenge without `recentBlockhash` cannot build the - // open transaction unless the caller overrides the blockhash. + // A new-channel challenge without `recentBlockhash` gives the client + // no blockhash it may verify. let mut no_blockhash = req.clone(); no_blockhash.method_details.recent_blockhash = None; - assert!( - build_open_payment_channel_transaction(BuildOpenPaymentChannelTransactionParams { - request: &no_blockhash, - signer: payer.as_ref(), - authorized_signer: session_signer.pubkey(), - fee_payer: None, - recent_blockhash: None, - options: PaymentChannelOpenOptions { - open_slot: Some(42), - ..Default::default() - }, - }) + let rpc = crate::core::blockhash::mock_blockhash_rpc(true); + assert!(OpenBlockhash::verify(&rpc, &no_blockhash) .await .unwrap_err() .to_string() - .contains("missing recentBlockhash") - ); + .contains("missing recentBlockhash")); req.method_details.fee_payer = Some(true); req.method_details.fee_payer_key = Some(Pubkey::new_unique().to_string()); @@ -1334,7 +1461,8 @@ mod tests { signer: payer.as_ref(), authorized_signer: session_signer.pubkey(), fee_payer: Some(payer.pubkey()), - recent_blockhash: None, + blockhash: OpenBlockhash::from_client_cluster(test_blockhash()), + authorization: &auth(), options: PaymentChannelOpenOptions { open_slot: Some(42), ..Default::default() @@ -1358,7 +1486,10 @@ mod tests { &req, payer.as_ref(), session_signer, - None, + OpenBlockhash::verify(&crate::core::blockhash::mock_blockhash_rpc(true), &req) + .await + .unwrap(), + &SessionOpenAuthorization::operator_signed(1000, operator.pubkey()), PaymentChannelSessionOpenOptions { open: PaymentChannelOpenOptions { // Earlier than the challenged recentSlot (42): allowed. @@ -1384,6 +1515,168 @@ mod tests { } } + /// An operator-signed channel lets the operator settle up to the whole + /// deposit with its own vouchers, so the challenge alone never makes the + /// client open one: the caller names the operator it trusts. + #[tokio::test] + async fn operator_vouchers_need_the_caller_to_name_the_operator() { + let operator = Pubkey::new_unique(); + let mut req = request(Pubkey::new_unique()); + req.method_details.voucher_signer = Some(SessionVoucherSigner::Operator); + req.method_details.operator = Some(operator.to_string()); + let open = |authorization: SessionOpenAuthorization| { + let req = req.clone(); + async move { + create_payment_channel_session_opener( + &req, + signer(2).as_ref(), + signer(3), + OpenBlockhash::from_client_cluster(test_blockhash()), + &authorization, + PaymentChannelSessionOpenOptions::default(), + ) + .await + } + }; + + let error = open(auth()).await.err().expect("client-signed only"); + assert!(error.to_string().contains("did not authorize"), "{error}"); + let other = SessionOpenAuthorization::operator_signed(1000, Pubkey::new_unique()); + let error = open(other).await.err().expect("another operator"); + assert!(error.to_string().contains("did not authorize"), "{error}"); + + let opened = open(SessionOpenAuthorization::operator_signed(1000, operator)) + .await + .unwrap(); + assert_eq!(opened.open.authorized_signer, operator); + assert_eq!(opened.open.deposit, 1000); + + // derive_payment_channel_open holds the same line for callers that + // pick the authorized signer themselves. + let derive = |authorized_signer, authorization: &SessionOpenAuthorization| { + derive_payment_channel_open(DerivePaymentChannelOpenParams { + request: &req, + payer: Pubkey::new_unique(), + authorized_signer, + authorization, + options: Default::default(), + }) + }; + assert!(derive(operator, &auth()).is_err()); + let trusted = SessionOpenAuthorization::operator_signed(1000, operator); + assert!(derive(Pubkey::new_unique(), &trusted).is_err()); + assert!(derive(operator, &trusted).is_ok()); + } + + /// The deposit is the caller's: a challenge's suggestedDeposit never + /// sizes the escrow. + #[tokio::test] + async fn the_deposit_is_the_callers_not_the_challenges() { + let mut req = request(Pubkey::new_unique()); + req.suggested_deposit = Some(u64::MAX.to_string()); + let opened = create_payment_channel_session_opener( + &req, + signer(2).as_ref(), + signer(3), + OpenBlockhash::from_client_cluster(test_blockhash()), + &SessionOpenAuthorization::client_signed(250), + PaymentChannelSessionOpenOptions::default(), + ) + .await + .unwrap(); + assert_eq!(opened.open.deposit, 250); + let SessionAction::Open(payload) = opened.action else { + panic!("open action"); + }; + assert_eq!(payload.deposit_amount, "250"); + } + + /// The grace period is the payer's wait to withdraw what was not settled, + /// so a challenge cannot stretch it past the caller's ceiling. + #[test] + fn the_grace_period_is_bounded() { + let derive = |grace: u32, option: Option, authorization: &SessionOpenAuthorization| { + let mut req = request(Pubkey::new_unique()); + req.method_details.grace_period_seconds = Some(grace); + derive_payment_channel_open(DerivePaymentChannelOpenParams { + request: &req, + payer: Pubkey::new_unique(), + authorized_signer: Pubkey::new_unique(), + authorization, + options: PaymentChannelOpenOptions { + grace_period: option, + ..Default::default() + }, + }) + }; + let error = derive(u32::MAX, None, &auth()).unwrap_err(); + assert!( + error.to_string().contains("exceeds the authorized maximum"), + "{error}" + ); + assert!(derive(MAX_SESSION_GRACE_PERIOD_SECONDS + 1, None, &auth()).is_err()); + assert_eq!( + derive(MAX_SESSION_GRACE_PERIOD_SECONDS, None, &auth()) + .unwrap() + .grace_period, + MAX_SESSION_GRACE_PERIOD_SECONDS + ); + + let tight = auth().with_max_grace_period(3_600).unwrap(); + assert!(derive(3_601, None, &tight).is_err()); + assert!(derive(u32::MAX, Some(3_601), &tight).is_err()); + assert_eq!( + derive(u32::MAX, Some(900), &tight).unwrap().grace_period, + 900 + ); + let wide = auth().with_max_grace_period(u32::MAX).unwrap(); + assert_eq!( + derive(u32::MAX, None, &wide).unwrap().grace_period, + u32::MAX + ); + assert!(auth().with_max_grace_period(0).is_err()); + } + + #[tokio::test] + async fn a_challenged_blockhash_the_client_cluster_does_not_know_is_refused() { + let req = request(Pubkey::new_unique()); + let foreign = crate::core::blockhash::mock_blockhash_rpc(false); + let error = OpenBlockhash::verify(&foreign, &req).await.unwrap_err(); + assert!( + error.to_string().contains("not a live blockhash"), + "{error}" + ); + + let rpc = crate::core::blockhash::mock_blockhash_rpc(true); + let blockhash = OpenBlockhash::verify(&rpc, &req).await.unwrap(); + assert_eq!(blockhash.hash(), test_blockhash()); + let opened = create_payment_channel_session_opener( + &req, + signer(2).as_ref(), + signer(3), + blockhash, + &auth(), + PaymentChannelSessionOpenOptions::default(), + ) + .await + .unwrap(); + let SessionAction::Open(payload) = opened.action else { + panic!("open action"); + }; + let decoded = + crate::mpp::program::payment_channels::decode_transaction(&payload.transaction) + .unwrap(); + assert_eq!(*decoded.message.recent_blockhash(), test_blockhash()); + } + + #[tokio::test] + async fn an_unreachable_client_rpc_refuses_the_challenged_blockhash() { + let req = request(Pubkey::new_unique()); + let rpc = solana_rpc_client::rpc_client::RpcClient::new("http://127.0.0.1:1".to_string()); + let error = OpenBlockhash::verify(&rpc, &req).await.unwrap_err(); + assert!(error.to_string().contains("could not check"), "{error}"); + } + #[test] fn stablecoin_and_token_program_resolution_is_exact() { let req = request(Pubkey::new_unique()); @@ -1391,6 +1684,7 @@ mod tests { request: &req, payer: Pubkey::new_unique(), authorized_signer: Pubkey::new_unique(), + authorization: &auth(), options: PaymentChannelOpenOptions { open_slot: Some(1), ..Default::default() diff --git a/rust/crates/kit/src/mpp/client/session_consumer.rs b/rust/crates/kit/src/mpp/client/session_consumer.rs index 997d2d1b5..df7cb816e 100644 --- a/rust/crates/kit/src/mpp/client/session_consumer.rs +++ b/rust/crates/kit/src/mpp/client/session_consumer.rs @@ -49,15 +49,62 @@ impl CommitTransport for Arc { } } +/// What a [`SessionConsumer`] may sign vouchers for. +/// +/// A metering directive is the server's claim of what a delivery cost, and +/// the voucher signed for it lets the server settle that much of the +/// deposit. The budget is the caller's bound on both: no directive is +/// committed past it, whatever the server names. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct MeteringBudget { + max_per_delivery: u64, + max_cumulative: u64, +} + +impl MeteringBudget { + /// At most `max_per_delivery` base units for one delivery, and at most + /// `max_cumulative` for the channel's cumulative voucher (typically the + /// deposit, or less). + pub fn new(max_per_delivery: u64, max_cumulative: u64) -> Result { + if max_per_delivery == 0 || max_per_delivery > max_cumulative { + return Err(Error::Other(format!( + "metering budget needs 0 < max_per_delivery ({max_per_delivery}) <= \ + max_cumulative ({max_cumulative})" + ))); + } + Ok(Self { + max_per_delivery, + max_cumulative, + }) + } + + pub fn max_per_delivery(&self) -> u64 { + self.max_per_delivery + } + + pub fn max_cumulative(&self) -> u64 { + self.max_cumulative + } +} + /// Client-side consumer for session-metered deliveries. pub struct SessionConsumer { session: ActiveSession, transport: T, + budget: MeteringBudget, } impl SessionConsumer { - pub fn new(session: ActiveSession, transport: T) -> Self { - Self { session, transport } + pub fn new(session: ActiveSession, transport: T, budget: MeteringBudget) -> Self { + Self { + session, + transport, + budget, + } + } + + pub fn budget(&self) -> MeteringBudget { + self.budget } pub fn session(&self) -> &ActiveSession { @@ -83,15 +130,8 @@ impl SessionConsumer { &mut self, directive: &MeteringDirective, ) -> Result { - self.validate_directive(directive)?; - let amount = directive.amount_base_units()?; - if amount == 0 { - return Err(Error::Other( - "metered delivery amount must be greater than zero".to_string(), - )); - } - - let voucher = self.session.prepare_increment(amount).await?; + let cumulative = self.validate_directive(directive)?; + let voucher = self.session.prepare_voucher(cumulative).await?; let payload = CommitPayload { delivery_id: directive.delivery_id.clone(), voucher, @@ -102,7 +142,9 @@ impl SessionConsumer { Ok(receipt) } - fn validate_directive(&self, directive: &MeteringDirective) -> Result<()> { + /// Check `directive` against the session, the transport and the budget, + /// and return the cumulative amount a voucher for it would sign. + fn validate_directive(&self, directive: &MeteringDirective) -> Result { let channel_id = self.session.channel_id_str(); if directive.session_id != channel_id { return Err(Error::Other(format!( @@ -110,7 +152,32 @@ impl SessionConsumer { directive.session_id ))); } - self.transport.check_directive(directive) + let amount = directive.amount_base_units()?; + if amount == 0 { + return Err(Error::Other( + "metered delivery amount must be greater than zero".to_string(), + )); + } + if amount > self.budget.max_per_delivery { + return Err(Error::Other(format!( + "metered delivery amount {amount} exceeds the per-delivery budget {}", + self.budget.max_per_delivery + ))); + } + let cumulative = self + .session + .cumulative + .checked_add(amount) + .filter(|cumulative| *cumulative <= self.budget.max_cumulative) + .ok_or_else(|| { + Error::Other(format!( + "metered delivery amount {amount} takes the session past its cumulative \ + budget {} (committed {})", + self.budget.max_cumulative, self.session.cumulative + )) + })?; + self.transport.check_directive(directive)?; + Ok(cumulative) } } @@ -190,6 +257,10 @@ mod tests { Box::new(MemorySigner::from_bytes(&kp).unwrap()) } + fn budget() -> MeteringBudget { + MeteringBudget::new(1_000, 10_000).unwrap() + } + fn directive(session_id: String, amount: u64) -> MeteringDirective { MeteringDirective { delivery_id: "d1".to_string(), @@ -211,7 +282,7 @@ mod tests { commits: Mutex::new(vec![]), fail: false, }; - let mut consumer = SessionConsumer::new(session, transport); + let mut consumer = SessionConsumer::new(session, transport, budget()); let envelope = MeteredEnvelope { payload: "work".to_string(), metering: directive(consumer.session().channel_id_str(), 250), @@ -234,7 +305,7 @@ mod tests { commits: Mutex::new(vec![]), fail: false, }; - let mut consumer = SessionConsumer::new(session, transport); + let mut consumer = SessionConsumer::new(session, transport, budget()); consumer.session_mut().set_expires_at(1234); let envelope = MeteredEnvelope { payload: "payload".to_string(), @@ -271,7 +342,8 @@ mod tests { commits: Mutex::new(vec![]), fail: false, }); - let mut consumer = SessionConsumer::new(session, std::sync::Arc::clone(&transport)); + let mut consumer = + SessionConsumer::new(session, std::sync::Arc::clone(&transport), budget()); let directive = directive(consumer.session().channel_id_str(), 25); let receipt = consumer.commit_directive(&directive).await.unwrap(); @@ -287,7 +359,7 @@ mod tests { commits: Mutex::new(vec![]), fail: false, }; - let mut consumer = SessionConsumer::new(session, transport); + let mut consumer = SessionConsumer::new(session, transport, budget()); let wrong_session = MeteredEnvelope { payload: (), @@ -321,11 +393,76 @@ mod tests { commits: Mutex::new(vec![]), fail: true, }; - let mut consumer = SessionConsumer::new(session, transport); + let mut consumer = SessionConsumer::new(session, transport, budget()); let directive = directive(consumer.session().channel_id_str(), 250); let err = consumer.commit_directive(&directive).await.unwrap_err(); assert!(err.to_string().contains("commit failed")); assert_eq!(consumer.session().cumulative, 0); } + + #[tokio::test] + async fn directives_past_the_budget_are_refused_before_signing() { + let session = ActiveSession::new(Pubkey::new_unique(), signer()); + let transport = RecordingTransport { + commits: Mutex::new(vec![]), + fail: false, + }; + let budget = MeteringBudget::new(400, 1_000).unwrap(); + let mut consumer = SessionConsumer::new(session, transport, budget); + let session_id = consumer.session().channel_id_str(); + + // One delivery may not cost more than the per-delivery cap. + let err = consumer + .accept(MeteredEnvelope { + payload: (), + metering: directive(session_id.clone(), 401), + }) + .err() + .expect("over the per-delivery cap"); + assert!(err.to_string().contains("per-delivery budget"), "{err}"); + let err = consumer + .commit_directive(&directive(session_id.clone(), 401)) + .await + .unwrap_err(); + assert!(err.to_string().contains("per-delivery budget"), "{err}"); + + // Deliveries within it commit up to the cumulative cap and no further. + for _ in 0..2 { + consumer + .commit_directive(&directive(session_id.clone(), 400)) + .await + .unwrap(); + } + consumer + .commit_directive(&directive(session_id.clone(), 200)) + .await + .unwrap(); + assert_eq!(consumer.session().cumulative, 1_000); + let err = consumer + .commit_directive(&directive(session_id.clone(), 1)) + .await + .unwrap_err(); + assert!(err.to_string().contains("cumulative budget"), "{err}"); + + // A directive that would overflow the cumulative is refused too. + consumer.session_mut().cumulative = u64::MAX - 1; + let err = consumer + .commit_directive(&directive(session_id, 2)) + .await + .unwrap_err(); + assert!(err.to_string().contains("cumulative budget"), "{err}"); + assert_eq!(consumer.transport.commits.lock().unwrap().len(), 3); + } + + #[test] + fn a_budget_needs_a_positive_per_delivery_cap_within_the_total() { + assert!(MeteringBudget::new(0, 10).is_err()); + assert!(MeteringBudget::new(11, 10).is_err()); + let budget = MeteringBudget::new(10, 10).unwrap(); + assert_eq!( + (budget.max_per_delivery(), budget.max_cumulative()), + (10, 10) + ); + } } diff --git a/rust/crates/kit/src/mpp/server/charge.rs b/rust/crates/kit/src/mpp/server/charge.rs index 3920b94fb..a77d00712 100644 --- a/rust/crates/kit/src/mpp/server/charge.rs +++ b/rust/crates/kit/src/mpp/server/charge.rs @@ -2171,6 +2171,8 @@ impl Mpp { } } + confirmed_within_replay_retention(tx.block_time, unix_now_secs())?; + let total_amount: u64 = request.amount.parse().map_err(|_| { VerificationError::invalid_amount(format!("Invalid amount: {}", request.amount)) })?; @@ -2925,6 +2927,34 @@ fn within_replay_retention(expires: Option<&str>) -> Result<(), VerificationErro Ok(()) } +/// A push payment confirmed within [`DEFAULT_CHARGE_RECORD_RETENTION`] of +/// `now`. A push signature is not bound to the challenge it pays, so its +/// consumed-signature record (kept at least that long after it is claimed) is +/// all that stops it paying again; an older transaction, or one without a +/// block time, could outlive that record. +fn confirmed_within_replay_retention( + block_time: Option, + now: i64, +) -> Result<(), VerificationError> { + let block_time = block_time.ok_or_else(|| { + VerificationError::credential_mismatch( + "Push-mode transaction has no block time; its age cannot be bounded", + ) + })?; + let retention = DEFAULT_CHARGE_RECORD_RETENTION.as_secs() as i64; + let age = now.saturating_sub(block_time); + if age > retention { + return Err(VerificationError::credential_mismatch(format!( + "Push-mode transaction confirmed {age}s ago, outside the {retention}s replay retention window" + ))); + } + Ok(()) +} + +fn unix_now_secs() -> i64 { + time::OffsetDateTime::now_utc().unix_timestamp() +} + /// The charge-record generation a settlement owns. /// /// A settlement transaction is only sent after [`Self::begin`] recorded its @@ -9395,6 +9425,20 @@ mod tests { /// JSON-RPC stub for a landed push payment: `getTransaction` returns a /// confirmed SOL transfer of `lamports` from `sender` to `recipient`. async fn stub_push_rpc(sender: Pubkey, recipient: Pubkey, lamports: u64) -> String { + let now = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap() + .as_secs() as i64; + stub_push_rpc_at(sender, recipient, lamports, Some(now)).await + } + + /// [`stub_push_rpc`] for a transaction confirmed at `block_time`. + async fn stub_push_rpc_at( + sender: Pubkey, + recipient: Pubkey, + lamports: u64, + block_time: Option, + ) -> String { use axum::{routing::post, Json, Router}; let app = Router::new().route( "/", @@ -9402,7 +9446,7 @@ mod tests { let result = match request["method"].as_str() { Some("getTransaction") => serde_json::json!({ "slot": 1, - "blockTime": std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_secs() as i64, + "blockTime": block_time, "version": 0, "transaction": { "signatures": [request["params"][0]], @@ -9490,6 +9534,57 @@ mod tests { assert_eq!(receipt.reference, signature); } + // A push signature is not bound to the challenge it pays: once its + // consumed-signature record expires, only the transaction's age stops a + // landed payment from paying a fresh challenge again. + #[tokio::test(flavor = "multi_thread")] + async fn push_rejects_a_transaction_older_than_the_replay_retention() { + let now = time::OffsetDateTime::now_utc().unix_timestamp(); + let retention = DEFAULT_CHARGE_RECORD_RETENTION.as_secs() as i64; + let sender = seed_pubkey(14); + let recipient = Pubkey::from_str(TEST_RECIPIENT).unwrap(); + let verify_at = |block_time: Option| async move { + let rpc_url = stub_push_rpc_at(sender, recipient, 1000, block_time).await; + let mpp = Mpp::new(Config { + realm: Some("test-realm".to_string()), + recipient: TEST_RECIPIENT.to_string(), + challenge_binding_secret: Some(TEST_SECRET.to_string()), + currency: "SOL".to_string(), + decimals: 9, + network: "devnet".to_string(), + rpc_url: Some(rpc_url), + accept_push_mode: true, + store: Some(Arc::new(MemoryStore::new())), + ..Default::default() + }) + .unwrap(); + let expected = ChargeRequest { + amount: "1000".into(), + currency: "SOL".into(), + recipient: Some(TEST_RECIPIENT.into()), + method_details: Some(serde_json::json!({ "network": "devnet", "decimals": 9 })), + ..Default::default() + }; + let signature = Signature::from([15u8; 64]).to_string(); + let credential = build_credential( + &mpp, + &expected, + serde_json::json!({ "type": "signature", "signature": signature }), + ); + mpp.verify(&credential, &expected).await + }; + + for stale in [Some(now - retention - 60), None] { + let err = verify_at(stale).await.unwrap_err(); + assert!( + err.message.contains("replay retention") || err.message.contains("block time"), + "{stale:?}: {err:?}" + ); + } + // Positive control: a payment confirmed inside the window is accepted. + verify_at(Some(now - retention + 60)).await.unwrap(); + } + // A charge that lands while its confirmed record cannot be written is // still pending in the store. Answering with a receipt would let the // retry's confirm_pending grant a second one: the retry is the receipt. diff --git a/rust/crates/kit/src/mpp/server/confidential.rs b/rust/crates/kit/src/mpp/server/confidential.rs index 6849587e6..e9cc4a973 100644 --- a/rust/crates/kit/src/mpp/server/confidential.rs +++ b/rust/crates/kit/src/mpp/server/confidential.rs @@ -58,6 +58,13 @@ pub(crate) const MAX_CT_BUNDLE_FUNDED_ACCOUNTS: usize = 6; #[cfg(feature = "confidential")] pub(crate) const MAX_CT_BUNDLE_CREATE_LAMPORTS: u64 = MAX_CT_CREATE_ACCOUNT_LAMPORTS * MAX_CT_BUNDLE_FUNDED_ACCOUNTS as u64; +/// The rent-exempt minimum for `space` bytes under the default rent every +/// public cluster runs: 3,480 lamports per byte-year for two years, over the +/// account plus its 128-byte overhead. +#[cfg(feature = "confidential")] +pub(crate) const fn rent_exempt_ceiling(space: u64) -> u64 { + (128 + space) * 3_480 * 2 +} /// Max base64 length of a single bundle transaction, by the largest accepted /// version: 1232 wire bytes (~1644 base64 chars) for version 0, 4096 (5464) /// for version 1. Caps decode/deserialize allocation so a client can't force @@ -321,7 +328,7 @@ impl Mpp { )); } - verify_confidential_account_lifecycle(&decoded, &gateway_pubkey)?; + let bundle_accounts = verify_confidential_account_lifecycle(&decoded, &gateway_pubkey)?; // Recover the amount from the validity proof the transfer itself // consumes. An account-wide balance delta cannot attribute a credit to @@ -348,6 +355,13 @@ impl Mpp { // the confidential transfer; its signature is the settlement signature. let mut final_sig = String::new(); let bundle_len = decoded.len(); + let mut cleanup = SetupCleanup { + rpc: std::sync::Arc::clone(&self.rpc), + signer: std::sync::Arc::clone(fee_payer_signer), + gateway: gateway_pubkey, + accounts: Vec::new(), + armed: true, + }; for (idx, tx) in decoded.iter_mut().enumerate() { // The gateway is every bundle tx's fee payer, so it is account key // zero. Keep that as an `invalid_payload` diagnostic naming the tx. @@ -400,6 +414,16 @@ impl Mpp { // Claim before sending, as pull settlement does, so the // transfer is recorded whatever happens after it leaves. fence.begin(self, &local_signature).await?; + // Once the final transaction may land, it owns the closes. + cleanup.armed = false; + } else { + if idx == 0 { + // One bundle presented for two challenges runs twice; only + // the run that claims its first setup transaction sends + // (and may clean up) the accounts the winner's final needs. + self.claim_bundle_setup(&local_signature).await?; + } + cleanup.sending(idx, &bundle_accounts); } let signature = match crate::core::rpc::send_transaction( &self.rpc, @@ -421,6 +445,7 @@ impl Mpp { }); } fence.abandon(self).await; + cleanup.armed = true; } return Err(error); } @@ -469,6 +494,24 @@ impl Mpp { Ok(BundleSettlement::Confirmed(final_sig)) } + /// Claim a bundle's setup by its first transaction's (deterministic) + /// gateway signature, across requests and replicas sharing the store. + #[cfg(feature = "confidential")] + async fn claim_bundle_setup(&self, signature: &str) -> Result<(), VerificationError> { + let key = format!("{CONFIDENTIAL_SETUP_CLAIM_PREFIX}{signature}"); + match self + .store + .put_if_absent(&key, serde_json::json!(true)) + .await + { + Ok(true) => Ok(()), + Ok(false) => Err(VerificationError::settlement_in_progress( + "This confidential bundle is already being settled; retry shortly", + )), + Err(e) => Err(VerificationError::new(format!("Store error: {e}"))), + } + } + /// Sweep gateway-owned orphaned confidential proof/record accounts left by /// partially-failed bundles and reclaim their rent back to the gateway. /// @@ -642,8 +685,110 @@ impl Mpp { } } +/// Store key prefix of [`Mpp::claim_bundle_setup`]. +#[cfg(feature = "confidential")] +const CONFIDENTIAL_SETUP_CLAIM_PREFIX: &str = "mpp:confidential-bundle-setup:"; + +/// The gateway-funded accounts a bundle's setup transactions may have +/// created. The final transaction closes them; when it never lands (it +/// fails simulation or is rejected at preflight, or settlement is +/// abandoned), dropping this guard while armed closes them back to the +/// gateway from a spawned task instead of leaving the rent parked until the +/// orphan sweeper's grace period ends. #[cfg(feature = "confidential")] -#[derive(Clone, Copy, PartialEq, Eq)] +struct SetupCleanup { + rpc: std::sync::Arc, + signer: std::sync::Arc, + gateway: Pubkey, + accounts: Vec, + armed: bool, +} + +#[cfg(feature = "confidential")] +impl SetupCleanup { + /// Bundle transaction `tx_index` is about to be sent: the accounts it + /// creates may exist from here on. + fn sending(&mut self, tx_index: usize, bundle: &[BundleAccount]) { + self.accounts.extend( + bundle + .iter() + .filter(|account| account.created_in == tx_index), + ); + } +} + +#[cfg(feature = "confidential")] +impl Drop for SetupCleanup { + fn drop(&mut self) { + if !self.armed || self.accounts.is_empty() { + return; + } + let Ok(runtime) = tokio::runtime::Handle::try_current() else { + tracing::warn!( + accounts = self.accounts.len(), + "no runtime to close a failed confidential bundle's accounts; leaving them to the orphan sweeper" + ); + return; + }; + let rpc = std::sync::Arc::clone(&self.rpc); + let signer = std::sync::Arc::clone(&self.signer); + let gateway = self.gateway; + let accounts = std::mem::take(&mut self.accounts); + runtime.spawn(async move { + if let Err(error) = close_setup_accounts(&rpc, signer.as_ref(), &gateway, &accounts).await + { + tracing::warn!( + error = %error.message, + "closing a failed confidential bundle's accounts failed; leaving them to the orphan sweeper" + ); + } + }); + } +} + +/// Close every account in `accounts` that exists back to the gateway, in one +/// gateway-paid transaction that must pass preflight. +#[cfg(feature = "confidential")] +async fn close_setup_accounts( + rpc: &solana_rpc_client::rpc_client::RpcClient, + signer: &dyn solana_keychain::TransactionSigner, + gateway: &Pubkey, + accounts: &[BundleAccount], +) -> Result<(), VerificationError> { + let addresses: Vec = accounts.iter().map(|account| account.address).collect(); + let existing = rpc + .get_multiple_accounts(&addresses) + .map_err(|e| VerificationError::network_error(format!("getMultipleAccounts: {e}")))?; + let closes: Vec<_> = accounts + .iter() + .zip(existing) + .filter(|(_, account)| account.is_some()) + .map(|(account, _)| account.close_instruction(gateway)) + .collect(); + if closes.is_empty() { + return Ok(()); + } + let blockhash = rpc + .get_latest_blockhash() + .map_err(|e| VerificationError::network_error(format!("get_latest_blockhash: {e}")))?; + let mut tx = crate::core::tx::build_unsigned( + crate::core::tx::TxVersion::V0, + gateway, + &closes, + blockhash, + None, + ) + .map_err(|e| VerificationError::new(format!("build close: {e}")))?; + crate::core::signing::cosign_versioned_fee_payer(signer, gateway, &mut tx) + .await + .map_err(|e| VerificationError::new(format!("sign close: {e}")))?; + crate::core::rpc::send_transaction(rpc, &tx, crate::core::rpc::preflight_config(rpc)) + .map_err(|e| VerificationError::network_error(format!("broadcast close: {e}")))?; + Ok(()) +} + +#[cfg(feature = "confidential")] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] enum FundedAccountKind { ProofContext, Record, @@ -657,6 +802,50 @@ struct FundedAccount { /// Allocated bytes, and record payload bytes written so far. space: u64, written: u64, + /// Index of the bundle transaction that creates it. + created_in: usize, +} + +/// A gateway-funded temporary account of a bundle. +#[cfg(feature = "confidential")] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub(crate) struct BundleAccount { + address: Pubkey, + kind: FundedAccountKind, + /// Index of the bundle transaction that creates it. + created_in: usize, +} + +#[cfg(feature = "confidential")] +impl BundleAccount { + /// The instruction closing this account back to the gateway. + fn close_instruction(&self, gateway: &Pubkey) -> solana_instruction::Instruction { + close_temporary_account(self.kind, &self.address, gateway) + } +} + +/// Close a gateway-authorized proof context or record back to the gateway. +#[cfg(feature = "confidential")] +fn close_temporary_account( + kind: FundedAccountKind, + account: &Pubkey, + gateway: &Pubkey, +) -> solana_instruction::Instruction { + match kind { + FundedAccountKind::Record => { + spl_record::instruction::close_account(account, gateway, gateway) + } + FundedAccountKind::ProofContext => { + let gw = solana_address::Address::from(gateway.to_bytes()); + solana_zk_elgamal_proof_interface::instruction::close_context_state( + solana_zk_elgamal_proof_interface::instruction::ContextStateInfo { + context_state_account: &solana_address::Address::from(account.to_bytes()), + context_state_authority: &gw, + }, + &gw, + ) + } + } } /// The spl-record instructions a confidential bundle may carry. @@ -705,7 +894,7 @@ impl RecordIx { pub(crate) fn verify_confidential_account_lifecycle( transactions: &[VersionedTransaction], gateway: &Pubkey, -) -> Result<(), VerificationError> { +) -> Result, VerificationError> { use std::collections::{HashMap, HashSet}; let zk_program = Pubkey::from_str(ZK_ELGAMAL_PROOF_PROGRAM).expect("valid zk program id"); @@ -792,6 +981,7 @@ pub(crate) fn verify_confidential_account_lifecycle( closed: false, space, written: 0, + created_in: tx_index, }, ) .is_some() @@ -953,7 +1143,16 @@ pub(crate) fn verify_confidential_account_lifecycle( "every gateway-funded temporary account must be initialized and closed back to the gateway", )); } - Ok(()) + let mut accounts: Vec = funded + .into_iter() + .map(|(address, account)| BundleAccount { + address, + kind: account.kind, + created_in: account.created_in, + }) + .collect(); + accounts.sort_by_key(|account| account.created_in); + Ok(accounts) } /// Orphan guard. An account may be closed only through an [`orphan::OrphanConfirmed`], @@ -998,23 +1197,11 @@ pub(crate) mod orphan { &self, gateway: &Pubkey, ) -> solana_instruction::Instruction { - match self.kind { - OrphanKind::Record => { - spl_record::instruction::close_account(&self.pubkey, gateway, gateway) - } - OrphanKind::ProofContext => { - let gw = solana_address::Address::from(gateway.to_bytes()); - solana_zk_elgamal_proof_interface::instruction::close_context_state( - solana_zk_elgamal_proof_interface::instruction::ContextStateInfo { - context_state_account: &solana_address::Address::from( - self.pubkey.to_bytes(), - ), - context_state_authority: &gw, - }, - &gw, - ) - } - } + let kind = match self.kind { + OrphanKind::Record => super::FundedAccountKind::Record, + OrphanKind::ProofContext => super::FundedAccountKind::ProofContext, + }; + super::close_temporary_account(kind, &self.pubkey, gateway) } } @@ -1200,6 +1387,16 @@ pub(crate) fn verify_confidential_bundle_tx( "create_account exceeds the allowed size/rent for a proof/record account", )); } + // A temporary account needs exactly its rent-exempt minimum; any + // more is gateway SOL parked in it until it is closed. + if let (Some(space), Some(lamports)) = (space, lamports) { + if lamports > rent_exempt_ceiling(space) { + return Err(VerificationError::credential_mismatch(format!( + "create_account funds {lamports} lamports, more than the {} rent-exempt minimum for {space} bytes", + rent_exempt_ceiling(space) + ))); + } + } if let Some(created) = ix.accounts.get(1).and_then(|i| keys.get(*i as usize)) { created_accounts.insert(*created); } @@ -2661,4 +2858,232 @@ pub(crate) mod tests { err.message ); } + + // A gateway-funded temporary account needs only its rent-exempt minimum; + // anything above it is gateway SOL a failed bundle would leave parked. + #[test] + fn temporary_accounts_are_funded_at_most_their_rent_exempt_minimum() { + let gateway = Pubkey::new_unique(); + let ata = Pubkey::new_unique(); + let p = layout_pieces(&gateway, &ata); + let setup = |lamports: u64| { + let record = client_key(); + v0_tx( + &gateway, + &[ + solana_system_interface::instruction::create_account( + &gateway, + &record, + lamports, + 100, + &spl_record::id(), + ), + solana_instruction::Instruction { + accounts: vec![ + solana_instruction::AccountMeta::new(record, false), + solana_instruction::AccountMeta::new_readonly(gateway, false), + ], + ..p.initialize.clone() + }, + ], + ) + }; + let err = accepts(&setup(rent_exempt_ceiling(100) + 1), &gateway, &ata).unwrap_err(); + assert!( + err.message.contains("rent-exempt minimum"), + "{}", + err.message + ); + accepts(&setup(rent_exempt_ceiling(100)), &gateway, &ata).unwrap(); + } + + /// Settlement RPC for a two-transaction bundle: confirms every broadcast, + /// reports every temporary account as existing, and fails the simulation + /// of any transaction that invokes `failing` (if set). Records the + /// program ids of each sent transaction. + async fn bundle_rpc( + failing: Option, + ) -> ( + String, + Arc>>>, + tokio::task::JoinHandle<()>, + ) { + use axum::{routing::post, Json, Router}; + let sent = Arc::new(std::sync::Mutex::new(Vec::new())); + let recorded = Arc::clone(&sent); + let programs_of = |b64: &str| { + let tx = crate::core::tx::decode(b64).unwrap(); + let keys = tx.message.static_account_keys().to_vec(); + let programs: Vec = tx + .message + .instructions() + .iter() + .map(|ix| keys[ix.program_id_index as usize]) + .collect(); + (tx.signatures[0], programs) + }; + let app = Router::new().route( + "/", + post(move |Json(request): Json| { + let recorded = Arc::clone(&recorded); + async move { + let result = match request["method"].as_str().unwrap() { + "simulateTransaction" => { + let (_, programs) = programs_of(request["params"][0].as_str().unwrap()); + let err = failing + .filter(|failing| programs.contains(failing)) + .map(|_| serde_json::json!({ "InstructionError": [0, { "Custom": 1 }] })); + serde_json::json!({ + "context": { "slot": 1 }, + "value": { "err": err, "logs": [], "accounts": null, "unitsConsumed": 0 } + }) + } + "sendTransaction" => { + let (signature, programs) = + programs_of(request["params"][0].as_str().unwrap()); + recorded.lock().unwrap().push(programs); + serde_json::json!(signature.to_string()) + } + "getSignatureStatuses" => { + let statuses = request["params"][0] + .as_array() + .unwrap() + .iter() + .map(|_| { + serde_json::json!({ + "slot": 1, "confirmations": null, "err": null, + "confirmationStatus": "finalized", "status": { "Ok": null } + }) + }) + .collect::>(); + serde_json::json!({ "context": { "slot": 1 }, "value": statuses }) + } + "getMultipleAccounts" => { + let accounts = request["params"][0] + .as_array() + .unwrap() + .iter() + .map(|_| { + serde_json::json!({ + "lamports": 1_000, "data": ["", "base64"], + "owner": spl_record::id().to_string(), + "executable": false, "rentEpoch": 0, "space": 0 + }) + }) + .collect::>(); + serde_json::json!({ "context": { "slot": 1 }, "value": accounts }) + } + "getLatestBlockhash" => serde_json::json!({ + "context": { "slot": 1 }, + "value": { + "blockhash": solana_hash::Hash::new_unique().to_string(), + "lastValidBlockHeight": 100 + } + }), + method => panic!("unexpected RPC method {method}"), + }; + Json(serde_json::json!({ "jsonrpc": "2.0", "id": request["id"], "result": result })) + } + }), + ); + let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap(); + let url = format!("http://{}", listener.local_addr().unwrap()); + let server = tokio::spawn(async move { axum::serve(listener, app).await.unwrap() }); + (url, sent, server) + } + + // One bundle presented for two challenges: the second run must not send + // its setup again, nor clean up accounts the first run's final needs. + #[tokio::test(flavor = "multi_thread")] + async fn a_bundle_presented_twice_is_sent_and_cleaned_up_once() { + let token_2022 = Pubkey::from_str(programs::TOKEN_2022_PROGRAM).unwrap(); + let system = solana_system_interface::program::ID; + let record = spl_record::id(); + let (url, sent, rpc) = bundle_rpc(None).await; + let mut server = confidential_server(false, None, true).await; + server.mpp.accepted_versions = vec![TxVersion::V0]; + server.mpp.rpc = Arc::new(solana_rpc_client::rpc_client::RpcClient::new(url)); + let p = layout_pieces(&server.gateway, &server.recipient_ata); + let bundle = encode_bundle(&[ + v0_tx(&server.gateway, &[p.create, p.initialize]), + v0_tx(&server.gateway, &[p.transfer, p.close]), + ]); + let req = request(1_000, &server.mint, server.mpp.recipient()); + let first = server + .mpp + .settle_confidential_bundle( + &bundle, + &req, + &server.method_details, + &mut server.mpp.test_fence().await, + ) + .await; + assert!(first.is_ok(), "{first:?}"); + let second = server + .mpp + .settle_confidential_bundle( + &bundle, + &req, + &server.method_details, + &mut server.mpp.test_fence().await, + ) + .await; + assert!(second.is_err(), "{second:?}"); + tokio::time::sleep(std::time::Duration::from_millis(200)).await; + assert_eq!( + *sent.lock().unwrap(), + vec![vec![system, record], vec![token_2022, record]], + "only the first run sends anything" + ); + rpc.abort(); + } + + // The final transaction closes every gateway-funded account. When it + // fails after the setup transactions landed, the gateway closes them + // straight away rather than leaving the rent for the orphan sweeper. + #[tokio::test(flavor = "multi_thread")] + async fn a_bundle_whose_final_transaction_fails_closes_its_landed_accounts() { + let token_2022 = Pubkey::from_str(programs::TOKEN_2022_PROGRAM).unwrap(); + let system = solana_system_interface::program::ID; + let record = spl_record::id(); + // (simulation failing on, expected sends: [programs of each]) + for (failing, expected) in [ + // Final fails: setup lands, then one cleanup closing the record. + (Some(token_2022), vec![vec![system, record], vec![record]]), + // Setup fails: nothing was sent, nothing to close. + (Some(system), vec![]), + // Positive control: the bundle settles, the final closes it all. + (None, vec![vec![system, record], vec![token_2022, record]]), + ] { + let (url, sent, rpc) = bundle_rpc(failing).await; + let mut server = confidential_server(false, None, true).await; + server.mpp.accepted_versions = vec![TxVersion::V0]; + server.mpp.rpc = Arc::new(solana_rpc_client::rpc_client::RpcClient::new(url)); + let p = layout_pieces(&server.gateway, &server.recipient_ata); + let bundle = encode_bundle(&[ + v0_tx(&server.gateway, &[p.create, p.initialize]), + v0_tx(&server.gateway, &[p.transfer, p.close]), + ]); + let result = server + .mpp + .settle_confidential_bundle( + &bundle, + &request(1_000, &server.mint, server.mpp.recipient()), + &server.method_details, + &mut server.mpp.test_fence().await, + ) + .await; + assert_eq!(result.is_ok(), failing.is_none(), "{failing:?}: {result:?}"); + // The cleanup runs on its own task. + for _ in 0..100 { + if sent.lock().unwrap().len() >= expected.len() { + break; + } + tokio::time::sleep(std::time::Duration::from_millis(20)).await; + } + tokio::time::sleep(std::time::Duration::from_millis(100)).await; + assert_eq!(*sent.lock().unwrap(), expected, "{failing:?}"); + rpc.abort(); + } + } } diff --git a/rust/crates/kit/src/mpp/server/mod.rs b/rust/crates/kit/src/mpp/server/mod.rs index 473aa3410..3fd9f7632 100644 --- a/rust/crates/kit/src/mpp/server/mod.rs +++ b/rust/crates/kit/src/mpp/server/mod.rs @@ -10,6 +10,7 @@ mod channel_charge; pub mod charge; pub mod html; pub mod session; +mod session_refund; pub mod subscription; #[cfg(feature = "axum")] diff --git a/rust/crates/kit/src/mpp/server/session.rs b/rust/crates/kit/src/mpp/server/session.rs index 083e08fa2..5dd654ea1 100644 --- a/rust/crates/kit/src/mpp/server/session.rs +++ b/rust/crates/kit/src/mpp/server/session.rs @@ -21,11 +21,19 @@ //! //! Replayed `open` payloads for an existing channel are idempotent: they //! never reset the voucher watermark or any other channel state. +//! +//! A charge (voucher, `use`, metered delivery) is admitted only on a confirmed +//! read of the channel account at most [`CHANNEL_SNAPSHOT_MAX_AGE_SECONDS`] +//! old, re-read as needed. A read showing a forced close sets +//! `close_requested_at` and makes the channel's lifecycle due at once; the host +//! must then settle it with [`SessionServer::seal_params`] before the grace +//! period ends. use solana_pubkey::Pubkey; use time::{format_description::well_known::Rfc3339, OffsetDateTime}; use crate::core::session::VoucherAcceptance; +use crate::core::store::{ObservedLifecycle, OnchainObservation, MAX_COMMITTED_AUTHORIZATIONS}; use crate::core::tx::{TxV1Mode, TxVersion}; use crate::mpp::error::{Error, Result}; use crate::mpp::program::payment_channels; @@ -120,6 +128,17 @@ const OPENED_ELSEWHERE_ERROR: &str = /// Index of the channel PDA among the `open` instruction's accounts. const OPEN_CHANNEL_ACCOUNT: usize = 5; +/// Longest `Idempotency-Key` an operator-signed `use` accepts, in bytes. Keys +/// are kept on the channel record, so their size is bounded. +pub const MAX_IDEMPOTENCY_KEY_BYTES: usize = 255; + +/// Longest a confirmed read of a channel account admits new charges on it. +/// +/// The payer can start a forced close at any time; the server learns of it at +/// most this long later and must still settle inside the grace period. It is +/// further capped at half the configured grace period. +pub const CHANNEL_SNAPSHOT_MAX_AGE_SECONDS: u64 = 30; + /// An open credential that passed the credential checks. struct ValidatedOpen { deposit: u64, @@ -337,6 +356,12 @@ pub struct SessionConfig { pub suggested_deposit: Option, /// Minimum accepted initial channel deposit. + /// + /// Required when [`fee_payer_signer`](Self::fee_payer_signer) is set: a + /// sponsored open makes the sponsor fund the channel and escrow rent, so + /// the refundable deposit is what it costs a client to make the sponsor + /// lock that SOL. A sponsored server without one refuses to issue + /// challenges or accept opens. pub minimum_deposit: Option, /// Currency identifier accepted in configuration (e.g., "USDC" or a mint). @@ -373,7 +398,8 @@ pub struct SessionConfig { /// Optional operator signer that sponsors session transaction fees and /// channel-account rent. When set, challenges advertise `feePayer: true` /// and clients leave this signer's fee-payer slot empty for the server to - /// co-sign after validating the transaction. + /// co-sign after validating the transaction. Requires + /// [`minimum_deposit`](Self::minimum_deposit). pub fee_payer_signer: Option>, /// Inactivity thresholds offered for a new channel. @@ -439,6 +465,20 @@ impl SessionConfig { &self.network, ) } + + /// A sponsor fronts the rent of every channel it opens, so it must name + /// the deposit floor that buys that rent rather than accept any non-zero + /// deposit. + fn check_sponsored_deposit_floor(&self) -> Result<()> { + if self.fee_payer_signer.is_some() && self.minimum_deposit.is_none() { + return Err(Error::InvalidConfig( + "sponsored sessions (fee_payer_signer) require minimum_deposit: the sponsor \ + funds each channel's rent" + .to_string(), + )); + } + Ok(()) + } } impl Default for SessionConfig { @@ -568,16 +608,26 @@ impl SealParams { /// Build distribution with the original mandatory callbacks, including /// terminal distributions whose actual payer refund is zero. The rent /// payer is the one recorded at open, never inferred from a signer. + /// + /// `clearance` comes from [`Self::payer_refund`]: the program forfeits a + /// due refund to the treasury when the payer's token account cannot + /// take it, so a sealed distribute is built only once that was ruled out. pub fn distribute_instruction( &self, treasury: &Pubkey, token_program: &Pubkey, + clearance: &crate::core::payment_channel::payer_refund::DistributeClearance, ) -> Result { let deployment = crate::mpp::program::channel_deployment::resolve( self.program_id, self.channel_version, self.channel_hooks.as_ref(), )?; + if clearance.channel() != &self.channel_id { + return Err(Error::Other( + "distribution clearance was issued for another channel".into(), + )); + } let payer = self .payer .ok_or_else(|| Error::Other("distribution missing payer".into()))?; @@ -784,6 +834,7 @@ impl SessionServer { /// as a non-retryable payment failure at open time. pub fn build_challenge_request(&self) -> Result { self.config.channel_deployment()?; + self.config.check_sponsored_deposit_floor()?; if self.config.decimals > 9 { return Err(Error::InvalidConfig( "session token decimals must be between 0 and 9".to_string(), @@ -887,6 +938,7 @@ impl SessionServer { payload: &OpenPayload, ) -> Result { self.config.channel_deployment()?; + self.config.check_sponsored_deposit_floor()?; let payer = parse_pubkey_field(&payload.payer, "payer")?; let payee = parse_pubkey_field(&payload.payee, "payee")?; let mint = parse_pubkey_field(&payload.mint, "mint")?; @@ -1598,6 +1650,14 @@ impl SessionServer { state.cumulative = state.cumulative.max(onchain_settled); state.spent_amount = state.spent_amount.max(onchain_settled); state.settled_on_chain = state.settled_on_chain.max(onchain_settled); + // The confirmed read above found the channel open. + state.record_onchain_observation( + OnchainObservation { + slot: None, + lifecycle: ObservedLifecycle::Open, + }, + now_unix_secs().max(0) as u64, + ); Ok(state) }), ) @@ -1771,6 +1831,9 @@ impl SessionServer { .cumulative_amount .parse() .map_err(|_| Error::Other("Invalid cumulative in voucher".to_string()))?; + self.refresh_channel_snapshot(&voucher.data.channel_id) + .await?; + let max_age = self.snapshot_max_age(); // Wire-agnostic acceptance (signature + monotonicity + deposit cap + // min-delta + idempotent replay + atomic advance) lives in core so the @@ -1779,6 +1842,8 @@ impl SessionServer { // outlast it so the operator can still redeem on-chain after the async // forced-close delay. let owner = self.config.operator.clone(); + let expires_at = voucher.data.expires_at.unwrap_or(0); + let grace_period = self.config.grace_period_seconds; let acceptance = crate::core::session::accept_voucher_with_commit( &self.store, &voucher.data.channel_id, @@ -1794,6 +1859,7 @@ impl SessionServer { // TypeScript/Python session servers' availability gate. amount, move |state, replay| { + require_fresh_snapshot(state, max_age)?; if replay && !allow_replay { return Err(StoreError::Internal( "voucher was already accepted; sign a new voucher for this request".into(), @@ -1807,10 +1873,7 @@ impl SessionServer { .ok_or_else(|| StoreError::Internal("session spent amount overflow".into()))?; let now_ms = now_unix_secs().saturating_mul(1_000) as u64; state.last_activity_at = now_ms; - state.lifecycle = state.idle_timeout_seconds.map(|seconds| ChannelLifecycle { - owner: owner.clone(), - close_after: now_ms.saturating_add(u64::from(seconds) * 1_000), - }); + state.lifecycle = idle_lifecycle(state, &owner, now_ms, expires_at, grace_period); Ok(()) }, ) @@ -1828,11 +1891,7 @@ impl SessionServer { ) -> Result { use ed25519_dalek::Signer; - if idempotency_key.is_empty() { - return Err(Error::Other( - "operator-signed use requires an Idempotency-Key".to_string(), - )); - } + check_idempotency_key(idempotency_key)?; if self.config.voucher_signer != VoucherSigner::Operator { return Err(Error::Other( "use is only valid for operator-signed sessions".to_string(), @@ -1857,6 +1916,8 @@ impl SessionServer { let idempotency_key = idempotency_key.to_string(); let price = self.config.amount; let lifecycle_owner = self.config.operator.clone(); + self.refresh_channel_snapshot(&channel_id).await?; + let max_age = self.snapshot_max_age(); let result = std::sync::Arc::new(std::sync::Mutex::new(None)); let result_out = std::sync::Arc::clone(&result); self.store @@ -1893,6 +1954,7 @@ impl SessionServer { }); return Ok(state); } + require_fresh_snapshot(&state, max_age)?; let cumulative = state.cumulative.checked_add(price).ok_or_else(|| { StoreError::Internal("session cumulative overflow".to_string()) })?; @@ -1925,10 +1987,7 @@ impl SessionServer { state.highest_voucher_expires_at = Some(0); let now_ms = now_unix_secs().saturating_mul(1_000) as u64; state.last_activity_at = now_ms; - state.lifecycle = state.idle_timeout_seconds.map(|seconds| ChannelLifecycle { - owner: lifecycle_owner.clone(), - close_after: now_ms.saturating_add(u64::from(seconds) * 1_000), - }); + state.lifecycle = idle_lifecycle(&state, &lifecycle_owner, now_ms, 0, 0); record_use( &mut state.processed_uses, crate::core::store::ProcessedUse { @@ -1985,11 +2044,7 @@ impl SessionServer { challenge_id: &str, idempotency_key: &str, ) -> Result { - if idempotency_key.is_empty() { - return Err(Error::Other( - "operator-signed use requires an Idempotency-Key".to_string(), - )); - } + check_idempotency_key(idempotency_key)?; if self.config.voucher_signer != VoucherSigner::Operator { return Err(Error::Other( "use is only valid for operator-signed sessions".to_string(), @@ -2009,6 +2064,7 @@ impl SessionServer { )); } check_use_binding(&state, &payload.authentication, &authentication).map_err(store_err)?; + self.refresh_channel_snapshot(&payload.channel_id).await?; Ok(AuthenticatedUse { channel_id: payload.channel_id.clone(), authentication, @@ -2073,6 +2129,8 @@ impl SessionServer { } let guard = std::sync::Arc::new(guard); let channel_id = authenticated.channel_id.clone(); + self.refresh_channel_snapshot(&channel_id).await?; + let max_age = self.snapshot_max_age(); for _ in 0..OPERATOR_CHARGE_ATTEMPTS { let state = self .store @@ -2135,6 +2193,7 @@ impl SessionServer { )); } check_bound_authentication(&state, &authenticated.authentication)?; + require_fresh_snapshot(&state, max_age)?; let recorded = recorded_use(&state, &authenticated)?; // A retry of this request reached the total since the // read: answer with its record and write nothing new. @@ -2169,10 +2228,7 @@ impl SessionServer { state.highest_voucher_expires_at = Some(0); let now_ms = now_unix_secs().saturating_mul(1_000) as u64; state.last_activity_at = now_ms; - state.lifecycle = state.idle_timeout_seconds.map(|seconds| ChannelLifecycle { - owner: lifecycle_owner.clone(), - close_after: now_ms.saturating_add(u64::from(seconds) * 1_000), - }); + state.lifecycle = idle_lifecycle(&state, &lifecycle_owner, now_ms, 0, 0); record_use( &mut state.processed_uses, crate::core::store::ProcessedUse { @@ -2232,6 +2288,161 @@ impl SessionServer { .is_some_and(|state| state.cumulative != base)) } + /// Longest a confirmed channel read admits charges on that channel. + fn snapshot_max_age(&self) -> u64 { + CHANNEL_SNAPSHOT_MAX_AGE_SECONDS.min(u64::from(self.config.grace_period_seconds) / 2) + } + + /// Re-read the channel account once half of + /// [`Self::snapshot_max_age`] has passed since the record's last + /// confirmed read, so a forced close started onchain fences the record + /// before it admits another charge. + /// + /// A due read that fails or finds no account refuses the charge. A read + /// showing the channel closing or closed records the close (no further + /// charges), makes the channel's lifecycle due now so the host settles it + /// inside the grace period, and refuses the charge. + async fn refresh_channel_snapshot(&self, channel_id: &str) -> Result<()> { + let now = now_unix_secs().max(0) as u64; + let max_age = self.snapshot_max_age(); + let due = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false)); + let due_out = std::sync::Arc::clone(&due); + let observed_slot = std::sync::Arc::new(std::sync::atomic::AtomicU64::new(0)); + let observed_slot_out = std::sync::Arc::clone(&observed_slot); + self.store + .read_channel( + channel_id, + Box::new(move |state| { + if let Some(state) = state { + observed_slot_out.store( + state.onchain_observed_slot(), + std::sync::atomic::Ordering::Relaxed, + ); + } + let stale = state.is_some_and(|state| { + !state.sealed + && state.close_requested_at.is_none() + && !state + .pending_setup + .as_ref() + .is_some_and(|setup| setup.opens_channel) + && now + .saturating_sub(state.onchain_observed_at()) + .saturating_mul(2) + >= max_age + }); + due_out.store(stale, std::sync::atomic::Ordering::Relaxed); + Ok(()) + }), + ) + .await + .map_err(store_err)?; + if !due.load(std::sync::atomic::Ordering::Relaxed) { + return Ok(()); + } + // A lagging node may still show a closing channel as open: read from + // a bank at least as recent as the one last recorded, and record the + // answering slot so an older view can never renew the window. + let min_slot = observed_slot.load(std::sync::atomic::Ordering::Relaxed); + let (read, slot) = self + .read_channel_lifecycle(channel_id, now, min_slot) + .await?; + let (lifecycle, settled) = + read.ok_or_else(|| Error::Other(format!("Channel {channel_id} not found onchain")))?; + let owner = self.config.operator.clone(); + self.store + .mutate_channel( + channel_id, + None, + Box::new(move |state| { + state.settled_on_chain = state.settled_on_chain.max(settled); + let outcome = state.record_onchain_observation( + OnchainObservation { + slot: Some(slot), + lifecycle, + }, + now, + ); + if let crate::core::store::ObservationOutcome::Behind { recorded } = outcome { + return Err(StoreError::Internal(format!( + "channel read at slot {slot} is behind the recorded slot {recorded}" + ))); + } + if lifecycle != ObservedLifecycle::Open { + let now_ms = now.saturating_mul(1_000); + let close_after = state + .lifecycle + .as_ref() + .map_or(now_ms, |current| current.close_after.min(now_ms)); + state.lifecycle = Some(ChannelLifecycle { owner, close_after }); + } + Ok(()) + }), + ) + .await + .map_err(store_err)?; + match lifecycle { + ObservedLifecycle::Open => Ok(()), + ObservedLifecycle::Closing { started_at } => Err(Error::Other(format!( + "Channel close is pending — channel {channel_id} has been closing onchain \ + since {started_at}; no further charges accepted" + ))), + ObservedLifecycle::Terminal { .. } => Err(Error::Other(format!( + "Channel {channel_id} is already sealed onchain" + ))), + } + } + + /// The lifecycle and settled watermark of the channel account (`None` + /// when it does not exist), read at confirmed commitment from a bank at + /// or after `min_slot`, with the slot that answered. + #[cfg(feature = "server")] + async fn read_channel_lifecycle( + &self, + channel_id: &str, + now: u64, + min_slot: u64, + ) -> Result<(Option<(ObservedLifecycle, u64)>, u64)> { + if self.config.rpc_url.is_none() { + return Err(Error::Other(format!( + "channel {channel_id} needs a confirmed onchain read before it accepts charges, \ + and no RPC is configured" + ))); + } + let pipeline = self.transaction_pipeline().await?; + let deployment = self.config.channel_deployment()?; + let (data, slot) = pipeline + .read_confirmed_owned_account_data_at( + parse_pubkey(channel_id)?, + min_slot, + deployment.program_id, + ) + .await + .map_err(|error| Error::Rpc(format!("channel account read failed: {error}")))?; + let read = data + .map(|data| { + let channel = deployment.decode_channel(&data)?.channel; + Ok::<_, Error>(( + ObservedLifecycle::of_channel(channel.status, channel.closure_started_at, now), + channel.settlement.settled, + )) + }) + .transpose()?; + Ok((read, slot)) + } + + #[cfg(not(feature = "server"))] + async fn read_channel_lifecycle( + &self, + _channel_id: &str, + _now: u64, + _min_slot: u64, + ) -> Result<(Option<(ObservedLifecycle, u64)>, u64)> { + Err(Error::Other( + "session channel reads require the `server` feature".to_string(), + )) + } + /// Process a `topup` action: atomically update the channel's deposit cap. /// /// The additional amount must be positive and must not overflow the @@ -2306,6 +2517,7 @@ impl SessionServer { let cid = payload.channel_id.clone(); let lifecycle_owner = self.config.operator.clone(); + let grace_period = self.config.grace_period_seconds; let replay = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false)); let replay_out = std::sync::Arc::clone(&replay); let transaction_signature = topup_signature.clone(); @@ -2342,10 +2554,13 @@ impl SessionServer { StoreError::Internal("top-up deposit overflow".to_string()) })?; let now_ms = now_unix_secs().saturating_mul(1_000) as u64; - state.lifecycle = state.idle_timeout_seconds.map(|seconds| ChannelLifecycle { - owner: lifecycle_owner.clone(), - close_after: now_ms.saturating_add(u64::from(seconds) * 1_000), - }); + state.lifecycle = idle_lifecycle( + &state, + &lifecycle_owner, + now_ms, + state.highest_voucher_expires_at.unwrap_or(0), + grace_period, + ); state.deposit = new_deposit; state.last_activity_at = now_ms; state @@ -2383,6 +2598,8 @@ impl SessionServer { .expires_at .unwrap_or(crate::mpp::protocol::intents::session::DEFAULT_SESSION_EXPIRES_AT); let directive_out = std::sync::Arc::new(std::sync::Mutex::new(None)); + self.refresh_channel_snapshot(&session_id).await?; + let max_age = self.snapshot_max_age(); self.store .update_channel( @@ -2405,6 +2622,7 @@ impl SessionServer { .to_string(), )); } + require_fresh_snapshot(&state, max_age)?; let reserved = state .pending_deliveries .iter() @@ -2598,6 +2816,7 @@ impl SessionServer { let signature = payload.voucher.signature.clone(); let expires_at = payload.voucher.data.expires_at.unwrap_or(0); let lifecycle_owner = self.config.operator.clone(); + let grace_period = self.config.grace_period_seconds; let commit_outcome = std::sync::Arc::new(std::sync::Mutex::new(None)); let _new_state = self .store @@ -2694,11 +2913,13 @@ impl SessionServer { // actively paying through the metered-delivery flow. let now_ms = now_unix_secs().saturating_mul(1_000) as u64; state.last_activity_at = now_ms; - state.lifecycle = - state.idle_timeout_seconds.map(|seconds| ChannelLifecycle { - owner: lifecycle_owner.clone(), - close_after: now_ms.saturating_add(u64::from(seconds) * 1_000), - }); + state.lifecycle = idle_lifecycle( + &state, + &lifecycle_owner, + now_ms, + expires_at, + grace_period, + ); state.committed_deliveries.push_back(CommittedDelivery { delivery_id: delivery_id.clone(), amount: actual_amount, @@ -2712,6 +2933,11 @@ impl SessionServer { cached_response: None, retain_until: 0, }); + // A commit evicted here can no longer be replayed, + // only refused: its delivery is no longer pending. + while state.committed_deliveries.len() > MAX_COMMITTED_AUTHORIZATIONS { + state.committed_deliveries.pop_front(); + } *commit_outcome.lock().unwrap() = Some((actual_amount, new_cumulative, CommitStatus::Committed)); Ok(state) @@ -2933,6 +3159,13 @@ impl SessionServer { } /// Return seal parameters for a channel ready for on-chain settlement. + /// + /// The channel's settled watermark is re-read onchain when an RPC is + /// configured (a failed read falls back to the stored one, so a retry + /// re-reads it). Once that watermark reaches the stored cumulative the + /// highest voucher can no longer be applied (the program requires it to + /// exceed `settled`), so no voucher is returned and the close seals at + /// the onchain watermark. pub async fn seal_params(&self, channel_id: &str) -> Result { let state = self .store @@ -2947,6 +3180,33 @@ impl SessionServer { state.cumulative, state.deposit ))); } + let mut state = state; + let now = now_unix_secs().max(0) as u64; + if let Ok((Some((_, onchain)), _)) = self.read_channel_lifecycle(channel_id, now, 0).await { + if onchain > state.settled_on_chain { + state.settled_on_chain = onchain; + self.store + .mutate_channel( + channel_id, + None, + Box::new(move |state| { + state.settled_on_chain = state.settled_on_chain.max(onchain); + Ok(()) + }), + ) + .await + .map_err(store_err)?; + } + } + let (voucher_signature, voucher_expires_at) = if state.settled_on_chain >= state.cumulative + { + (None, None) + } else { + ( + state.highest_voucher_signature, + state.highest_voucher_expires_at, + ) + }; let channel_pubkey = parse_pubkey(channel_id)?; let recipient_pubkey = parse_pubkey(&self.config.recipient)?; @@ -2980,9 +3240,9 @@ impl SessionServer { program_id, channel_version: self.config.channel_version, channel_hooks: self.config.channel_hooks.clone(), - settled: state.cumulative, - voucher_signature: state.highest_voucher_signature, - voucher_expires_at: state.highest_voucher_expires_at, + settled: state.cumulative.max(state.settled_on_chain), + voucher_signature, + voucher_expires_at, recipient: recipient_pubkey, splits: self.config.splits.clone(), distribution_hash, @@ -2991,16 +3251,112 @@ impl SessionServer { /// Mark a channel as sealed (call after the on-chain seal tx confirms). pub async fn mark_sealed(&self, channel_id: &str) -> Result<()> { - self.store.mark_sealed(channel_id).await.map_err(store_err) + self.store + .mark_sealed(channel_id) + .await + .map_err(store_err)?; + let now = now_unix_secs(); + self.store + .mutate_channel( + channel_id, + None, + Box::new(move |state| { + state + .extra + .entry(SEALED_AT_KEY.to_string()) + .or_insert_with(|| now.into()); + Ok(()) + }), + ) + .await + .map_err(store_err) + } + + /// When [`Self::mark_sealed`] first recorded the channel sealed (unix + /// seconds), the start of a deferred distribute's deadline + /// ([`SealParams::payer_refund`]). + pub async fn sealed_at(&self, channel_id: &str) -> Result> { + Ok(self + .store + .get_channel(channel_id) + .await + .map_err(store_err)? + .and_then(|state| state.extra.get(SEALED_AT_KEY)?.as_i64())) } } +/// Where a session record keeps the time it was first recorded sealed, +/// inside [`ChannelState::extra`]. +const SEALED_AT_KEY: &str = "mppSealedAt"; + // ── Helpers ── fn store_err(e: StoreError) -> Error { Error::Other(e.to_string()) } +/// An operator-signed `use` must name its request with a non-empty +/// `Idempotency-Key` of at most [`MAX_IDEMPOTENCY_KEY_BYTES`]. +fn check_idempotency_key(key: &str) -> Result<()> { + if key.is_empty() { + return Err(Error::Other( + "operator-signed use requires an Idempotency-Key".to_string(), + )); + } + if key.len() > MAX_IDEMPOTENCY_KEY_BYTES { + return Err(Error::Other(format!( + "Idempotency-Key exceeds {MAX_IDEMPOTENCY_KEY_BYTES} bytes" + ))); + } + Ok(()) +} + +/// The idle-close deadline after activity at `now_ms`: the negotiated idle +/// timeout, but never later than `grace_period` seconds before the expiry of +/// the voucher the close will settle (`0`: never expires), so that voucher is +/// still redeemable when the host closes the channel. +fn idle_lifecycle( + state: &ChannelState, + owner: &str, + now_ms: u64, + voucher_expires_at: i64, + grace_period: u32, +) -> Option { + state.idle_timeout_seconds.map(|seconds| { + let idle = now_ms.saturating_add(u64::from(seconds) * 1_000); + let close_after = match u64::try_from(voucher_expires_at) { + Ok(expires_at) if expires_at > 0 => idle.min( + expires_at + .saturating_sub(u64::from(grace_period)) + .saturating_mul(1_000), + ), + _ => idle, + }; + ChannelLifecycle { + owner: owner.to_string(), + close_after, + } + }) +} + +/// Refuse a charge on a record whose last confirmed onchain read is older +/// than `max_age` seconds: only a fresh read can rule out a forced close. +/// Checked inside every admitting mutation, after +/// [`SessionServer::refresh_channel_snapshot`]. +fn require_fresh_snapshot( + state: &ChannelState, + max_age: u64, +) -> std::result::Result<(), StoreError> { + let now = now_unix_secs().max(0) as u64; + if now.saturating_sub(state.onchain_observed_at()) > max_age { + return Err(StoreError::Internal(format!( + "channel {} has no confirmed onchain read in the last {max_age}s", + state.channel_id + ))); + } + Ok(()) +} + /// The checks a `use` proof must pass against the channel record: the /// channel is operator-signed and bound at open to exactly this proof, which /// was issued for the opening challenge by the payer and verifies over the @@ -3426,7 +3782,7 @@ async fn submit_and_fetch_open( // first submission landed (response lost, or the store write after it // failed) dies at preflight with "already processed", and the pipeline // still reports that signature's confirmed landing. - let submission = pipeline.submit_verified(&tx).await; + let submission = submit_client_transaction(pipeline, tx, config).await; let min_context_slot = submission.as_ref().ok().map(|confirmed| confirmed.slot); if let (Some(floor), Ok(landed)) = (activation_floor, &submission) { if let Err(elsewhere) = landed_here(landed.slot, floor) { @@ -3446,6 +3802,31 @@ async fn submit_and_fetch_open( }) } +/// Broadcast a validated client `open` or `topUp` and await confirmation. +/// One the configured sponsor pays the fee for is simulated first: it is +/// charged for a transaction that fails on-chain, and the offline checks +/// cannot show that the payer holds the tokens it moves. +#[cfg(feature = "server")] +async fn submit_client_transaction( + pipeline: &crate::core::tx_pipeline::TxPipeline, + tx: solana_transaction::versioned::VersionedTransaction, + config: &SessionConfig, +) -> std::result::Result< + crate::core::tx_pipeline::ConfirmedTransaction, + crate::core::tx_pipeline::TxPipelineError, +> { + let sponsor = config + .fee_payer_signer + .as_ref() + .map(|signer| signer.pubkey()); + if sponsor.is_some() && tx.message.static_account_keys().first() == sponsor.as_ref() { + let simulated = pipeline.simulate(tx).await?; + pipeline.submit_simulated(&simulated).await + } else { + pipeline.submit_verified(&tx).await + } +} + #[cfg(feature = "server")] async fn validate_open_slot( pipeline: &crate::core::tx_pipeline::TxPipeline, @@ -3715,8 +4096,7 @@ async fn verify_submit_and_fetch_topup( // atomic mutator in `process_topup_with_outcome` credits // `additionalAmount` once per distinct signature — stacking N credits in // the store for one real on-chain deposit. - let confirmed = pipeline - .submit_verified(&tx) + let confirmed = submit_client_transaction(pipeline, tx, config) .await .map_err(|error| Error::Rpc(format!("top-up submission failed: {error}")))?; // A confirmed signature can still be forked out, and the aggregate @@ -4001,6 +4381,33 @@ mod tests { } } + // A sponsor funds each channel's rent; without a deposit floor a 1-unit + // deposit buys that rent, so a sponsored server must name the floor. + #[test] + fn sponsored_sessions_require_a_minimum_deposit() { + let mut cfg = config(VoucherSigner::Client); + cfg.fee_payer_signer = Some(shared_signer(8)); + cfg.minimum_deposit = None; + let server = SessionServer::new(cfg.clone(), MemoryChannelStore::new()); + let challenge = server.build_challenge_request().unwrap_err().to_string(); + assert!(challenge.contains("minimum_deposit"), "{challenge}"); + let open = valid_open(&server); + let open = server.payment_channel_open_params(&open).unwrap_err(); + assert!(open.to_string().contains("minimum_deposit"), "{open}"); + + // Positive controls: a sponsored server with a floor, and an + // unsponsored one without, both get past the check. + cfg.minimum_deposit = Some(100); + let server = SessionServer::new(cfg, MemoryChannelStore::new()); + let open = valid_open(&server); + server.payment_channel_open_params(&open).unwrap(); + let mut unsponsored = config(VoucherSigner::Client); + unsponsored.minimum_deposit = None; + let server = SessionServer::new(unsponsored, MemoryChannelStore::new()); + let open = valid_open(&server); + server.payment_channel_open_params(&open).unwrap(); + } + #[test] fn v2_network_is_checked_for_raw_config_and_challenges_before_rpc() { let mut config = config(VoucherSigner::Client); @@ -4033,7 +4440,7 @@ mod tests { } fn state(channel_id: String, authorized_signer: String) -> ChannelState { - ChannelState { + let mut state = ChannelState { channel_id, authorized_signer, deposit: 1_000, @@ -4064,7 +4471,15 @@ mod tests { lifecycle: None, schema_version: CHANNEL_STATE_SCHEMA_VERSION, extra: Default::default(), - } + }; + state.record_onchain_observation( + OnchainObservation { + slot: None, + lifecycle: ObservedLifecycle::Open, + }, + now_unix_secs() as u64, + ); + state } async fn client_server() -> (SessionServer, ActiveSession, String) { @@ -4151,6 +4566,9 @@ mod tests { enum LandedStatus { Finalized, Failed, + /// Fails simulation (e.g. the payer cannot fund it) and would fail + /// on-chain if sent. + Unexecutable, /// Confirmed but never finalized (e.g. on a fork that is abandoned). ConfirmedOnly, } @@ -4246,6 +4664,27 @@ mod tests { Ok(json!({"context": {"slot": 42}, "value": true})) } "getSlot" => Ok(json!(slot.load(std::sync::atomic::Ordering::SeqCst))), + "simulateTransaction" => { + assert_eq!(request["params"][1]["commitment"], "confirmed"); + assert_eq!(request["params"][1]["replaceRecentBlockhash"], false); + let signature = payment_channels::decode_transaction( + request["params"][0].as_str().unwrap(), + ) + .unwrap() + .signatures[0] + .to_string(); + let err = if landed.lock().unwrap().contains_key(&signature) { + json!("AlreadyProcessed") + } else if landed_status == LandedStatus::Unexecutable { + json!({"InstructionError": [1, {"Custom": 1}]}) + } else { + Value::Null + }; + Ok(json!({ + "context": { "slot": slot.load(std::sync::atomic::Ordering::SeqCst) }, + "value": { "err": err, "logs": [], "accounts": null, "unitsConsumed": 0 } + })) + } "sendTransaction" => { send_tx_count.fetch_add(1, std::sync::atomic::Ordering::SeqCst); let signature = payment_channels::decode_transaction( @@ -4284,7 +4723,10 @@ mod tests { .get(signature.as_str().unwrap()) .copied() { - if landed_status == LandedStatus::Failed { + if matches!( + landed_status, + LandedStatus::Failed | LandedStatus::Unexecutable + ) { // A signature the RPC saw land, but // whose execution failed on-chain // (e.g. insufficient fee-payer @@ -4535,7 +4977,7 @@ mod tests { use crate::core::tx::{ComputeBudget, TxVersion}; use crate::mpp::client::session::{ build_open_payment_channel_transaction, BuildOpenPaymentChannelTransactionParams, - PaymentChannelOpenOptions, + OpenBlockhash, PaymentChannelOpenOptions, SessionOpenAuthorization, }; let mut cfg = config(VoucherSigner::Client); @@ -4558,7 +5000,15 @@ mod tests { signer: payer.as_ref(), authorized_signer: params.authorized_signer, fee_payer: None, - recent_blockhash: None, + blockhash: OpenBlockhash::from_client_cluster(test_blockhash()), + authorization: &SessionOpenAuthorization::client_signed( + request + .suggested_deposit + .as_deref() + .unwrap() + .parse() + .unwrap(), + ), options: PaymentChannelOpenOptions { compute_budget: Some(budget), salt: Some(params.salt), @@ -4676,6 +5126,73 @@ mod tests { rpc.abort(); } + // The sponsor pays the fee of a sponsored open even when it fails + // on-chain (an empty payer token account), so one that fails simulation + // never reaches the network. + #[cfg(feature = "server")] + #[tokio::test(flavor = "multi_thread")] + async fn sponsored_open_that_fails_simulation_is_never_broadcast() { + use payment_channels::generated::generated::types::SettlementWatermarks; + + for (status, lands) in [ + (LandedStatus::Unexecutable, false), + (LandedStatus::Finalized, true), + ] { + let sponsor = shared_signer(8); + let mut cfg = config(VoucherSigner::Client); + cfg.fee_payer_signer = Some(std::sync::Arc::clone(&sponsor)); + let mut server = SessionServer::new(cfg, MemoryChannelStore::new()); + let (open, params) = signed_open(&server, 6).await; + let channel = payment_channels::generated::generated::accounts::Channel { + discriminator: 1, + version: 1, + bump: 1, + status: 0, + salt: params.salt, + deposit: params.deposit, + settlement: SettlementWatermarks { + settled: 0, + payout_watermark: 0, + }, + closure_started_at: 0, + payer_withdrawn_at: 0, + grace_period: params.grace_period, + distribution_hash: payment_channels::distribution_hash(¶ms.recipients), + payer: payment_channels::to_address(¶ms.payer), + payee: payment_channels::to_address(¶ms.payee), + authorized_signer: payment_channels::to_address(¶ms.authorized_signer), + mint: payment_channels::to_address(¶ms.mint), + rent_payer: payment_channels::to_address(¶ms.rent_payer), + open_slot: params.open_slot, + }; + let (url, rpc, sends) = rpc_for_channel_with_options(channel, 43, status).await; + server.config.rpc_url = Some(url); + let blockhash = test_blockhash().to_string(); + let result = server + .process_open( + &open, + SessionOpenContext { + challenge_id: "opening", + expires: None, + recent_blockhash: &blockhash, + recent_slot: CHALLENGED_SLOT, + }, + ) + .await; + if lands { + result.unwrap(); + } else { + let error = result.unwrap_err().to_string(); + assert!(error.contains("failed simulation"), "{error}"); + } + assert_eq!( + sends.load(std::sync::atomic::Ordering::SeqCst), + usize::from(lands) + ); + rpc.abort(); + } + } + #[cfg(feature = "server")] #[tokio::test(flavor = "multi_thread")] async fn sponsored_open_rejects_payer_aliasing_the_fee_payer() { @@ -6442,6 +6959,111 @@ mod tests { rpc.abort(); } + // A sponsored top-up the payer cannot fund fails simulation and is never + // broadcast at the sponsor's expense. + #[cfg(feature = "server")] + #[tokio::test(flavor = "multi_thread")] + async fn sponsored_topup_that_fails_simulation_is_never_broadcast() { + use payment_channels::generated::generated::types::SettlementWatermarks; + + for (status, lands) in [ + (LandedStatus::Unexecutable, false), + (LandedStatus::Finalized, true), + ] { + let (mut server, _session, channel_id) = client_server().await; + let payer = signer(5); + let sponsor = shared_signer(8); + server.config.fee_payer_signer = Some(std::sync::Arc::clone(&sponsor)); + server + .store + .update_channel( + &channel_id, + Box::new({ + let payer = payer.pubkey().to_string(); + let rent_payer = sponsor.pubkey().to_string(); + move |state| { + let mut state = state.unwrap(); + state.payer = payer; + state.rent_payer = rent_payer; + Ok(state) + } + }), + ) + .await + .unwrap(); + let channel = Pubkey::from_str(&channel_id).unwrap(); + let mint = Pubkey::from_str(mints::USDC_MAINNET).unwrap(); + let token_program = Pubkey::from_str(programs::TOKEN_PROGRAM).unwrap(); + let program_id = payment_channels::default_program_id(); + let ix = payment_channels::build_top_up_instruction( + &payer.pubkey(), + &channel, + &mint, + 100, + &token_program, + &program_id, + ); + let mut tx = crate::core::tx::build_unsigned_unchecked( + crate::core::tx::TxVersion::V0, + &sponsor.pubkey(), + &[ix], + solana_hash::Hash::new_unique(), + None, + ) + .unwrap(); + crate::core::signing::sign_versioned_transaction_slot(payer.as_ref(), &mut tx) + .await + .unwrap(); + let transaction = crate::core::tx::encode(&tx).unwrap(); + // The on-chain account already reflects deposit=1_100 — as if a + // *different* concurrent top-up already landed — even though THIS + // request's own transaction is about to be reported as failed. + let account = payment_channels::generated::generated::accounts::Channel { + discriminator: 1, + version: 1, + bump: 1, + status: 0, + salt: 7, + deposit: 1_100, + settlement: SettlementWatermarks { + settled: 0, + payout_watermark: 0, + }, + closure_started_at: 0, + payer_withdrawn_at: 0, + grace_period: server.config.grace_period_seconds, + distribution_hash: [0; 32], + payer: payment_channels::to_address(&payer.pubkey()), + payee: payment_channels::to_address( + &Pubkey::from_str(&server.config.recipient).unwrap(), + ), + authorized_signer: payment_channels::to_address(&signer(1).pubkey()), + mint: payment_channels::to_address(&mint), + rent_payer: payment_channels::to_address(&sponsor.pubkey()), + open_slot: 42, + }; + let (url, rpc, sends) = rpc_for_channel_with_options(account, 43, status).await; + server.config.rpc_url = Some(url); + let payload = TopUpPayload { + channel_id: channel_id.clone(), + additional_amount: "100".into(), + transaction, + }; + let result = server.process_topup_with_outcome(&payload).await; + if lands { + result.unwrap(); + } else { + let error = result.unwrap_err().to_string(); + assert!(error.contains("failed simulation"), "{error}"); + } + assert_eq!( + sends.load(std::sync::atomic::Ordering::SeqCst), + usize::from(lands) + ); + rpc.abort(); + } + } + /// Regression: a top-up whose own transaction fails on-chain must not be /// credited just because the channel's *aggregate* on-chain deposit /// happens to already meet `state.deposit + amount` — that aggregate can @@ -6768,22 +7390,97 @@ mod tests { ); } - #[tokio::test] - async fn seal_params_refuses_a_watermark_above_deposit() { - let (server, _session, channel_id) = client_server().await; - server - .store - .update_channel( - &channel_id, - Box::new(|state| { - let mut state = state.unwrap(); - state.cumulative = state.deposit + 1; - Ok(state) - }), - ) - .await - .unwrap(); - assert!(server.seal_params(&channel_id).await.is_err()); + #[cfg(feature = "server")] + /// A client channel at cumulative 100 holding its highest voucher, whose + /// account (served when `onchain_settled` is set) has settled that much. + async fn sealable_channel( + onchain_settled: Option, + ) -> ( + SessionServer, + String, + Option>, + ) { + let channel = Pubkey::new_unique(); + let channel_id = channel.to_string(); + let mut session = ActiveSession::new(channel, signer(1)); + let voucher = session.sign_increment(100).await.unwrap(); + let mut stored = state(channel_id.clone(), signer_address(1)); + stored.cumulative = 100; + stored.highest_voucher_signature = Some(voucher.signature); + stored.highest_voucher_expires_at = Some(voucher.data.expires_at.unwrap_or(0)); + let mut cfg = config(VoucherSigner::Client); + let rpc = match onchain_settled { + Some(settled) => { + let account = channel_account(&stored, 0, 0, settled); + let (url, rpc, _) = rpc_for_channel(account, 43).await; + cfg.rpc_url = Some(url); + Some(rpc) + } + None => None, + }; + (seeded_server(cfg, stored).await, channel_id, rpc) + } + + #[cfg(feature = "server")] + #[tokio::test] + async fn seal_params_omits_a_voucher_already_settled_onchain() { + let (server, channel_id, rpc) = sealable_channel(Some(100)).await; + let seal = server.seal_params(&channel_id).await.unwrap(); + assert_eq!(seal.settled, 100); + assert!(seal.voucher_signature.is_none()); + let operator = Pubkey::from_str(&server.config.operator).unwrap(); + // settle_and_seal alone, with no Ed25519 voucher instruction. + assert_eq!(seal.settle_instructions(&operator).unwrap().len(), 1); + assert_eq!(stored(&server, &channel_id).await.settled_on_chain, 100); + + // The recorded watermark keeps the voucher out without a read. + rpc.unwrap().abort(); + assert!(server + .seal_params(&channel_id) + .await + .unwrap() + .voucher_signature + .is_none()); + } + + #[cfg(feature = "server")] + #[tokio::test] + async fn seal_params_keeps_a_voucher_above_the_onchain_watermark() { + let (server, channel_id, rpc) = sealable_channel(Some(40)).await; + let seal = server.seal_params(&channel_id).await.unwrap(); + assert_eq!(seal.settled, 100); + assert!(seal.voucher_signature.is_some()); + let operator = Pubkey::from_str(&server.config.operator).unwrap(); + assert_eq!(seal.settle_instructions(&operator).unwrap().len(), 2); + assert_eq!(stored(&server, &channel_id).await.settled_on_chain, 40); + rpc.unwrap().abort(); + + // Without an RPC the stored watermark decides. + let (server, channel_id, _) = sealable_channel(None).await; + assert!(server + .seal_params(&channel_id) + .await + .unwrap() + .voucher_signature + .is_some()); + } + + #[tokio::test] + async fn seal_params_refuses_a_watermark_above_deposit() { + let (server, _session, channel_id) = client_server().await; + server + .store + .update_channel( + &channel_id, + Box::new(|state| { + let mut state = state.unwrap(); + state.cumulative = state.deposit + 1; + Ok(state) + }), + ) + .await + .unwrap(); + assert!(server.seal_params(&channel_id).await.is_err()); } fn action_voucher(action: crate::mpp::SessionAction) -> VoucherPayload { @@ -7308,6 +8005,358 @@ mod tests { assert_eq!(after.spent_amount, 50); } + #[cfg(feature = "server")] + /// A channel account as the program stores it, at `status` with a forced + /// close started at `closure_started_at` (`0`: none). + fn channel_account( + state: &ChannelState, + status: u8, + closure_started_at: i64, + settled: u64, + ) -> payment_channels::generated::generated::accounts::Channel { + let key = |value: &str| payment_channels::to_address(&Pubkey::from_str(value).unwrap()); + payment_channels::generated::generated::accounts::Channel { + discriminator: 1, + version: 1, + bump: 1, + status, + salt: 7, + deposit: state.deposit, + settlement: payment_channels::generated::generated::types::SettlementWatermarks { + settled, + payout_watermark: 0, + }, + closure_started_at, + payer_withdrawn_at: 0, + grace_period: payment_channels::DEFAULT_GRACE_PERIOD_SECONDS, + distribution_hash: [0; 32], + payer: key(&state.payer), + payee: payment_channels::to_address(&Pubkey::new_unique()), + authorized_signer: key(&state.authorized_signer), + mint: payment_channels::to_address(&Pubkey::new_unique()), + rent_payer: key(&state.rent_payer), + open_slot: 42, + } + } + + /// `stored`, last confirmed onchain long ago. + fn stale(mut stored: ChannelState) -> ChannelState { + stored.record_onchain_observation( + OnchainObservation { + slot: None, + lifecycle: ObservedLifecycle::Open, + }, + 1, + ); + stored + } + + /// A client-signed channel whose snapshot is stale, served by a fixture + /// RPC holding its account at `status` / `closure_started_at`. + #[cfg(feature = "server")] + async fn client_channel_onchain( + status: u8, + closure_started_at: i64, + ) -> ( + SessionServer, + ActiveSession, + String, + tokio::task::JoinHandle<()>, + ) { + let channel = Pubkey::new_unique(); + let channel_id = channel.to_string(); + let stored = stale(state(channel_id.clone(), signer_address(1))); + let account = channel_account(&stored, status, closure_started_at, 0); + let (url, rpc, _) = rpc_for_channel(account, 43).await; + let mut cfg = config(VoucherSigner::Client); + cfg.rpc_url = Some(url); + ( + seeded_server(cfg, stored).await, + ActiveSession::new(channel, signer(1)), + channel_id, + rpc, + ) + } + + #[cfg(feature = "server")] + #[tokio::test] + async fn a_forced_close_started_onchain_stops_vouchers_and_makes_the_close_due() { + let started_at = now_unix_secs() - 10; + let (server, mut session, channel_id, rpc) = client_channel_onchain(2, started_at).await; + let voucher = session.sign_increment(100).await.unwrap(); + let error = server + .verify_voucher(&voucher_payload(voucher)) + .await + .unwrap_err(); + assert!(error.to_string().contains("closing onchain"), "{error}"); + + let after = stored(&server, &channel_id).await; + assert_eq!(after.cumulative, 0); + assert_eq!(after.spent_amount, 0); + assert_eq!(after.close_requested_at, Some(started_at as u64)); + let due = after + .lifecycle + .expect("closing channel is scheduled") + .close_after; + assert!(due <= now_unix_secs() as u64 * 1_000); + + // The record alone now refuses every further voucher. + rpc.abort(); + let next = session.sign_increment(100).await.unwrap(); + let error = server + .verify_voucher_for_amount(&voucher_payload(next), 25) + .await + .unwrap_err(); + assert!(error.to_string().contains("close is pending"), "{error}"); + assert!(server + .begin_delivery(DeliveryRequest::new(channel_id.clone(), 10)) + .await + .is_err()); + } + + #[cfg(feature = "server")] + #[tokio::test] + async fn an_open_channel_read_renews_the_snapshot_and_admits_the_voucher() { + let (server, mut session, channel_id, rpc) = client_channel_onchain(0, 0).await; + let voucher = session.sign_increment(100).await.unwrap(); + let accepted = server + .verify_voucher(&voucher_payload(voucher)) + .await + .unwrap(); + assert_eq!(accepted.charged, 100); + let after = stored(&server, &channel_id).await; + assert!(after.close_requested_at.is_none()); + assert!(now_unix_secs() as u64 - after.onchain_observed_at() <= 1); + + // Inside the window the snapshot stands in for a read. + rpc.abort(); + let next = session.sign_increment(100).await.unwrap(); + assert_eq!( + server + .verify_voucher(&voucher_payload(next)) + .await + .unwrap() + .charged, + 100 + ); + assert!(server + .begin_delivery(DeliveryRequest::new(channel_id, 10)) + .await + .is_ok()); + } + + /// A lagging RPC node can still show a channel open after the payer + /// started closing it: a read from a bank older than the recorded one + /// never renews the charge window. + #[cfg(feature = "server")] + #[tokio::test] + async fn a_read_behind_the_recorded_slot_never_renews_the_snapshot() { + let channel = Pubkey::new_unique(); + let channel_id = channel.to_string(); + let mut record = state(channel_id.clone(), signer_address(1)); + record.record_onchain_observation( + OnchainObservation { + slot: Some(100), + lifecycle: ObservedLifecycle::Open, + }, + 1, + ); + let account = channel_account(&record, 0, 0, 0); + // The node answers from slot 43, behind the recorded 100. + let (url, _rpc, _) = rpc_for_channel(account, 43).await; + let mut cfg = config(VoucherSigner::Client); + cfg.rpc_url = Some(url); + let server = seeded_server(cfg, record).await; + let mut session = ActiveSession::new(channel, signer(1)); + let voucher = session.sign_increment(100).await.unwrap(); + assert!(server + .verify_voucher(&voucher_payload(voucher)) + .await + .is_err()); + let after = stored(&server, &channel_id).await; + assert_eq!(after.cumulative, 0); + assert_eq!(after.onchain_observed_at(), 1, "the window was not renewed"); + assert_eq!(after.onchain_observed_slot(), 100); + } + + #[tokio::test] + async fn a_stale_snapshot_without_a_read_refuses_every_charge() { + let channel = Pubkey::new_unique(); + let channel_id = channel.to_string(); + let server = seeded_server( + config(VoucherSigner::Client), + stale(state(channel_id.clone(), signer_address(1))), + ) + .await; + let mut session = ActiveSession::new(channel, signer(1)); + let voucher = session.sign_increment(100).await.unwrap(); + assert!(server + .verify_voucher(&voucher_payload(voucher)) + .await + .is_err()); + assert!(server + .begin_delivery(DeliveryRequest::new(channel_id.clone(), 10)) + .await + .is_err()); + let after = stored(&server, &channel_id).await; + assert_eq!(after.cumulative, 0); + assert!(after.pending_deliveries.is_empty()); + + let cfg = config(VoucherSigner::Operator); + let channel_id = Pubkey::new_unique().to_string(); + let proof = SessionAuthentication::sign("opening", &channel_id, &key(3)).unwrap(); + let mut bound = stale(state(channel_id.clone(), cfg.operator.clone())); + bound.payer = proof.payer.clone(); + bound.authentication = Some(serde_json::to_string(&proof).unwrap()); + bound.voucher_signer = "operator".into(); + let server = seeded_server(cfg, bound).await; + let payload = UsePayload { + channel_id: channel_id.clone(), + authentication: proof, + }; + assert!(server + .process_use(&payload, "use-1", "request-1") + .await + .is_err()); + assert!(server + .authenticate_use(&payload, "use-1", "request-1") + .await + .is_err()); + assert_eq!(stored(&server, &channel_id).await.cumulative, 0); + } + + #[cfg(feature = "server")] + #[tokio::test] + async fn operator_use_stops_once_the_channel_is_closing_onchain() { + let cfg = config(VoucherSigner::Operator); + let channel_id = Pubkey::new_unique().to_string(); + let proof = SessionAuthentication::sign("opening", &channel_id, &key(3)).unwrap(); + let mut bound = stale(state(channel_id.clone(), cfg.operator.clone())); + bound.payer = proof.payer.clone(); + bound.authentication = Some(serde_json::to_string(&proof).unwrap()); + bound.voucher_signer = "operator".into(); + let account = channel_account(&bound, 2, now_unix_secs() - 5, 0); + let (url, rpc, _) = rpc_for_channel(account, 43).await; + let mut cfg = cfg; + cfg.rpc_url = Some(url); + let server = seeded_server(cfg, bound).await; + let payload = UsePayload { + channel_id: channel_id.clone(), + authentication: proof, + }; + let error = server + .process_use(&payload, "use-1", "request-1") + .await + .unwrap_err(); + assert!(error.to_string().contains("closing onchain"), "{error}"); + assert!(server + .authenticate_use(&payload, "use-2", "request-2") + .await + .is_err()); + let after = stored(&server, &channel_id).await; + assert_eq!(after.cumulative, 0); + assert!(after.close_requested_at.is_some()); + rpc.abort(); + } + + #[test] + fn admission_requires_a_snapshot_inside_the_window() { + let fresh = state(Pubkey::new_unique().to_string(), signer_address(1)); + assert!(require_fresh_snapshot(&fresh, 30).is_ok()); + assert!(require_fresh_snapshot(&stale(fresh), 30).is_err()); + } + + #[test] + fn channel_status_maps_to_the_observed_lifecycle() { + assert_eq!( + ObservedLifecycle::of_channel(0, 0, 9), + ObservedLifecycle::Open + ); + assert_eq!( + ObservedLifecycle::of_channel(2, 5, 9), + ObservedLifecycle::Closing { started_at: 5 } + ); + assert_eq!( + ObservedLifecycle::of_channel(1, 0, 9), + ObservedLifecycle::Terminal { + started_at: Some(1) + } + ); + assert_eq!( + ObservedLifecycle::of_channel(3, 0, 9), + ObservedLifecycle::Terminal { + started_at: Some(1) + } + ); + } + + #[tokio::test] + async fn idle_close_comes_before_the_settled_voucher_expires() { + let (mut server, mut session, channel_id) = client_server().await; + server.config.grace_period_seconds = 900; + server + .store + .mutate_channel( + &channel_id, + None, + Box::new(|state| { + state.idle_timeout_seconds = Some(3_600); + Ok(()) + }), + ) + .await + .unwrap(); + // Outlasts the grace period, so it is accepted, but expires long + // before the one-hour idle timeout would close the channel. + let expires_at = now_unix_secs() + 960; + session.set_expires_at(expires_at); + let voucher = session.sign_increment(100).await.unwrap(); + server + .verify_voucher(&voucher_payload(voucher)) + .await + .unwrap(); + let close_after = stored(&server, &channel_id) + .await + .lifecycle + .unwrap() + .close_after; + assert_eq!(close_after, (expires_at as u64 - 900) * 1_000); + + let directive = server + .begin_delivery(DeliveryRequest::new(channel_id.clone(), 10)) + .await + .unwrap(); + session.set_expires_at(expires_at + 30); + let payload = CommitPayload { + delivery_id: directive.delivery_id, + voucher: session.sign_increment(10).await.unwrap(), + }; + server.process_commit(&payload).await.unwrap(); + let close_after = stored(&server, &channel_id) + .await + .lifecycle + .unwrap() + .close_after; + assert_eq!(close_after, (expires_at as u64 + 30 - 900) * 1_000); + } + + #[tokio::test] + async fn a_never_expiring_voucher_keeps_the_idle_timeout() { + let (server, mut session, channel_id) = client_server().await; + session.set_expires_at(0); + let voucher = session.sign_increment(100).await.unwrap(); + let before = now_unix_secs() as u64 * 1_000; + server + .verify_voucher(&voucher_payload(voucher)) + .await + .unwrap(); + let after = stored(&server, &channel_id).await; + let close_after = after.lifecycle.unwrap().close_after; + // `state` negotiates a 60-second idle timeout. + assert!(close_after >= before + 60_000); + assert!(close_after <= after.last_activity_at + 60_000); + } + #[tokio::test] async fn deliveries_commit_partially_and_are_idempotent() { let (server, mut session, channel_id) = client_server().await; @@ -7649,6 +8698,67 @@ mod tests { (server, payload, memory_signer(9)) } + #[tokio::test] + async fn operator_use_bounds_the_idempotency_key() { + let (server, payload, _) = operator_channel().await; + let too_long = "k".repeat(MAX_IDEMPOTENCY_KEY_BYTES + 1); + let error = server + .process_use(&payload, "use-1", &too_long) + .await + .unwrap_err(); + assert!(error.to_string().contains("exceeds"), "{error}"); + assert!(server + .authenticate_use(&payload, "use-1", &too_long) + .await + .is_err()); + assert!(stored(&server, &payload.channel_id) + .await + .processed_uses + .is_empty()); + + let longest = "k".repeat(MAX_IDEMPOTENCY_KEY_BYTES); + assert!(server + .process_use(&payload, "use-1", &longest) + .await + .is_ok()); + assert!(server + .authenticate_use(&payload, "use-2", &longest) + .await + .is_ok()); + } + + #[tokio::test] + async fn committed_deliveries_keep_a_bounded_replay_window() { + let (server, mut session, channel_id) = client_server().await; + let commits = MAX_COMMITTED_AUTHORIZATIONS + 2; + let mut first = None; + for _ in 0..commits { + let directive = server + .begin_delivery(DeliveryRequest::new(channel_id.clone(), 1)) + .await + .unwrap(); + let payload = CommitPayload { + delivery_id: directive.delivery_id, + voucher: session.sign_increment(1).await.unwrap(), + }; + server.process_commit(&payload).await.unwrap(); + first.get_or_insert(payload); + } + let after = stored(&server, &channel_id).await; + assert_eq!(after.cumulative, commits as u64); + assert_eq!( + after.committed_deliveries.len(), + MAX_COMMITTED_AUTHORIZATIONS + ); + + // An evicted commit is refused, never charged again. + assert!(server.process_commit(&first.unwrap()).await.is_err()); + assert_eq!( + stored(&server, &channel_id).await.cumulative, + commits as u64 + ); + } + fn memory_signer(seed: u8) -> MemorySigner { let key = key(seed); let mut bytes = [0_u8; 64]; @@ -7817,6 +8927,34 @@ mod tests { assert_eq!(record.spent_amount, 21); } + /// A stream charges one authenticated request again and again, so every + /// charge, not only the authentication, needs a fresh channel read. + #[tokio::test] + async fn every_operator_charge_needs_a_fresh_channel_read() { + let (server, payload, operator) = operator_channel().await; + let request = authenticate(&server, &payload, "request-1").await; + let first = server + .charge_operator_request(&request, &operator, 7, |_| Ok(())) + .await + .unwrap(); + assert_eq!(first.cumulative, 7); + + server + .store + .update_channel( + &payload.channel_id, + Box::new(|state| Ok(stale(state.unwrap()))), + ) + .await + .unwrap(); + let error = server + .charge_operator_request(&request, &operator, 20, |_| Ok(())) + .await + .unwrap_err(); + assert!(error.to_string().contains("onchain"), "{error}"); + assert_eq!(stored(&server, &payload.channel_id).await.cumulative, 7); + } + async fn authenticate( server: &SessionServer, payload: &UsePayload, @@ -8234,8 +9372,21 @@ mod tests { assert_eq!(params.rent_payer, Some(client_payer)); let treasury = Pubkey::new_unique(); let token_program = Pubkey::from_str(programs::TOKEN_PROGRAM).unwrap(); + let clearance = match params + .payer_refund( + &sealed_channel_account(¶ms, params.settled), + &token_program, + None, + None, + now_unix_secs(), + ) + .unwrap() + { + crate::core::payment_channel::payer_refund::PayerRefund::Clear(clearance) => clearance, + blocked => panic!("{blocked:?}"), + }; let ix = params - .distribute_instruction(&treasury, &token_program) + .distribute_instruction(&treasury, &token_program, &clearance) .unwrap(); // Accounts: channel, payer, rent_payer, … assert_eq!(ix.accounts[2].pubkey, client_payer); @@ -8244,12 +9395,225 @@ mod tests { let mut missing = params; missing.rent_payer = None; assert!(missing - .distribute_instruction(&treasury, &token_program) + .distribute_instruction(&treasury, &token_program, &clearance) .unwrap_err() .to_string() .contains("rent payer")); } + /// The on-chain account of a channel closed by `params` whose deposit is + /// `deposit`. + fn sealed_channel_account(params: &SealParams, deposit: u64) -> Vec { + channel_account_at(params, deposit, 0, 0) + } + + /// The channel account for `params` at onchain `status` and `settled`. + fn channel_account_at(params: &SealParams, deposit: u64, status: u8, settled: u64) -> Vec { + use payment_channels::generated::generated::types::SettlementWatermarks; + borsh::to_vec(&payment_channels::generated::generated::accounts::Channel { + discriminator: 1, + version: 1, + bump: 1, + status, + salt: 7, + deposit, + settlement: SettlementWatermarks { + settled, + payout_watermark: 0, + }, + closure_started_at: 0, + payer_withdrawn_at: 0, + grace_period: 900, + distribution_hash: [0; 32], + payer: payment_channels::to_address(¶ms.payer.unwrap()), + payee: payment_channels::to_address(¶ms.recipient), + authorized_signer: payment_channels::to_address(¶ms.authorized_signer.unwrap()), + mint: payment_channels::to_address(¶ms.mint.unwrap()), + rent_payer: payment_channels::to_address(¶ms.rent_payer.unwrap()), + open_slot: 42, + }) + .unwrap() + } + + /// A channel the payer already sealed onchain below the stored watermark + /// refunds `deposit - onchain settled`: the stored cumulative never lands, + /// so it must not hide a due refund behind a missing account. + #[tokio::test] + async fn an_already_sealed_channel_refunds_from_its_onchain_watermark() { + use crate::core::payment_channel::payer_refund::PayerRefund; + + let (server, mut session, channel_id) = client_server().await; + let params = server + .process_close(&ClosePayload { + channel_id, + authentication: None, + voucher: Some(session.sign_increment(100).await.unwrap()), + }) + .await + .unwrap(); + assert_eq!(params.settled, 100); + let token_program = Pubkey::from_str(programs::TOKEN_PROGRAM).unwrap(); + let sealed = payment_channels::generated::generated::types::ChannelStatus::Sealed as u8; + // Sealed by the payer at 0 of a 100 deposit: all 100 is due back. + let outcome = params + .payer_refund( + &channel_account_at(¶ms, 100, sealed, 0), + &token_program, + None, + None, + now_unix_secs(), + ) + .unwrap(); + assert!( + matches!(outcome, PayerRefund::Deferred { refund: 100, .. }), + "{outcome:?}" + ); + // Positive control: an open channel this close seals at 100 owes + // nothing back, so no account is needed. + let outcome = params + .payer_refund( + &channel_account_at(¶ms, 100, 0, 0), + &token_program, + None, + None, + now_unix_secs(), + ) + .unwrap(); + assert!(matches!(outcome, PayerRefund::Clear(_)), "{outcome:?}"); + } + + // The program forfeits a due refund to the treasury when the payer's + // token account cannot take it, so a close leaves the sealed distribute + // unbuilt until the payer can be paid. + #[tokio::test] + async fn sealed_distribute_needs_a_payable_refund_account() { + use crate::core::payment_channel::payer_refund::{ObservedAccount, PayerRefund}; + + let (server, mut session, channel_id) = client_server().await; + let params = server + .process_close(&ClosePayload { + channel_id, + authentication: None, + voucher: Some(session.sign_increment(100).await.unwrap()), + }) + .await + .unwrap(); + let token_program = Pubkey::from_str(programs::TOKEN_PROGRAM).unwrap(); + // 900 of a 1_000 deposit is due back to the payer. + let channel = sealed_channel_account(¶ms, 1_000); + let refund_account = params.payer_refund_account(&token_program).unwrap(); + let mut live = vec![0u8; 165]; + live[..32].copy_from_slice(params.mint.unwrap().as_ref()); + live[32..64].copy_from_slice(params.payer.unwrap().as_ref()); + live[108] = 1; + let mut frozen = live.clone(); + frozen[108] = 2; + + for missing_or_frozen in [None, Some(frozen.as_slice())] { + let outcome = params + .payer_refund( + &channel, + &token_program, + missing_or_frozen.map(|data| ObservedAccount { + owner: token_program, + data, + }), + None, + now_unix_secs(), + ) + .unwrap(); + assert!( + matches!( + &outcome, + PayerRefund::Deferred { refund: 900, payer_token_account, until, .. } + if *payer_token_account == refund_account + && *until >= now_unix_secs() + 899 + ), + "{outcome:?}" + ); + } + + let PayerRefund::Clear(clearance) = params + .payer_refund( + &channel, + &token_program, + Some(ObservedAccount { + owner: token_program, + data: &live, + }), + None, + now_unix_secs(), + ) + .unwrap() + else { + panic!("a live refund account must clear the distribute"); + }; + params + .distribute_instruction(&Pubkey::new_unique(), &token_program, &clearance) + .unwrap(); + + // A clearance is bound to its channel. + let mut other = params.clone(); + other.channel_id = Pubkey::new_unique(); + assert!(other + .distribute_instruction(&Pubkey::new_unique(), &token_program, &clearance) + .unwrap_err() + .to_string() + .contains("another channel")); + } + + /// A deferred distribute is retried by the host and runs anyway once the + /// channel has been sealed for its grace period, so a payer keeping its + /// refund account unusable cannot hold the payout. The seal time is the + /// one `mark_sealed` recorded first. + #[tokio::test] + async fn a_deferred_distribute_runs_once_the_grace_period_after_the_seal_ends() { + use crate::core::payment_channel::payer_refund::PayerRefund; + + let (server, mut session, channel_id) = client_server().await; + let params = server + .process_close(&ClosePayload { + channel_id: channel_id.clone(), + authentication: None, + voucher: Some(session.sign_increment(100).await.unwrap()), + }) + .await + .unwrap(); + assert_eq!(server.sealed_at(&channel_id).await.unwrap(), None); + server.mark_sealed(&channel_id).await.unwrap(); + let sealed_at = server.sealed_at(&channel_id).await.unwrap().unwrap(); + assert!(now_unix_secs() - sealed_at <= 1); + // A later mark keeps the first seal time. + server.mark_sealed(&channel_id).await.unwrap(); + assert_eq!( + server.sealed_at(&channel_id).await.unwrap(), + Some(sealed_at) + ); + + let token_program = Pubkey::from_str(programs::TOKEN_PROGRAM).unwrap(); + let sealed = payment_channels::generated::generated::types::ChannelStatus::Sealed as u8; + // Sealed at 100 of a 1_000 deposit with no refund account (grace 900). + let channel = channel_account_at(¶ms, 1_000, sealed, 100); + let at = |now: i64| { + params + .payer_refund(&channel, &token_program, None, Some(sealed_at), now) + .unwrap() + }; + assert!( + matches!(at(sealed_at + 899), PayerRefund::Deferred { until, .. } if until == sealed_at + 900) + ); + let PayerRefund::Forfeit { + clearance, refund, .. + } = at(sealed_at + 900) + else { + panic!("the deferral ends at the deadline"); + }; + assert_eq!(refund, 900); + params + .distribute_instruction(&Pubkey::new_unique(), &token_program, &clearance) + .unwrap(); + } + #[tokio::test] async fn client_close_seal_and_store_lifecycle_are_consistent() { let (server, mut session, channel_id) = client_server().await; diff --git a/rust/crates/kit/src/mpp/server/session_refund.rs b/rust/crates/kit/src/mpp/server/session_refund.rs new file mode 100644 index 000000000..61780b0df --- /dev/null +++ b/rust/crates/kit/src/mpp/server/session_refund.rs @@ -0,0 +1,103 @@ +//! The payer-refund check a sealed session `distribute` requires. + +use solana_pubkey::Pubkey; + +use super::session::SealParams; +use crate::core::payment_channel::payer_refund::{ + payer_refund, ObservedAccount, PayerRefund, RefundDeadline, SealedRefundTerms, +}; +use crate::mpp::error::{Error, Result}; + +impl SealParams { + /// The account [`Self::payer_refund`] needs fetched next to the channel: + /// the payer's refund token account. + pub fn payer_refund_account(&self, token_program: &Pubkey) -> Result { + Ok(self + .refund_terms(token_program, 0, 0)? + .payer_token_account()) + } + + /// What the sealed `distribute` may do at `now` (unix seconds), from the + /// fetched channel account and the account at + /// [`Self::payer_refund_account`] (`None` when it does not exist). + /// + /// `sealed_at` is when the channel was sealed, as recorded by + /// [`SessionServer::mark_sealed`](super::session::SessionServer::mark_sealed) + /// and read back with + /// [`SessionServer::sealed_at`](super::session::SessionServer::sealed_at); + /// it is ignored for a channel this close seals, and `None` for an + /// already-sealed one starts the deadline at `now`. + /// + /// [`PayerRefund::Clear`] and [`PayerRefund::Forfeit`] carry the + /// clearance [`Self::distribute_instruction`] takes. On + /// [`PayerRefund::Deferred`] land only the settle-and-seal and retry the + /// distribute by `until`: the program would forfeit the refund to the + /// treasury, while the payer can still repair its account or + /// `withdraw_payer`. From `until` on the distribute runs anyway + /// ([`PayerRefund::Forfeit`]), so the payout is never held hostage. + pub fn payer_refund( + &self, + channel_account: &[u8], + token_program: &Pubkey, + payer_token_account: Option>, + sealed_at: Option, + now: i64, + ) -> Result { + let deployment = crate::mpp::program::channel_deployment::resolve( + self.program_id, + self.channel_version, + self.channel_hooks.as_ref(), + )?; + let channel = deployment.decode_channel(channel_account)?.channel; + let terms = + self.refund_terms(token_program, channel.deposit, channel.payer_withdrawn_at)?; + let sealed = channel.status + == crate::generated::payment_channels::generated::types::ChannelStatus::Sealed as u8; + let terms = SealedRefundTerms { + // An already-sealed channel refunds from its onchain watermark; + // otherwise the seal this close lands commits at least the one it + // settles. + settled: if sealed { + channel.settlement.settled + } else { + channel.settlement.settled.max(self.settled) + }, + ..terms + }; + if crate::core::payment_channels::from_address(&channel.payer) != terms.payer { + return Err(Error::Other( + "channel account payer does not match the seal parameters".into(), + )); + } + let deadline = RefundDeadline { + sealed_at: if sealed { + sealed_at.unwrap_or(now) + } else { + now + }, + grace_period: channel.grace_period, + }; + Ok(payer_refund(&terms, payer_token_account, deadline, now)) + } + + fn refund_terms( + &self, + token_program: &Pubkey, + deposit: u64, + payer_withdrawn_at: i64, + ) -> Result { + Ok(SealedRefundTerms { + channel: self.channel_id, + payer: self + .payer + .ok_or_else(|| Error::Other("distribution missing payer".into()))?, + mint: self + .mint + .ok_or_else(|| Error::Other("distribution missing mint".into()))?, + token_program: *token_program, + deposit, + settled: self.settled, + payer_withdrawn_at, + }) + } +} diff --git a/rust/crates/kit/src/x402/client/batch_settlement/payment.rs b/rust/crates/kit/src/x402/client/batch_settlement/payment.rs index 77699a233..af6842415 100644 --- a/rust/crates/kit/src/x402/client/batch_settlement/payment.rs +++ b/rust/crates/kit/src/x402/client/batch_settlement/payment.rs @@ -1361,6 +1361,8 @@ mod tests { voucher_signer: None, operator: None, max_idle_secs: None, + max_claim_channels: None, + max_settle_channels: None, }, } } diff --git a/rust/crates/kit/src/x402/client/exact/payment.rs b/rust/crates/kit/src/x402/client/exact/payment.rs index 9f7f13a64..6011aae1a 100644 --- a/rust/crates/kit/src/x402/client/exact/payment.rs +++ b/rust/crates/kit/src/x402/client/exact/payment.rs @@ -18,6 +18,10 @@ use crate::x402::{ X402_VERSION_V2, }; +/// Loaded-account-data budget an x402 `exact` client sets on a version-1 +/// payment, matching the TypeScript, Go and Python reference clients. +pub const X402_LOADED_ACCOUNTS_DATA_SIZE_LIMIT: u32 = 4 * 1024 * 1024; + /// Build a payment transaction from x402 payment requirements. /// /// Returns a `PaymentPayload` ready to be wrapped in `PAYMENT-SIGNATURE`. @@ -59,7 +63,13 @@ pub async fn build_payment( // Compute budget. Canonical SVM exact validates these by index; on version // 0 they are the first two instructions, on version 1 the header config. - let budget = crate::core::tx::ComputeBudget::new(20_000, 1); + // Version 1 also carries a loaded-account-data budget (§1.5: it MUST be + // set); the reference x402 clients request 4 MiB, which covers the mainnet + // Token-2022 program data (about 1.4 MiB) and the rest of a payment. + let budget = crate::core::tx::ComputeBudget { + loaded_accounts_data_size_limit: X402_LOADED_ACCOUNTS_DATA_SIZE_LIMIT, + ..crate::core::tx::ComputeBudget::new(20_000, 1) + }; let cluster = signing_cluster(requirements)?; let mint = try_resolve_mint(&requirements.currency, Some(cluster))?; diff --git a/rust/crates/kit/src/x402/client/upto/payment.rs b/rust/crates/kit/src/x402/client/upto/payment.rs index 27b6ae765..3437e36b4 100644 --- a/rust/crates/kit/src/x402/client/upto/payment.rs +++ b/rust/crates/kit/src/x402/client/upto/payment.rs @@ -14,7 +14,7 @@ use solana_keychain::TransactionSigner; use solana_pubkey::Pubkey; use solana_rpc_client::rpc_client::RpcClient; -use crate::core::blockhash::fetch_blockhash_with_slot; +use crate::core::blockhash::CachedBlockhash; use crate::core::payment_channels as pc; use crate::x402::error::Error; @@ -37,7 +37,10 @@ use crate::x402::{PAYMENT_REQUIRED_HEADER, X402_VERSION_V2}; /// the program's `openSlot`, a channel-PDA seed the program only accepts /// within a recent window. Both hints are optional per the upto spec — when /// either is absent, a single `getLatestBlockhash` call against `rpc` -/// supplies the missing value(s); `rpc` is untouched when both are present. +/// supplies the missing value(s). A `recentBlockhash` hint is signed only +/// once `rpc`, which serves the cluster the client pays on, confirms it is +/// live there: a hash from another cluster would open the channel on that +/// cluster instead. pub async fn build_upto_payload( payer_signer: &dyn TransactionSigner, rpc: &RpcClient, @@ -81,19 +84,21 @@ pub async fn build_upto_payload( // absent — its response context carries the current slot, covering both. let hint_blockhash = requirements.extra.recent_blockhash.as_deref(); let hint_slot = requirements.extra.recent_slot.map(Slot::get); - let (blockhash_str, open_slot) = match (hint_blockhash, hint_slot) { - (Some(blockhash), Some(slot)) => (blockhash.to_string(), slot), - _ => { - let fetched = fetch_blockhash_with_slot(rpc, rpc.commitment()).map_err(Error::Rpc)?; - let blockhash = hint_blockhash - .map(str::to_string) - .unwrap_or(fetched.blockhash); - let open_slot = hint_slot.unwrap_or(fetched.slot); - (blockhash, open_slot) - } + let fetched = match (hint_blockhash, hint_slot) { + (Some(_), Some(_)) => None, + _ => Some(fetch_blockhash_with_slot(rpc).await?), + }; + let blockhash = match (hint_blockhash, &fetched) { + (Some(hint), _) => verified_hint(rpc, hint).await?, + (None, Some(fetched)) => Hash::from_str(&fetched.blockhash) + .map_err(|e| Error::Other(format!("invalid recentBlockhash: {e}")))?, + (None, None) => unreachable!("a missing blockhash hint fetches one"), + }; + let open_slot = match (hint_slot, &fetched) { + (Some(slot), _) => slot, + (None, Some(fetched)) => fetched.slot, + (None, None) => unreachable!("a missing slot hint fetches one"), }; - let blockhash = Hash::from_str(&blockhash_str) - .map_err(|e| Error::Other(format!("invalid recentBlockhash: {e}")))?; let salt = salt_for_nonce(&nonce); // “Clients MUST include a Memo instruction containing either the value @@ -146,6 +151,48 @@ pub async fn build_upto_payload( }) } +/// The latest blockhash and the slot it was observed at, in one +/// `getLatestBlockhash` call (its response context carries the slot). +async fn fetch_blockhash_with_slot(rpc: &RpcClient) -> Result { + use solana_rpc_client_api::{ + config::RpcContextConfig, + request::RpcRequest, + response::{Response, RpcBlockhash}, + }; + // Every call goes through the nonblocking client: mixing it with the + // blocking one shares a connection pool across runtimes and can stall. + let response: Response = rpc + .get_inner_client() + .send( + RpcRequest::GetLatestBlockhash, + serde_json::json!([RpcContextConfig { + commitment: Some(rpc.commitment()), + min_context_slot: None, + }]), + ) + .await + .map_err(|e| Error::Rpc(e.to_string()))?; + Ok(CachedBlockhash { + blockhash: response.value.blockhash, + last_valid_block_height: response.value.last_valid_block_height, + slot: response.context.slot, + }) +} + +/// The requirement's `recentBlockhash`, once the client's cluster knows it. +async fn verified_hint(rpc: &RpcClient, hint: &str) -> Result { + // Only the nonblocking client is reachable here: a blocking call panics + // on a current-thread runtime. + crate::core::blockhash::resolve_challenge_blockhash(rpc.get_inner_client(), Some(hint)) + .await + .map_err(|e| match e { + crate::core::blockhash::ChallengeBlockhashError::Invalid(message) => { + Error::Other(format!("invalid extra.recentBlockhash: {message}")) + } + crate::core::blockhash::ChallengeBlockhashError::Rpc(message) => Error::Rpc(message), + }) +} + /// The channel salt for a request `nonce`: derived from it, or random when the /// caller supplied none. fn salt_for_nonce(nonce: &str) -> u64 { @@ -348,12 +395,26 @@ mod tests { assert!(parse_upto_challenge(&[], None).is_none()); } + /// An RPC that knows every blockhash and serves `succeeds` otherwise. + fn live_rpc() -> RpcClient { + use solana_rpc_client::mock_sender::MocksMap; + use solana_rpc_client_api::request::RpcRequest; + let mut mocks = MocksMap::default(); + for _ in 0..8 { + mocks.insert( + RpcRequest::IsBlockhashValid, + serde_json::json!({ "context": { "slot": 1 }, "value": true }), + ); + } + RpcClient::new_mock_with_mocks_map("succeeds", mocks) + } + #[tokio::test(flavor = "multi_thread")] async fn build_payload_uses_challenge_hints_without_rpc() { let signer = make_signer(); - // A "fails" mock makes any RPC hit error loudly: with both hints - // embedded, the build must succeed without touching RPC at all. - let rpc = RpcClient::new_mock("fails".to_string()); + // Every other RPC method errors loudly: with both hints embedded, the + // build only asks whether the hinted blockhash is live. + let rpc = crate::core::blockhash::mock_blockhash_rpc(true); let payload = build_upto_payload(&*signer, &rpc, &requirements(), 4_102_444_800, "n-1", None) .await @@ -367,7 +428,7 @@ mod tests { #[tokio::test(flavor = "multi_thread")] async fn the_request_nonce_pins_the_channel() { let signer = make_signer(); - let rpc = RpcClient::new_mock("fails".to_string()); + let rpc = crate::core::blockhash::mock_blockhash_rpc(true); let build = |nonce: &'static str| { let signer = &signer; let rpc = &rpc; @@ -407,7 +468,7 @@ mod tests { #[tokio::test(flavor = "multi_thread")] async fn build_payload_fetches_missing_slot_keeping_hinted_blockhash() { let signer = make_signer(); - let rpc = RpcClient::new_mock("succeeds".to_string()); + let rpc = live_rpc(); let mut req = requirements(); req.extra.recent_slot = None; let payload = build_upto_payload(&*signer, &rpc, &req, 4_102_444_800, "n-1", None) @@ -421,7 +482,7 @@ mod tests { // A seller that declares extra.memo requires exactly one matching Memo // after open, so the client emits it. let signer = make_signer(); - let rpc = RpcClient::new_mock("fails".to_string()); + let rpc = crate::core::blockhash::mock_blockhash_rpc(true); let mut req = requirements(); req.extra.memo = Some("order-4711".to_string()); let payload = build_upto_payload(&*signer, &rpc, &req, 4_102_444_800, "n-1", None) @@ -480,6 +541,39 @@ mod tests { ); } + /// The hinted blockhash is the only thing binding the open to a + /// cluster, so one the client's own cluster does not know is refused, + /// with or without a slot hint. + #[tokio::test(flavor = "multi_thread")] + async fn a_hinted_blockhash_the_client_cluster_does_not_know_is_refused() { + let signer = make_signer(); + let foreign = crate::core::blockhash::mock_blockhash_rpc(false); + let err = build_upto_payload( + &*signer, + &foreign, + &requirements(), + 4_102_444_800, + "n", + None, + ) + .await + .expect_err("a foreign blockhash is refused"); + assert!(err.to_string().contains("not a live blockhash"), "{err}"); + + let mut without_slot = requirements(); + without_slot.extra.recent_slot = None; + let mut mocks = solana_rpc_client::mock_sender::MocksMap::default(); + mocks.insert( + solana_rpc_client_api::request::RpcRequest::IsBlockhashValid, + serde_json::json!({ "context": { "slot": 1 }, "value": false }), + ); + let foreign = RpcClient::new_mock_with_mocks_map("succeeds", mocks); + let err = build_upto_payload(&*signer, &foreign, &without_slot, 4_102_444_800, "n", None) + .await + .expect_err("a foreign blockhash is refused when the slot is fetched"); + assert!(err.to_string().contains("not a live blockhash"), "{err}"); + } + #[tokio::test(flavor = "multi_thread")] async fn build_payload_errors_when_hints_absent_and_rpc_unavailable() { let signer = make_signer(); diff --git a/rust/crates/kit/src/x402/protocol/schemes/batch_settlement/errors.rs b/rust/crates/kit/src/x402/protocol/schemes/batch_settlement/errors.rs index 7d1e3a863..709374f43 100644 --- a/rust/crates/kit/src/x402/protocol/schemes/batch_settlement/errors.rs +++ b/rust/crates/kit/src/x402/protocol/schemes/batch_settlement/errors.rs @@ -195,15 +195,31 @@ impl From for crate::x402::error::Error { /// /// The server composes checks that return the crate-wide [`crate::x402::error::Error`], /// which erases the code into a string; this maps it back for the wire without -/// forcing every intermediate helper to thread a typed error. +/// forcing every intermediate helper to thread a typed error. The code a +/// [`BatchError`] leads with wins: its detail may quote client-supplied +/// text, which must not be able to name a different code. pub fn classify(message: &str) -> &'static str { - ALL_CODES - .iter() - .find(|code| message.contains(*code)) - .copied() + leading_code(message) + .or_else(|| { + ALL_CODES + .iter() + .find(|code| message.contains(*code)) + .copied() + }) .unwrap_or("transaction_failed") } +/// The code a [`BatchError`] message leads with (`": "`), if +/// it leads with one. Unlike [`classify`] it never searches the detail, so +/// a decision taken on it cannot be steered by text a client supplied. +pub fn leading_code(message: &str) -> Option<&'static str> { + ALL_CODES.iter().copied().find(|code| { + message + .strip_prefix(code) + .is_some_and(|rest| rest.starts_with(": ")) + }) +} + #[cfg(test)] mod tests { use super::*; @@ -232,4 +248,27 @@ mod tests { assert!(err.to_string().contains("expiresAt was 42")); assert_eq!(classify("something else entirely"), "transaction_failed"); } + + #[test] + fn a_quoted_code_in_the_detail_does_not_override_the_raised_code() { + let err = BatchError::new( + INVALID_CHANNEL_STATE, + format!("channelConfig.receiver {INVALID_CUMULATIVE_AMOUNT_MISMATCH} does not match"), + ); + assert_eq!(classify(&err.to_string()), INVALID_CHANNEL_STATE); + assert_eq!(leading_code(&err.to_string()), Some(INVALID_CHANNEL_STATE)); + // Positive control: the mismatch itself is still recognised. + let err = BatchError::new(INVALID_CUMULATIVE_AMOUNT_MISMATCH, "voucher authorizes 5"); + assert_eq!( + leading_code(&err.to_string()), + Some(INVALID_CUMULATIVE_AMOUNT_MISMATCH) + ); + // A message that only quotes a code leads with none. + assert_eq!( + leading_code(&format!( + "store error: {INVALID_CUMULATIVE_AMOUNT_MISMATCH}: x" + )), + None + ); + } } diff --git a/rust/crates/kit/src/x402/protocol/schemes/batch_settlement/mod.rs b/rust/crates/kit/src/x402/protocol/schemes/batch_settlement/mod.rs index 4363f87a0..d5003d718 100644 --- a/rust/crates/kit/src/x402/protocol/schemes/batch_settlement/mod.rs +++ b/rust/crates/kit/src/x402/protocol/schemes/batch_settlement/mod.rs @@ -7,7 +7,7 @@ mod tx_policy; mod types; mod verify; -pub use errors::{classify, BatchError}; +pub use errors::{classify, leading_code, BatchError}; pub use tx_policy::*; pub use types::*; pub use verify::*; diff --git a/rust/crates/kit/src/x402/protocol/schemes/batch_settlement/tx_policy.rs b/rust/crates/kit/src/x402/protocol/schemes/batch_settlement/tx_policy.rs index 877e94ed4..ea30630d3 100644 --- a/rust/crates/kit/src/x402/protocol/schemes/batch_settlement/tx_policy.rs +++ b/rust/crates/kit/src/x402/protocol/schemes/batch_settlement/tx_policy.rs @@ -338,6 +338,8 @@ fn check_envelope( crate::core::tx::LoadedDataLimitRule::Present, ) .map_err(|e| err(format!("{label} transaction: {e}")))?; + crate::core::tx::reject_v1_heap_request(&tx.message) + .map_err(|e| err(format!("{label} transaction: {e}")))?; let payer = pc::parse_pubkey(&expected.config.payer) .map_err(|e| err(format!("channelConfig.payer: {e}")))?; @@ -1062,6 +1064,16 @@ mod tests { } } + fn cu_price_ix(micro_lamports: u64) -> Instruction { + let mut data = vec![pc::COMPUTE_BUDGET_SET_UNIT_PRICE]; + data.extend_from_slice(µ_lamports.to_le_bytes()); + Instruction { + program_id: pc::to_address(&pc::compute_budget_program_id()), + accounts: vec![], + data, + } + } + #[test] fn accepts_a_canonical_open() { let f = fixture(); @@ -1082,6 +1094,79 @@ mod tests { assert_eq!(validated.payer, f.payer); } + #[test] + fn the_sponsor_bounds_the_priority_fee_it_pays() { + use crate::core::tx::{ComputeBudget, MAX_SPONSORED_PRIORITY_FEE_LAMPORTS}; + let f = fixture(); + let open = || pc::build_open_instruction(&f.open_params(100_000)); + let setup = |tx: &str| { + validate_setup_transaction( + tx, + SetupForm::Open, + &f.expectations(), + 100_000, + Some(341_000_100), + ) + }; + let over_fee_cap = |err: BatchError| { + assert_eq!(err.code, errors::INVALID_SETUP_TRANSACTION); + assert!( + err.detail.contains("exceeds the sponsored fee maximum"), + "{}", + err.detail + ); + }; + let at_cap = MAX_SPONSORED_PRIORITY_FEE_LAMPORTS * 1_000_000 + / u64::from(pc::OPEN_MAX_COMPUTE_UNIT_LIMIT); + + // Each field at its own ceiling. + over_fee_cap( + setup(&f.sign(&[ + cu_limit_ix(pc::OPEN_MAX_COMPUTE_UNIT_LIMIT), + cu_price_ix(pc::MAX_COMPUTE_UNIT_PRICE_MICROLAMPORTS), + open(), + nonce_memo(), + f.binding(), + ])) + .unwrap_err(), + ); + assert!(setup(&f.sign(&[ + cu_limit_ix(pc::OPEN_MAX_COMPUTE_UNIT_LIMIT), + cu_price_ix(at_cap), + open(), + nonce_memo(), + f.binding(), + ])) + .is_ok()); + // No declared limit: three instructions are budgeted 600,000 units. + over_fee_cap( + setup(&f.sign(&[cu_price_ix(at_cap), open(), nonce_memo(), f.binding()])).unwrap_err(), + ); + // Version 1 carries the fee itself in the header. + let ixs = [open(), nonce_memo(), f.binding()]; + assert!(setup(&f.sign_v1(&ixs, ComputeBudget::new(200_000, 10_000))).is_ok()); + over_fee_cap(setup(&f.sign_v1(&ixs, ComputeBudget::new(200_000, 10_005))).unwrap_err()); + + // The refund `request_close` is co-signed under the same policy. + let close = pc::build_request_close_instruction(&f.payer, &f.channel_id, &f.program_id); + let err = validate_request_close_transaction( + &f.sign(&[ + cu_limit_ix(pc::OPEN_MAX_COMPUTE_UNIT_LIMIT), + cu_price_ix(pc::MAX_COMPUTE_UNIT_PRICE_MICROLAMPORTS), + close.clone(), + nonce_memo(), + ]), + &f.expectations(), + ) + .unwrap_err(); + assert_eq!(err.code, errors::INVALID_REFUND_TRANSACTION); + assert!(validate_request_close_transaction( + &f.sign(&[cu_price_ix(at_cap), close, nonce_memo()]), + &f.expectations(), + ) + .is_ok()); + } + #[test] fn open_requires_a_memo_the_sponsor_can_correlate() { let f = fixture(); diff --git a/rust/crates/kit/src/x402/protocol/schemes/batch_settlement/types.rs b/rust/crates/kit/src/x402/protocol/schemes/batch_settlement/types.rs index f274addcf..7f9679382 100644 --- a/rust/crates/kit/src/x402/protocol/schemes/batch_settlement/types.rs +++ b/rust/crates/kit/src/x402/protocol/schemes/batch_settlement/types.rs @@ -33,10 +33,21 @@ pub const MIN_WITHDRAW_DELAY_SECONDS: u32 = 900; /// Maximum forced-close grace period (30 days). pub const MAX_WITHDRAW_DELAY_SECONDS: u32 = 2_592_000; -/// Maximum voucher claims in one `claim` batch, so the Ed25519-precompile plus -/// `settle` instruction pairs fit a legacy transaction without lookup tables. +/// Channels per `claim` or `settle` request when the facilitator advertises +/// no capacity, and the most a legacy or version-0 redemption carries: four +/// Ed25519-precompile plus `settle` pairs fit a legacy transaction. pub const MAX_CLAIMS_PER_BATCH: usize = 4; +/// Ed25519+`settle` pairs that fit one version-1 redemption (size-bound), the +/// most `claims[]` entries any facilitator may advertise as `maxClaimChannels`. +pub const V1_MAX_CLAIM_CHANNELS: usize = 18; + +/// `distribute` instructions advertised per version-1 redemption, the most +/// `channels[]` entries any facilitator may advertise as `maxSettleChannels`. +/// Bound by the 64 static account keys: 14 fit when every channel pays the +/// route's `payTo`, so 13 leaves a channel of margin. +pub const V1_MAX_SETTLE_CHANNELS: usize = 13; + /// The only voucher expiry this scheme permits. /// /// The forced-close grace period after a payer `request_close` already bounds @@ -160,6 +171,18 @@ pub struct BatchExtra { #[serde(default, skip_serializing_if = "Option::is_none")] pub max_idle_secs: Option, + /// Most `claims[]` entries the facilitator redeems in one `claim` + /// transaction, copied from its `/supported` extra. Absent means + /// [`MAX_CLAIMS_PER_BATCH`]. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub max_claim_channels: Option, + + /// Most `channels[]` entries the facilitator distributes in one `settle` + /// transaction, copied from its `/supported` extra. Absent means + /// [`MAX_CLAIMS_PER_BATCH`]. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub max_settle_channels: Option, + /// Corrective-only server channel snapshot, for cumulative-amount /// resynchronization. See [`BatchRequirements::is_corrective`]. #[serde(skip_serializing_if = "Option::is_none")] @@ -632,10 +655,27 @@ pub struct BatchSettleChannel { pub channel_config: BatchChannelConfig, } -/// One to [`MAX_CLAIMS_PER_BATCH`] redemption entries: the only batch sizes a -/// `claim` or `settle` payload may carry (spec §4.5, "`claims[]` MUST contain -/// between one and four entries so the instruction pairs fit in a legacy -/// Solana transaction without address lookup tables"). +/// A `claim` or `settle` entry type and the most entries any facilitator can +/// accept in one request: what fits one version-1 redemption. +pub trait RedemptionEntry { + /// Largest capacity a facilitator may advertise for this entry type. + const MAX_PER_REQUEST: usize; +} + +impl RedemptionEntry for BatchVoucherClaim { + const MAX_PER_REQUEST: usize = V1_MAX_CLAIM_CHANNELS; +} + +impl RedemptionEntry for BatchSettleChannel { + const MAX_PER_REQUEST: usize = V1_MAX_SETTLE_CHANNELS; +} + +/// One to [`RedemptionEntry::MAX_PER_REQUEST`] redemption entries (spec 4.5: +/// "`claims[]` MUST contain at least one entry and at most +/// `extra.maxClaimChannels` entries"). No facilitator can advertise more than +/// what fits one version-1 transaction, so a longer batch is malformed for +/// every facilitator; a facilitator then checks the batch against its own, +/// possibly smaller, capacity. /// /// The bound is enforced at construction and at parse time, so an empty or /// oversized batch never exists as a value: a facilitator cannot silently @@ -643,18 +683,19 @@ pub struct BatchSettleChannel { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(try_from = "Vec", into = "Vec")] #[serde(bound( - serialize = "T: Serialize + Clone", - deserialize = "T: Deserialize<'de>" + serialize = "T: Serialize + Clone + RedemptionEntry", + deserialize = "T: Deserialize<'de> + RedemptionEntry" ))] -pub struct RedemptionBatch(Vec); +pub struct RedemptionBatch(Vec); -impl RedemptionBatch { +impl RedemptionBatch { /// Wrap `entries`, refusing an empty batch or one over - /// [`MAX_CLAIMS_PER_BATCH`]. + /// [`RedemptionEntry::MAX_PER_REQUEST`]. pub fn new(entries: Vec) -> Result { - if entries.is_empty() || entries.len() > MAX_CLAIMS_PER_BATCH { + if entries.is_empty() || entries.len() > T::MAX_PER_REQUEST { return Err(Error::Other(format!( - "a redemption batch must carry 1 through {MAX_CLAIMS_PER_BATCH} entries, got {}", + "a redemption batch must carry 1 through {} entries, got {}", + T::MAX_PER_REQUEST, entries.len() ))); } @@ -672,7 +713,7 @@ impl RedemptionBatch { } } -impl TryFrom> for RedemptionBatch { +impl TryFrom> for RedemptionBatch { type Error = String; fn try_from(entries: Vec) -> Result { @@ -680,7 +721,7 @@ impl TryFrom> for RedemptionBatch { } } -impl From> for Vec { +impl From> for Vec { fn from(batch: RedemptionBatch) -> Self { batch.0 } @@ -878,6 +919,8 @@ mod tests { voucher_signer: None, operator: None, max_idle_secs: None, + max_claim_channels: None, + max_settle_channels: None, } } @@ -1232,30 +1275,58 @@ mod tests { } #[test] - fn redemption_batches_carry_one_to_four_entries() { - let entry = || { + fn redemption_batches_carry_up_to_the_version_1_capacity() { + let claim_entry = || { serde_json::json!({ "channelId": CHANNEL, "channelConfig": serde_json::to_value(channel_config()).unwrap(), "voucher": serde_json::to_value(voucher("5000")).unwrap(), }) }; - let claim = |n: usize| serde_json::json!({ "type": "claim", "claims": (0..n).map(|_| entry()).collect::>() }); - for n in 1..=MAX_CLAIMS_PER_BATCH { + let settle_entry = || { + serde_json::json!({ + "channelId": CHANNEL, + "channelConfig": serde_json::to_value(channel_config()).unwrap(), + }) + }; + let claim = |n: usize| serde_json::json!({ "type": "claim", "claims": (0..n).map(|_| claim_entry()).collect::>() }); + let settle = |n: usize| serde_json::json!({ "type": "settle", "channels": (0..n).map(|_| settle_entry()).collect::>() }); + for n in [1, MAX_CLAIMS_PER_BATCH + 1, V1_MAX_CLAIM_CHANNELS] { let parsed: BatchRedemptionPayload = serde_json::from_value(claim(n)).unwrap(); assert!( matches!(parsed, BatchRedemptionPayload::Claim { claims } if claims.entries().len() == n) ); } - // Below the minimum and above the transaction-size bound never parse. - for n in [0, MAX_CLAIMS_PER_BATCH + 1] { + for n in [1, V1_MAX_SETTLE_CHANNELS] { + let parsed: BatchRedemptionPayload = serde_json::from_value(settle(n)).unwrap(); + assert!( + matches!(parsed, BatchRedemptionPayload::Settle { channels } if channels.entries().len() == n) + ); + } + // Below the minimum, and above what any facilitator can advertise, + // never parse. + for n in [0, V1_MAX_CLAIM_CHANNELS + 1] { let err = serde_json::from_value::(claim(n)).unwrap_err(); - assert!(err.to_string().contains("1 through 4"), "{err}"); + assert!(err.to_string().contains("1 through 18"), "{err}"); } - let settle = serde_json::json!({ "type": "settle", "channels": [] }); - assert!(serde_json::from_value::(settle).is_err()); - assert!(RedemptionBatch::::new(vec![]).is_err()); - assert!(RedemptionBatch::new(vec![0u8; 5]).is_err()); + for n in [0, V1_MAX_SETTLE_CHANNELS + 1] { + let err = serde_json::from_value::(settle(n)).unwrap_err(); + assert!(err.to_string().contains("1 through 13"), "{err}"); + } + } + + #[test] + fn redemption_capacity_round_trips_in_the_extra() { + let mut json = serde_json::to_value(requirements()).unwrap(); + json["extra"]["maxClaimChannels"] = serde_json::json!(18); + json["extra"]["maxSettleChannels"] = serde_json::json!(13); + let parsed: BatchRequirements = serde_json::from_value(json.clone()).unwrap(); + assert_eq!(parsed.extra.max_claim_channels, Some(18)); + assert_eq!(parsed.extra.max_settle_channels, Some(13)); + assert_eq!( + serde_json::to_value(&parsed).unwrap()["extra"], + json["extra"] + ); } #[test] diff --git a/rust/crates/kit/src/x402/protocol/schemes/batch_settlement/verify.rs b/rust/crates/kit/src/x402/protocol/schemes/batch_settlement/verify.rs index ce438f200..1a114bbba 100644 --- a/rust/crates/kit/src/x402/protocol/schemes/batch_settlement/verify.rs +++ b/rust/crates/kit/src/x402/protocol/schemes/batch_settlement/verify.rs @@ -663,6 +663,8 @@ mod tests { voucher_signer: None, operator: None, max_idle_secs: None, + max_claim_channels: None, + max_settle_channels: None, }, }; let config = BatchChannelConfig { diff --git a/rust/crates/kit/src/x402/protocol/schemes/exact/types.rs b/rust/crates/kit/src/x402/protocol/schemes/exact/types.rs index 7be660c54..20640ba6a 100644 --- a/rust/crates/kit/src/x402/protocol/schemes/exact/types.rs +++ b/rust/crates/kit/src/x402/protocol/schemes/exact/types.rs @@ -447,29 +447,33 @@ impl<'de> Deserialize<'de> for PaymentRequirements { } } -/// `extra.transactionVersions` intersected with what the kit can build. +/// `extra.transactionVersions` as the accepted set. /// -/// §1.5: clients intersect the advertisement with the versions they can -/// build, so an entry the kit never builds (`"legacy"`, an unknown version) -/// is dropped rather than refusing the offer; an advertisement with nothing -/// buildable left then fails negotiation with `unsupported_transaction_version` -/// (RULINGS T1, T2). A value that is not an array is malformed. The wire -/// object stays in `accepted`, so the echoed offer is unchanged. +/// §1.5: "A client or server MUST treat a field containing any non-integer +/// entry (a string, null, or "legacy") or any integer other than 0 or 1 as +/// invalid and fail closed with unsupported_transaction_version." The whole +/// field is refused, never filtered down to the entries the kit knows. A value +/// that is not an array is malformed the same way. fn buildable_transaction_versions( value: &serde_json::Value, ) -> Result, String> { let entries = value .as_array() - .ok_or("extra.transactionVersions must be an array")?; - Ok(entries + .ok_or("unsupported_transaction_version: extra.transactionVersions must be an array")?; + entries .iter() - .filter_map(|entry| { + .map(|entry| { entry .as_u64() .and_then(|n| u8::try_from(n).ok()) .and_then(|n| crate::core::tx::TxVersion::try_from(n).ok()) + .ok_or_else(|| { + format!( + "unsupported_transaction_version: extra.transactionVersions entries must be the integers 0 or 1 (got {entry})" + ) + }) }) - .collect()) + .collect() } fn normalize_network_identifier(network: &str) -> String { @@ -1438,31 +1442,46 @@ mod tests { assert_eq!(requirement.network, SOLANA_MAINNET); } - /// §1.5: the client intersects `extra.transactionVersions` with what it - /// can build. `"legacy"` is never buildable, so `["legacy"]` leaves an - /// empty intersection (negotiation then fails with - /// unsupported_transaction_version) instead of failing to parse. + /// `extra.transactionVersions` holds only the integers 0 and 1; any other + /// entry invalidates the whole field (x402 scheme_exact_svm.md §1.5: "fail + /// closed with unsupported_transaction_version"), rather than being + /// filtered out. #[test] - fn transaction_versions_keep_only_buildable_entries() { + fn transaction_versions_fail_closed_on_any_invalid_entry() { use crate::core::tx::TxVersion; let with_versions = |versions: serde_json::Value| { let mut offer = v2_offer(); offer["extra"]["transactionVersions"] = versions; serde_json::from_value::(offer) }; - let legacy = with_versions(serde_json::json!(["legacy"])).unwrap(); - assert_eq!(legacy.transaction_versions, Some(vec![])); - let err = crate::core::tx::negotiate(legacy.transaction_versions.as_deref(), None) - .unwrap_err() - .to_string(); - assert!(err.contains("advertises no transaction version"), "{err}"); assert_eq!( - with_versions(serde_json::json!([1, "legacy", 7])) + with_versions(serde_json::json!([1, 0])) + .unwrap() + .transaction_versions, + Some(vec![TxVersion::V1, TxVersion::V0]) + ); + for invalid in [ + serde_json::json!(["legacy"]), + serde_json::json!([1, "legacy", 7]), + serde_json::json!([2, 1, 0]), + serde_json::json!(["1", 0]), + serde_json::json!([null, 0]), + serde_json::json!([0.5, 0]), + serde_json::json!("0"), + ] { + let err = with_versions(invalid.clone()).unwrap_err().to_string(); + assert!( + err.contains("unsupported_transaction_version"), + "{invalid}: {err}" + ); + } + // Present and empty is valid and accepts nothing (RULINGS T2). + assert_eq!( + with_versions(serde_json::json!([])) .unwrap() .transaction_versions, - Some(vec![TxVersion::V1]) + Some(vec![]) ); - assert!(with_versions(serde_json::json!("0")).is_err()); let mut absent = v2_offer(); if let Some(extra) = absent["extra"].as_object_mut() { extra.remove("transactionVersions"); diff --git a/rust/crates/kit/src/x402/protocol/schemes/exact/verify.rs b/rust/crates/kit/src/x402/protocol/schemes/exact/verify.rs index 7f604f72b..952bcb324 100644 --- a/rust/crates/kit/src/x402/protocol/schemes/exact/verify.rs +++ b/rust/crates/kit/src/x402/protocol/schemes/exact/verify.rs @@ -15,8 +15,9 @@ use crate::x402::error::Error; const MAX_COMPUTE_UNIT_PRICE_MICROLAMPORTS: u64 = 5_000_000; -/// Highest compute-unit limit a sponsored fee payer co-signs. -const MAX_COMPUTE_UNIT_LIMIT: u32 = 200_000; +/// Highest compute-unit limit a sponsored fee payer co-signs: the reference +/// default of scheme_exact_svm.md §2.2.1 ("Max compute units | `400,000`"). +const MAX_COMPUTE_UNIT_LIMIT: u32 = 400_000; /// Verify a confirmed transaction matches the expected payment requirements. /// @@ -284,6 +285,7 @@ pub fn verify_exact_versioned_transaction( // has no ComputeBudget prefix; the price cap is applied to the header. let budgeted = version == crate::core::tx::TxVersion::V1; if budgeted { + verify_v1_config_presence(&tx.message)?; let declared = crate::core::tx::DeclaredBudget::of(&tx.message) .map_err(|e| Error::Other(format!("invalid_exact_svm_payload_transaction: {e}")))?; if declared @@ -303,12 +305,15 @@ pub fn verify_exact_versioned_transaction( ); } // The limit and price caps are checked above with their own reasons; - // what is left (a zero unit limit, a missing or short - // loadedAccountsDataSizeLimit) is a malformed version-1 header. - crate::core::tx::check_v1_budget_caps( + // what is left (a zero unit limit or loaded-data budget, one above the + // runtime maximum) is a malformed version-1 header. §1.5 requires the + // loaded-data budget to be set, not to be the maximum: clients size it + // (the reference SDKs request 4 MiB). + crate::core::tx::check_v1_budget_caps_with( &tx.message, MAX_COMPUTE_UNIT_LIMIT, MAX_COMPUTE_UNIT_PRICE_MICROLAMPORTS, + crate::core::tx::LoadedDataLimitRule::Present, ) .map_err(|e| Error::Other(format!("invalid_exact_svm_payload_transaction: {e}")))?; } @@ -334,6 +339,39 @@ pub fn verify_exact_versioned_transaction( verify_required_signers(&tx.message, budgeted) } +/// The version-1 config rules of scheme_exact_svm.md §1.5 and §2.2.1 that +/// have their own reasons, checked before the shared budget caps so each +/// failure names its rule: no ComputeBudget instruction (the runtime ignores +/// them, so bounding one bounds nothing), no heap request (version 0 rejects +/// RequestHeapFrame the same way), and both the compute unit limit and the +/// loaded-account-data budget set (an unset value is zero, which cannot +/// execute after the sponsor has paid the fee). +fn verify_v1_config_presence(message: &solana_message::VersionedMessage) -> Result<(), Error> { + let solana_message::VersionedMessage::V1(v1) = message else { + return Ok(()); + }; + let keys = message.static_account_keys(); + if message.instructions().iter().any(|ix| { + keys.get(ix.program_id_index as usize) == Some(&crate::core::tx::COMPUTE_BUDGET_PROGRAM_ID) + }) { + return invalid("invalid_exact_svm_payload_transaction_v1_compute_budget_instruction"); + } + if v1.config.heap_size.is_some() { + return invalid("invalid_exact_svm_payload_transaction_v1_heap_size"); + } + if v1.config.compute_unit_limit.is_none() { + return invalid( + "invalid_exact_svm_payload_transaction_instructions_compute_limit_instruction", + ); + } + if v1.config.loaded_accounts_data_size_limit.is_none() { + return invalid( + "invalid_exact_svm_payload_transaction_loaded_accounts_data_size_limit_missing", + ); + } + Ok(()) +} + /// Only the fee payer and the transfer authority may sign: every extra /// required signature is a base fee the sponsor pays. fn verify_required_signers( @@ -1637,16 +1675,62 @@ mod tests { let solana_message::VersionedMessage::V1(message) = &mut tx.message else { panic!("version-1 message expected"); }; - message.config.loaded_accounts_data_size_limit = None; - let err = verify_exact_versioned_transaction(&tx, &requirements, &[fee_payer]).unwrap_err(); - let reason = err.to_string(); - assert!( - reason.starts_with("invalid_exact_svm_payload_transaction: ") - && reason.contains("loaded accounts data size limit"), - "{reason}" + let base = message.config; + let reason_for = |tx: &VersionedTransaction| { + verify_exact_versioned_transaction(tx, &requirements, &[fee_payer]) + .unwrap_err() + .to_string() + }; + let with_config = |edit: &dyn Fn(&mut solana_message::v1::TransactionConfig)| { + let mut tx = tx.clone(); + let solana_message::VersionedMessage::V1(message) = &mut tx.message else { + unreachable!() + }; + message.config = base; + edit(&mut message.config); + tx + }; + + assert_eq!( + reason_for(&with_config(&|c| c.loaded_accounts_data_size_limit = None)), + "invalid_exact_svm_payload_transaction_loaded_accounts_data_size_limit_missing" + ); + assert_eq!( + reason_for(&with_config(&|c| c.compute_unit_limit = None)), + "invalid_exact_svm_payload_transaction_instructions_compute_limit_instruction" + ); + assert_eq!( + reason_for(&with_config(&|c| c.heap_size = Some(64 * 1024))), + "invalid_exact_svm_payload_transaction_v1_heap_size" ); + // §1.5 requires the loaded-data budget to be set, not to be the + // runtime maximum: the reference TypeScript and Go clients set 4 MiB. + let sized = with_config(&|c| c.loaded_accounts_data_size_limit = Some(4 * 1024 * 1024)); + assert!(verify_exact_versioned_transaction(&sized, &requirements, &[fee_payer]).is_ok()); + let zero = with_config(&|c| c.loaded_accounts_data_size_limit = Some(0)); + assert!(reason_for(&zero).starts_with("invalid_exact_svm_payload_transaction: ")); } + /// A ComputeBudget instruction in a version-1 message is refused with its + /// own reason (x402 scheme_exact_svm.md §2.2.1). + #[test] + fn verify_exact_v1_rejects_compute_budget_instructions() { + let requirements = requirements("1000"); + let fee_payer = Pubkey::new_unique(); + let owner = Pubkey::new_unique(); + let tx = build_exact_v1_transaction( + &requirements, + &fee_payer, + &owner, + vec![crate::core::tx::unit_price_instruction(1)], + crate::core::tx::ComputeBudget::new(20_000, 1), + ); + let err = verify_exact_versioned_transaction(&tx, &requirements, &[fee_payer]).unwrap_err(); + assert_eq!( + err.to_string(), + "invalid_exact_svm_payload_transaction_v1_compute_budget_instruction" + ); + } #[test] fn verify_exact_transaction_caps_v1_compute_unit_limit() { let requirements = requirements("1000"); diff --git a/rust/crates/kit/src/x402/server/batch_settlement.rs b/rust/crates/kit/src/x402/server/batch_settlement.rs index f8a4805a9..0610b46db 100644 --- a/rust/crates/kit/src/x402/server/batch_settlement.rs +++ b/rust/crates/kit/src/x402/server/batch_settlement.rs @@ -40,6 +40,14 @@ use solana_pubkey::Pubkey; use solana_rpc_client::rpc_client::RpcClient; use solana_transaction::versioned::VersionedTransaction; +use crate::core::payment_channel::payer_refund::DistributeClearance; +use crate::core::payment_channel::token_account::{ + decode_token_account, TOKEN_ACCOUNT_FROZEN, TOKEN_ACCOUNT_INITIALIZED, +}; +#[cfg(test)] +use crate::core::payment_channel::token_account::{ + EXTENSION_IMMUTABLE_OWNER, TOKEN_ACCOUNT_LEN, TOKEN_ACCOUNT_TYPE, +}; use crate::core::payment_channels as pc; use crate::core::payment_channels::generated::accounts::Channel; use crate::core::settlement::packing::{pack, ChannelInstructionGroup}; @@ -59,7 +67,8 @@ use crate::x402::protocol::schemes::batch_settlement::{ BatchChannelConfig, BatchError, BatchExtra, BatchPayload, BatchPaymentPayload, BatchRefund, BatchRequiredEnvelope, BatchRequirements, BatchSettlementExtra, BatchSettlementResponse, ChannelStateSnapshot, SetupForm, TransactionExpectations, VoucherState, - BATCH_SETTLEMENT_SCHEME, MAX_CLAIMS_PER_BATCH, MIN_WITHDRAW_DELAY_SECONDS, VOUCHER_EXPIRES_AT, + BATCH_SETTLEMENT_SCHEME, MAX_CLAIMS_PER_BATCH, MIN_WITHDRAW_DELAY_SECONDS, + V1_MAX_CLAIM_CHANNELS, V1_MAX_SETTLE_CHANNELS, VOUCHER_EXPIRES_AT, }; use crate::x402::protocol::schemes::exact::{ caip2_network_for_cluster, default_rpc_url, default_token_program_for_currency, ResourceInfo, @@ -199,36 +208,72 @@ fn is_empty_tombstone(state: &ChannelState) -> bool { fn spawn_next_submission( version: TxVersion, - in_flight: &mut tokio::task::JoinSet>, - pending: &mut std::collections::VecDeque>, + in_flight: &mut tokio::task::JoinSet>, + pending: &mut std::collections::VecDeque>>, pipeline: &TxPipeline, signer: &Arc, fee_payer: &Pubkey, ) { - let Some(instructions) = pending.pop_front() else { + let Some(groups) = pending.pop_front() else { return; }; let pipeline = pipeline.clone(); let signer = Arc::clone(signer); let fee_payer = *fee_payer; in_flight.spawn(async move { - let blockhash = pipeline - .latest_blockhash() - .await - .map_err(|e| Error::Rpc(format!("blockhash fetch failed: {e}")))?; - let mut tx = - crate::core::tx::build_unsigned(version, &fee_payer, &instructions, blockhash, None)?; - crate::core::signing::sign_versioned_transaction_slot(signer.as_ref(), &mut tx) - .await - .map_err(|e| Error::Other(format!("fee payer signing failed: {e}")))?; - pipeline - .submit_verified(&tx) - .await - .map(|confirmed| confirmed.signature.to_string()) - .map_err(|e| Error::Rpc(format!("settlement submission failed: {e}"))) + let failed = + |error: Error, on_chain: bool, groups: Vec>| FailedSubmission { + error, + on_chain, + groups, + }; + let instructions: Vec = groups.iter().flatten().cloned().collect(); + let blockhash = match pipeline.latest_blockhash().await { + Ok(blockhash) => blockhash, + Err(e) => { + let error = Error::Rpc(format!("blockhash fetch failed: {e}")); + return Err(failed(error, false, groups)); + } + }; + let mut tx = match crate::core::tx::build_unsigned( + version, + &fee_payer, + &instructions, + blockhash, + None, + ) { + Ok(tx) => tx, + Err(error) => return Err(failed(error.into(), false, groups)), + }; + if let Err(e) = + crate::core::signing::sign_versioned_transaction_slot(signer.as_ref(), &mut tx).await + { + let error = Error::Other(format!("fee payer signing failed: {e}")); + return Err(failed(error, false, groups)); + } + match pipeline.submit_verified(&tx).await { + Ok(confirmed) => Ok(confirmed.signature.to_string()), + Err(e) => { + let on_chain = matches!( + e, + crate::core::tx_pipeline::TxPipelineError::TransactionFailed { .. } + ); + let error = Error::Rpc(format!("settlement submission failed: {e}")); + Err(failed(error, on_chain, groups)) + } + } }); } +/// A settlement transaction that did not land, with the channel groups it +/// carried. +struct FailedSubmission { + error: Error, + /// It landed and failed, so none of its instructions applied. + on_chain: bool, + groups: Vec>, +} + /// Fetch and decode a channel account with the blocking RPC client. Factored out /// of [`X402BatchSettlement::lookup_channel`] so the reconcile path can run it on /// a blocking thread (via `spawn_blocking`) instead of stalling an async worker: @@ -593,10 +638,11 @@ pub enum BatchAccess { /// not finish. Call [`X402BatchSettlement::finish_commit`] and return its /// response; the handler MUST NOT run again. Resume(BatchOutcome), - /// Already committed: return this stored response, and do not run the - /// handler. The second element is the resource handler's cached response - /// from the original serve, when one was stored for it — see - /// [`X402BatchSettlement::cache_response`]. + /// Already committed: return this stored settlement response, and do + /// not run the handler. The resource body is never replayed (the voucher + /// that reaches this arm is public once a claim or a corrective 402 + /// discloses it), so the second element is always `None`; it is kept for + /// compatibility. Replay( BatchSettlementResponse, Option, @@ -764,6 +810,17 @@ impl X402BatchSettlement { crate::core::tx::highest(&self.accepted_versions) } + /// Channels per claim and per settle redemption transaction: the + /// version-1 capacities when redemptions are built as version 1, four + /// otherwise (scheme_batch_settlement_svm.md, facilitator-built + /// transactions). + fn redemption_capacity(&self) -> (usize, usize) { + match self.tx_version() { + TxVersion::V1 => (V1_MAX_CLAIM_CHANNELS, V1_MAX_SETTLE_CHANNELS), + TxVersion::V0 => (MAX_CLAIMS_PER_BATCH, MAX_CLAIMS_PER_BATCH), + } + } + /// Route this handler's chain reads through `rpc` (a mock in tests). #[cfg(test)] pub(crate) fn with_rpc_client(mut self, rpc: RpcClient) -> Self { @@ -881,6 +938,12 @@ impl X402BatchSettlement { voucher_signer: None, operator: None, max_idle_secs: None, + // The redemption capacity of the message version this server + // builds redemptions in; absent (four) when that is version 0. + max_claim_channels: (self.tx_version() == TxVersion::V1) + .then_some(V1_MAX_CLAIM_CHANNELS as u32), + max_settle_channels: (self.tx_version() == TxVersion::V1) + .then_some(V1_MAX_SETTLE_CHANNELS as u32), }, }) } @@ -1022,9 +1085,12 @@ impl X402BatchSettlement { error: &Error, resource: Option<&str>, ) -> Result<(String, String), Error> { + // Only a mismatch this server raised: the detail of any other error + // may quote client-supplied text, which must not be able to request + // the channel's snapshot. let is_mismatch = - crate::x402::protocol::schemes::batch_settlement::classify(&error.to_string()) - == codes::INVALID_CUMULATIVE_AMOUNT_MISMATCH; + crate::x402::protocol::schemes::batch_settlement::leading_code(&error.to_string()) + == Some(codes::INVALID_CUMULATIVE_AMOUNT_MISMATCH); if is_mismatch { if let Some(channel_id) = self.channel_id_for_header(header) { if let Ok(envelope) = self @@ -1318,6 +1384,20 @@ impl X402BatchSettlement { recent_slot, )?; let deposit_signature = payer_signature(&validated.transaction); + // The deposit is broadcast only after the handler runs, so a + // transaction that cannot land must be refused now. One this + // server already recorded may be in flight or committed, and + // its funds already moved. + if !deposit_already_recorded(stored.as_ref(), deposit_signature.as_deref()) { + self.check_deposit_can_land( + &validated.transaction, + &payer, + &mint, + &token_program, + deposit_amount, + ) + .await?; + } let deposit_after = Self::deposit_ceiling( stored.as_ref(), deposit_amount, @@ -1529,40 +1609,147 @@ impl X402BatchSettlement { format!("{role} settlement ATA {ata} is unavailable: {e}"), ) })?; - if pc::from_address(&account.owner) != *token_program { - return reject("is not owned by the declared token program".to_string()); - } - let Some(decoded) = decode_token_account(&account.data) else { - return reject("is not an initialized token account".to_string()); - }; - if decoded.mint != *mint { - return reject(format!( - "holds mint {} rather than {}", - pc::pubkey_string(&decoded.mint), - pc::pubkey_string(mint) - )); - } - if decoded.owner != owner { - return reject(format!( - "is owned by {} rather than {}", - pc::pubkey_string(&decoded.owner), - pc::pubkey_string(&owner) - )); - } - if decoded.state == TOKEN_ACCOUNT_FROZEN { - return reject("is frozen".to_string()); + if let Some(problem) = unusable_settlement_account( + &pc::from_address(&account.owner), + &account.data, + &owner, + mint, + token_program, + ) { + return reject(problem); } - if let Some(extension) = decoded.unsupported_extension { - return reject(format!( - "carries token account extension {extension}, which this server \ - will not settle through" - )); + } + Ok(()) + } + + /// The checks a deposit transaction must pass before the handler runs, + /// since it is only broadcast afterwards: its blockhash is still live and + /// the payer's token account holds the deposit (spec, canonical `open` + /// and `top_up`: "It MUST confirm the payer has sufficient tokens"). A + /// failed read is a refusal too. The blocking reads run on a blocking + /// thread (`spawn_blocking`). + async fn check_deposit_can_land( + &self, + transaction: &VersionedTransaction, + payer: &Pubkey, + mint: &Pubkey, + token_program: &Pubkey, + deposit_amount: u64, + ) -> Result<(), Error> { + let rpc = Arc::clone(&self.rpc); + let blockhash = *transaction.message.recent_blockhash(); + let (ata, _) = pc::find_associated_token_address(payer, mint, token_program); + tokio::task::spawn_blocking(move || { + deposit_can_land(&rpc, &blockhash, &ata, deposit_amount) + }) + .await + .map_err(|e| Error::Other(format!("deposit check task failed: {e}")))? + } + + /// The clearance to send the sealed `distribute` of `channel`, sealed at + /// `settled` (at `sealed_at`, unix seconds), or `None` to defer it. The + /// program forfeits a due refund to the treasury when the payer's token + /// account cannot take it, so such a channel is sealed without its + /// distribute and a later pass retries: as soon as the account is usable + /// or the payer withdrew, and once the channel has been sealed for its + /// grace period, anyway, so the payer cannot hold the payout hostage. + fn sealed_distribute_clearance( + &self, + channel_id: &str, + channel: &Pubkey, + onchain: &Channel, + settled: u64, + sealed_at: i64, + now: i64, + ) -> Result, Error> { + use crate::core::payment_channel::payer_refund::{ + payer_refund, ObservedAccount, PayerRefund, RefundDeadline, SealedRefundTerms, + }; + let terms = SealedRefundTerms { + channel: *channel, + payer: pc::from_address(&onchain.payer), + mint: self.mint()?, + token_program: self.token_program()?, + deposit: onchain.deposit, + settled: settled.max(onchain.settlement.settled), + payer_withdrawn_at: onchain.payer_withdrawn_at, + }; + let deadline = RefundDeadline { + sealed_at, + grace_period: onchain.grace_period, + }; + if terms.refund_due() == 0 { + return Ok(payer_refund(&terms, None, deadline, now).clearance()); + } + let address = terms.payer_token_account(); + let account = self + .rpc + .get_account_with_commitment(&address, self.rpc.commitment()) + .map_err(|e| Error::Rpc(format!("payer refund account {address}: {e}")))? + .value; + let observed = account.as_ref().map(|account| ObservedAccount { + owner: pc::from_address(&account.owner), + data: &account.data, + }); + match payer_refund(&terms, observed, deadline, now) { + PayerRefund::Clear(clearance) => Ok(Some(clearance)), + PayerRefund::Deferred { + refund, + payer_token_account, + reason, + until, + } => { + tracing::warn!( + channel = %channel_id, + %payer_token_account, + refund, + reason, + until, + "payer refund account cannot be paid; sealing without distributing \ + until it can, or until the deadline" + ); + Ok(None) } - if decoded.state != TOKEN_ACCOUNT_INITIALIZED { - return reject(format!("is in account state {}", decoded.state)); + PayerRefund::Forfeit { + clearance, + refund, + payer_token_account, + reason, + } => { + tracing::warn!( + channel = %channel_id, + %payer_token_account, + refund, + reason, + "payer refund account still unusable past the deadline; distributing, \ + the refund goes to the treasury" + ); + Ok(Some(clearance)) } } - Ok(()) + } + + /// When this server first saw `channel_id` sealed, recording `now` when it + /// had not; `now` for a channel this store has no record of. + async fn first_sealed_at(&self, channel_id: &str, now: i64) -> i64 { + self.store + .update_channel( + channel_id, + Box::new(move |current| { + let mut state = current.ok_or_else(|| { + crate::core::store::StoreError::Internal("channel not found".into()) + })?; + state + .extra + .entry(SEALED_AT_KEY.to_string()) + .or_insert_with(|| now.into()); + Ok(state) + }), + ) + .await + .ok() + .and_then(|state| state.extra.get(SEALED_AT_KEY)?.as_i64()) + .unwrap_or(now) } /// Verify a client-mode `refund` and return the watermark it closes at. @@ -1994,31 +2181,17 @@ impl X402BatchSettlement { Ok(()) } - /// Cache the resource handler's response against an already-committed - /// authorization, so a future replay of the same voucher can return the - /// purchased representation itself rather than only the settlement - /// result — the `("access", channelId, maxClaimableAmount)` cache the - /// batch-settlement spec requires. Call after [`Self::finish_commit`] (or - /// [`Self::settle_payment`]) has already succeeded; this is a best-effort - /// improvement to a *future* request, so its own failure is not this - /// request's problem and callers should log, not propagate, an error. + /// Formerly cached the handler's response so a replay of the same + /// voucher returned it. A replay now returns the settlement response + /// only: the voucher that unlocks a replay is public once a claim or a + /// corrective 402 discloses it, so it cannot gate a payer's resource + /// body. This is a no-op kept for compatibility. + #[deprecated(note = "batch replays never return a cached body; this is a no-op")] pub async fn cache_response( &self, - outcome: &BatchOutcome, - cached: crate::core::store::CachedUpstreamResponse, + _outcome: &BatchOutcome, + _cached: crate::core::store::CachedUpstreamResponse, ) -> Result<(), Error> { - let Authorization { id, .. } = self.authorization_of(outcome)?; - self.store - .mutate_channel( - &outcome.channel_id, - None, - Box::new(move |state| { - state.attach_cached_response(&id, cached); - Ok(()) - }), - ) - .await - .map_err(|e| Error::Other(format!("store error: {e}")))?; Ok(()) } @@ -2703,15 +2876,11 @@ impl X402BatchSettlement { } } - /// Rebuild the accepted response for an idempotent voucher retry, plus - /// the resource handler's cached response when one was stored for it - /// (see [`Self::cache_response`]) — together, the - /// `("access", channelId, maxClaimableAmount)` replay the batch-settlement - /// spec requires. The cached response is `None` when no response was - /// stored — a record that predates response storage, one whose response - /// exceeded the caller's size cap for caching, or one whose stored - /// response has aged out — in which case the caller falls back to a - /// settlement-only reply. + /// Rebuild the accepted settlement response for an idempotent voucher + /// retry. The second element is always `None`: possession of the voucher + /// proves nothing about who sent the original request (a claim publishes + /// it, and the corrective 402 returns it), so no resource body is ever + /// replayed against it (the scheme replays neither, Phase 3 step 6). pub async fn replay_response( &self, outcome: &BatchOutcome, @@ -2748,12 +2917,11 @@ impl X402BatchSettlement { )); } } - let cached = committed.and_then(|committed| committed.cached_response.clone()); let stored = committed .and_then(|committed| committed.settlement_response.clone()) .and_then(|value| serde_json::from_value(value).ok()); if let Some(response) = stored { - return Ok((response, cached)); + return Ok((response, None)); } Ok(( accepted_response( @@ -2765,7 +2933,7 @@ impl X402BatchSettlement { outcome.requirements.amount()?, &state, ), - cached, + None, )) } @@ -3228,7 +3396,9 @@ impl X402BatchSettlement { }); claimed_watermarks.push((channel_id.clone(), state.cumulative)); } - let signatures = self.submit_groups(groups, MAX_CLAIMS_PER_BATCH).await?; + let signatures = self + .submit_groups(groups, self.redemption_capacity().0) + .await?; for (channel_id, claimed) in claimed_watermarks { self.store .update_channel( @@ -3292,7 +3462,9 @@ impl X402BatchSettlement { }); distributed_watermarks.push((channel_id.clone(), onchain.settlement.settled)); } - let signatures = self.submit_groups(groups, MAX_CLAIMS_PER_BATCH).await?; + let signatures = self + .submit_groups(groups, self.redemption_capacity().1) + .await?; // A successful distribute proves the claim watermark was already // visible and paid. Persist it immediately so the next lifecycle tick // does not re-submit the same channel merely because the RPC account @@ -3361,18 +3533,16 @@ impl X402BatchSettlement { // remote signing cannot age later batches before they are submitted. let mut pending = std::collections::VecDeque::with_capacity(batches.len()); for batch in batches { - let instructions: Vec<_> = batch - .into_iter() - .flat_map(|group| group.instructions) - .collect(); - pending.push_back(instructions); + let groups: Vec> = + batch.into_iter().map(|group| group.instructions).collect(); + pending.push_back(groups); } // Feed each independent transaction into the shared pipeline. This // local bound limits task creation; the pipeline supplies the global // send bound, pacing, retry policy, and batched confirmation tracker // across every concurrent lifecycle chunk. - let total = pending.len(); + let mut total = pending.len(); let pipeline = self.transaction_pipeline().await; let mut in_flight = tokio::task::JoinSet::new(); for _ in 0..SUBMIT_GROUPS_CONCURRENCY { @@ -3388,19 +3558,35 @@ impl X402BatchSettlement { let mut signatures = Vec::with_capacity(total); let mut failures = Vec::new(); while let Some(joined) = in_flight.join_next().await { - spawn_next_submission( - self.tx_version(), - &mut in_flight, - &mut pending, - &pipeline, - &self.config.fee_payer_signer, - &self.fee_payer, - ); match joined { Ok(Ok(signature)) => signatures.push(signature), - Ok(Err(error)) => failures.push(error.to_string()), + // A transaction is atomic, so nothing in it applied: one + // channel failing deterministically must not fail the others + // packed with it. Each is submitted again alone. + Ok(Err(failed)) if failed.on_chain && failed.groups.len() > 1 => { + tracing::warn!( + error = %failed.error, + channels = failed.groups.len(), + "packed settlement failed on-chain; submitting each channel alone", + ); + total += failed.groups.len() - 1; + for group in failed.groups { + pending.push_back(vec![group]); + } + } + Ok(Err(failed)) => failures.push(failed.error.to_string()), Err(error) => failures.push(format!("submit join error: {error}")), } + while in_flight.len() < SUBMIT_GROUPS_CONCURRENCY && !pending.is_empty() { + spawn_next_submission( + self.tx_version(), + &mut in_flight, + &mut pending, + &pipeline, + &self.config.fee_payer_signer, + &self.fee_payer, + ); + } } if !failures.is_empty() { return Err(Error::Rpc(format!( @@ -3479,6 +3665,20 @@ impl X402BatchSettlement { let distribute = match terminal_step(onchain.status, distribute) { TerminalStep::PlanClose(distribute) => distribute, TerminalStep::Submit(instructions) => { + let sealed_at = self.first_sealed_at(channel_id, now).await; + if self + .sealed_distribute_clearance( + channel_id, + &channel, + &onchain, + onchain.settlement.settled, + sealed_at, + now, + )? + .is_none() + { + continue; + } groups.push(ChannelInstructionGroup { channel_id: channel_id.clone(), instructions, @@ -3524,9 +3724,23 @@ impl X402BatchSettlement { let seal_ix = pc::build_seal_instruction(&channel, &program_id); match plan { None | Some((GraceSealPlan::SealFrozen, _)) => { + let mut instructions = vec![seal_ix]; + if self + .sealed_distribute_clearance( + channel_id, + &channel, + &onchain, + onchain.settlement.settled, + now, + now, + )? + .is_some() + { + instructions.push(distribute); + } groups.push(ChannelInstructionGroup { channel_id: channel_id.clone(), - instructions: vec![seal_ix, distribute], + instructions, }); } Some((GraceSealPlan::InFlight, _)) => { @@ -3566,7 +3780,14 @@ impl X402BatchSettlement { expires_at, &program_id, )?; - instructions.push(distribute); + if self + .sealed_distribute_clearance( + channel_id, &channel, &onchain, cumulative, now, now, + )? + .is_some() + { + instructions.push(distribute); + } groups.push(ChannelInstructionGroup { channel_id: channel_id.clone(), instructions, @@ -3595,6 +3816,10 @@ impl X402BatchSettlement { crate::core::store::StoreError::Internal("channel not found".into()) })?; state.sealed = true; + state + .extra + .entry(SEALED_AT_KEY.to_string()) + .or_insert_with(|| now.into()); if let Some(watermark) = applied { state.settled_on_chain = state.settled_on_chain.max(watermark); } @@ -3834,95 +4059,110 @@ fn payer_signature(transaction: &VersionedTransaction) -> Option { Some(signature.to_string()) } -/// Base length of an SPL token account. Token-2022 appends its extensions -/// after the same fixed layout, so one decoder covers both programs. -const TOKEN_ACCOUNT_LEN: usize = 165; - -/// `AccountState::Initialized`, at offset 108. -const TOKEN_ACCOUNT_INITIALIZED: u8 = 1; - -/// `AccountState::Frozen`: the account cannot receive or send. -const TOKEN_ACCOUNT_FROZEN: u8 = 2; - -/// `AccountType::Account`, the discriminant a Token-2022 account carries at -/// offset 165 before its extensions. -const TOKEN_ACCOUNT_TYPE: u8 = 2; - -/// `ExtensionType::ImmutableOwner`. -/// -/// The only account extension a settlement destination may carry. It is inert -/// — it fixes the owner, nothing else — and every associated token account has -/// it, so requiring its absence would reject ordinary ATAs. -const EXTENSION_IMMUTABLE_OWNER: u16 = 7; - -/// The fields of an SPL token account this server cares about. -struct TokenAccount { - mint: Pubkey, - owner: Pubkey, - state: u8, - /// An account extension this server will not settle through, if any. - unsupported_extension: Option, +/// Why the account at `owner`'s associated token address for `mint`, owned +/// by `program` and holding `data`, cannot receive a settlement payout, or +/// `None` when it can: it must be an +/// initialized, unfrozen account of the declared token program holding +/// `mint` for `owner`, with no extension outside the allowlist. The program +/// forfeits a payout to an unusable account to the treasury, so a server +/// checks before it accepts a deposit that would settle there. +pub(crate) fn unusable_settlement_account( + program: &Pubkey, + data: &[u8], + owner: &Pubkey, + mint: &Pubkey, + token_program: &Pubkey, +) -> Option { + if program != token_program { + return Some("is not owned by the declared token program".to_string()); + } + let Some(decoded) = decode_token_account(data) else { + return Some("is not an initialized token account".to_string()); + }; + if decoded.mint != *mint { + return Some(format!( + "holds mint {} rather than {}", + pc::pubkey_string(&decoded.mint), + pc::pubkey_string(mint) + )); + } + if decoded.owner != *owner { + return Some(format!( + "is owned by {} rather than {}", + pc::pubkey_string(&decoded.owner), + pc::pubkey_string(owner) + )); + } + if decoded.state == TOKEN_ACCOUNT_FROZEN { + return Some("is frozen".to_string()); + } + if let Some(extension) = decoded.unsupported_extension { + return Some(format!( + "carries token account extension {extension}, which this server \ + will not settle through" + )); + } + if decoded.state != TOKEN_ACCOUNT_INITIALIZED { + return Some(format!("is in account state {}", decoded.state)); + } + None } -/// Decode a token account, or `None` when the data is too short to be one — -/// which is what an uninitialized (or non-token) account looks like. -/// -/// Token-2022 appends a type byte and a TLV extension list after the same -/// 165-byte base. Those extensions are not cosmetic: one can withhold part of a -/// transfer, require a memo to precede it, block it from a CPI, or move the -/// balance out of the classic ledger entirely — so an account carrying one is -/// reported rather than silently accepted as a payout destination. -fn decode_token_account(data: &[u8]) -> Option { - if data.len() < TOKEN_ACCOUNT_LEN { - return None; - } - Some(TokenAccount { - mint: Pubkey::try_from(&data[0..32]).ok()?, - owner: Pubkey::try_from(&data[32..64]).ok()?, - state: data[108], - unsupported_extension: unsupported_account_extension(data), - }) +/// Whether `signature` is a deposit this server already recorded for the +/// channel: still pending, or committed (a byte-identical retry). Its landing +/// was checked when it was first presented. +fn deposit_already_recorded(stored: Option<&ChannelState>, signature: Option<&str>) -> bool { + let (Some(state), Some(signature)) = (stored, signature) else { + return false; + }; + state + .pending_setup + .as_ref() + .is_some_and(|setup| setup.payer_signature == signature) + || state + .processed_topup_signatures + .iter() + .any(|recorded| recorded == signature) } -/// The first account extension outside the allowlist, if the account has one. -/// -/// A malformed or truncated TLV is reported as unsupported rather than skipped: -/// this decides whether to accept an escrow, so anything it cannot read is -/// something it should not settle through. -fn unsupported_account_extension(data: &[u8]) -> Option { - // A classic SPL Token account is exactly the base length and has no - // extension list at all. - if data.len() == TOKEN_ACCOUNT_LEN { - return None; - } - if data[TOKEN_ACCOUNT_LEN] != TOKEN_ACCOUNT_TYPE { - return Some(u16::from(data[TOKEN_ACCOUNT_LEN])); - } - let mut cursor = TOKEN_ACCOUNT_LEN + 1; - while cursor < data.len() { - // A run of zero padding is the end of the list, not an extension. - if data[cursor..].iter().all(|byte| *byte == 0) { - return None; - } - let Some(header) = data.get(cursor..cursor + 4) else { - return Some(u16::MAX); - }; - let extension = u16::from_le_bytes([header[0], header[1]]); - let length = usize::from(u16::from_le_bytes([header[2], header[3]])); - if extension != EXTENSION_IMMUTABLE_OWNER { - return Some(extension); - } - let Some(next) = cursor.checked_add(4).and_then(|c| c.checked_add(length)) else { - return Some(u16::MAX); - }; - if next > data.len() { - return Some(u16::MAX); - } - cursor = next; +/// [`X402BatchSettlement::check_deposit_can_land`]'s blocking reads. +fn deposit_can_land( + rpc: &RpcClient, + blockhash: &solana_hash::Hash, + ata: &Pubkey, + deposit_amount: u64, +) -> Result<(), Error> { + let not_ready = |detail: String| batch_err(codes::INVALID_SETTLEMENT_SIMULATION, detail); + let live = rpc + .is_blockhash_valid(blockhash, rpc.commitment()) + .map_err(|e| not_ready(format!("deposit blockhash check failed: {e}")))?; + if !live { + return Err(not_ready(format!( + "deposit transaction blockhash {blockhash} is not live" + ))); } - None + let account = rpc + .get_account(ata) + .map_err(|e| not_ready(format!("payer token account {ata} is unavailable: {e}")))?; + let balance = account + .data + .get(64..72) + .and_then(|bytes| bytes.try_into().ok()) + .map(u64::from_le_bytes) + .ok_or_else(|| not_ready(format!("payer token account {ata} is not a token account")))?; + if balance < deposit_amount { + return Err(not_ready(format!( + "payer token account {ata} holds {balance}, less than the {deposit_amount} deposit" + ))); + } + Ok(()) } +/// Where a record keeps when this server first saw its channel sealed (unix +/// seconds), inside [`ChannelState::extra`]: the program records no seal +/// time, and a deferred distribute's deadline counts from it. +const SEALED_AT_KEY: &str = "x402BatchSealedAt"; + /// Where a record keeps the receiver authorizer its channel's open bound /// (spec §3), inside [`ChannelState::extra`]. const RECEIVER_BINDING_KEY: &str = "x402BatchReceiverAuthorizer"; @@ -4372,6 +4612,8 @@ mod tests { voucher_signer: None, operator: None, max_idle_secs: None, + max_claim_channels: None, + max_settle_channels: None, }, }; let (_, config, channel) = client(&fee_payer, &requirements); @@ -4428,6 +4670,67 @@ mod tests { assert!(json["extra"].get("channelProgram").is_none()); } + /// The advertised version-1 claim capacity packs into one transaction: + /// 18 Ed25519+settle pairs fit 4096 bytes, where version 0 needs five. + #[test] + fn eighteen_claims_pack_into_one_version_1_transaction() { + let program_id = Pubkey::from_str(pc::PAYMENT_CHANNELS_PROGRAM_ID).unwrap(); + let groups: Vec = (0..V1_MAX_CLAIM_CHANNELS) + .map(|_| ChannelInstructionGroup { + channel_id: Pubkey::new_unique().to_string(), + instructions: pc::build_settle_instructions( + &Pubkey::new_unique(), + &Pubkey::new_unique(), + &[7u8; 64], + 123_456_789, + 0, + &program_id, + ) + .unwrap(), + }) + .collect(); + let fee_payer = Pubkey::new_unique(); + let v1 = pack( + TxVersion::V1, + groups.clone(), + &fee_payer, + None, + V1_MAX_CLAIM_CHANNELS, + ); + assert_eq!(v1.len(), 1); + let v0 = pack( + TxVersion::V0, + groups, + &fee_payer, + None, + MAX_CLAIMS_PER_BATCH, + ); + assert_eq!( + v0.len(), + V1_MAX_CLAIM_CHANNELS.div_ceil(MAX_CLAIMS_PER_BATCH) + ); + } + + #[test] + fn requirements_advertise_the_redemption_capacity_of_version_1() { + let (mut handler, _) = handler(Arc::new(MemoryChannelStore::new())); + let v0 = handler.requirements("0.001").unwrap(); + assert_eq!(handler.redemption_capacity(), (4, 4)); + assert_eq!(v0.extra.max_claim_channels, None); + assert_eq!(v0.extra.max_settle_channels, None); + + handler.accepted_versions = vec![TxVersion::V0, TxVersion::V1]; + let v1 = handler.requirements("0.001").unwrap(); + assert_eq!(handler.redemption_capacity(), (18, 13)); + let json = serde_json::to_value(&v1).unwrap(); + assert_eq!(json["extra"]["maxClaimChannels"], 18); + assert_eq!(json["extra"]["maxSettleChannels"], 13); + assert_eq!( + json["extra"]["transactionVersions"], + serde_json::json!([0, 1]) + ); + } + #[tokio::test] async fn withdraw_delay_outside_the_conformance_range_is_refused_at_verify() { let (mut handler, _) = handler(Arc::new(MemoryChannelStore::new())); @@ -4678,12 +4981,11 @@ mod tests { ); } - /// A replay returns the resource handler's own cached response when one - /// was stored for it — the spec's `("access", channelId, - /// maxClaimableAmount)` cache — not only the settlement result layered - /// on top of it. + /// A replay returns the settlement only, never a stored resource body: + /// the voucher that reaches it is public once a claim publishes it or a + /// corrective 402 returns it, so it cannot gate a payer's response. #[tokio::test] - async fn a_replay_surfaces_the_cached_upstream_response() { + async fn a_replay_never_returns_a_stored_response_body() { let store = Arc::new(MemoryChannelStore::new()); let (handler, fee_payer) = handler(store.clone()); let (_, request) = paid_channel(&store, &handler, &fee_payer, 2_000).await; @@ -4696,33 +4998,50 @@ mod tests { panic!("a fresh authorization must be served"); }; handler.mark_handler_succeeded(&outcome).await.unwrap(); - handler.finish_commit(&outcome).await.expect("commits"); - let cached = crate::core::store::CachedUpstreamResponse { - status: 200, - content_type: Some("application/json".to_string()), - headers: vec![("etag".to_string(), "\"v1\"".to_string())], - body: br#"{"result":42}"#.to_vec(), - }; - handler - .cache_response(&outcome, cached.clone()) + let settled = handler.finish_commit(&outcome).await.expect("commits"); + // A body stored against the authorization, as an earlier release + // cached it. + let id = handler.authorization_of(&outcome).unwrap().id; + store + .mutate_channel( + &outcome.channel_id, + None, + Box::new(move |state| { + state.attach_cached_response( + &id, + crate::core::store::CachedUpstreamResponse { + status: 200, + content_type: Some("application/json".to_string()), + headers: vec![], + body: br#"{"secret":42}"#.to_vec(), + }, + ); + Ok(()) + }), + ) .await - .expect("caching a response is best-effort but should succeed here"); + .unwrap(); drop(outcome); - let BatchAccess::Replay(_, replayed_cached) = handler + let BatchAccess::Replay(replayed, replayed_body) = handler .verify_and_reserve_payment(&request, "0.001") .await .expect("the same voucher verifies") else { panic!("a committed authorization must replay"); }; - assert_eq!(replayed_cached, Some(cached)); + assert_eq!(replayed_body, None); + // Positive control: the settlement result itself still replays. + assert_eq!( + replayed.extra.and_then(|extra| extra.charged_amount), + settled.extra.and_then(|extra| extra.charged_amount) + ); } /// A repeat of a committed voucher presented to a higher-priced route, /// with `accepted.amount` rewritten to match it, is refused rather than - /// replayed: the original settlement and cached body belong to the route - /// that was paid for. + /// replayed: the original settlement belongs to the route that was paid + /// for. #[tokio::test] async fn a_replay_is_bound_to_the_route_that_committed_it() { let store = Arc::new(MemoryChannelStore::new()); @@ -4753,18 +5072,6 @@ mod tests { }; handler.mark_handler_succeeded(&first).await.unwrap(); handler.finish_commit(&first).await.unwrap(); - handler - .cache_response( - &first, - crate::core::store::CachedUpstreamResponse { - status: 200, - content_type: None, - headers: vec![], - body: b"low-route body".to_vec(), - }, - ) - .await - .unwrap(); drop(first); let err = handler @@ -4789,7 +5096,7 @@ mod tests { .verify_and_reserve_payment(&low_request, "0.001") .await .unwrap(), - BatchAccess::Replay(_, Some(_)) + BatchAccess::Replay(_, None) )); } @@ -5953,6 +6260,232 @@ mod tests { } } + /// A pipeline RPC that confirms every broadcast and records the program + /// ids each sent transaction invokes. + async fn recording_pipeline_rpc() -> ( + String, + Arc>>>, + tokio::task::JoinHandle<()>, + ) { + use axum::{routing::post, Json, Router}; + let sent = Arc::new(Mutex::new(Vec::new())); + let recorded = Arc::clone(&sent); + let app = Router::new().route( + "/", + post(move |Json(request): Json| { + let recorded = Arc::clone(&recorded); + async move { + let result = match request["method"].as_str().unwrap() { + "getLatestBlockhash" => serde_json::json!({ + "context": { "slot": 1 }, + "value": { + "blockhash": solana_hash::Hash::new_unique().to_string(), + "lastValidBlockHeight": 100 + } + }), + "sendTransaction" => { + let tx = + crate::core::tx::decode(request["params"][0].as_str().unwrap()) + .unwrap(); + let keys = tx.message.static_account_keys(); + recorded.lock().unwrap().push( + tx.message + .instructions() + .iter() + .map(|ix| keys[ix.program_id_index as usize]) + .collect(), + ); + serde_json::json!(tx.signatures[0].to_string()) + } + "getSignatureStatuses" => { + let statuses = request["params"][0] + .as_array() + .unwrap() + .iter() + .map(|_| { + serde_json::json!({ + "slot": 2, "confirmations": null, "err": null, + "confirmationStatus": "finalized", + "status": { "Ok": null } + }) + }) + .collect::>(); + serde_json::json!({ "context": { "slot": 2 }, "value": statuses }) + } + method => panic!("unexpected RPC method {method}"), + }; + Json(serde_json::json!({ + "jsonrpc": "2.0", "id": request["id"], "result": result + })) + } + }), + ); + let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap(); + let url = format!("http://{}", listener.local_addr().unwrap()); + let server = tokio::spawn(async move { axum::serve(listener, app).await.unwrap() }); + (url, sent, server) + } + + /// The program forfeits a due refund to the treasury when the payer's + /// token account cannot take it, so `finalize_close` seals such a + /// channel without distributing it. + /// Run `finalize_close` over one channel at onchain `status`, its payer + /// refund account usable or not, its record seeded with `sealed_at`. + /// Returns the payment-channels instructions sent and the seal time the + /// record holds afterwards. + async fn finalize_close_once( + status: u8, + payable: bool, + sealed_at: Option, + ) -> (usize, Option) { + use base64::Engine as _; + use solana_rpc_client_api::request::RpcRequest; + + { + let (url, sent, rpc) = recording_pipeline_rpc().await; + let key = SigningKey::from_bytes(&[21; 32]); + let mut keypair = [0u8; 64]; + keypair[..32].copy_from_slice(key.as_bytes()); + keypair[32..].copy_from_slice(key.verifying_key().as_bytes()); + let signer = solana_keychain::MemorySigner::from_bytes(&keypair).unwrap(); + let fee_payer = signer.pubkey(); + let mut config = BatchConfig::new(PAY_TO, "localnet", Arc::new(signer)); + config.withdraw_delay = 3600; + config.rpc_url = Some(url); + let store = Arc::new(MemoryChannelStore::new()); + let handler = X402BatchSettlement::with_store(config, store.clone()).unwrap(); + let requirements = handler.requirements("0.001").unwrap(); + let (_, client_config, channel) = client(&fee_payer, &requirements); + let channel_b58 = pc::pubkey_string(&channel); + let mut seeded = handler.seed_state(&channel_b58, &client_config); + if let Some(sealed_at) = sealed_at { + seeded + .extra + .insert(SEALED_AT_KEY.to_string(), sealed_at.into()); + } + store.put_channel(&channel_b58, seeded).await.unwrap(); + // 4_000 of the 5_000 deposit is due back to the payer; the + // closing channel is past its grace deadline. + let mut onchain = onchain_channel(&client_config, &fee_payer, 5_000); + onchain.status = status; + onchain.settlement.settled = 1_000; + onchain.closure_started_at = 1; + let mint = handler.mint().unwrap(); + let token_program = handler.token_program().unwrap(); + let payer = pc::from_address(&onchain.payer); + let mut token_account = vec![0u8; 165]; + token_account[..32].copy_from_slice(mint.as_ref()); + token_account[32..64].copy_from_slice(payer.as_ref()); + token_account[108] = 1; + let account = |data: &[u8], owner: &Pubkey| { + serde_json::json!({ + "context": { "slot": 1 }, + "value": { + "lamports": 1_000_000, + "data": [base64::engine::general_purpose::STANDARD.encode(data), "base64"], + "owner": pc::pubkey_string(owner), + "executable": false, + "rentEpoch": 0, + "space": data.len(), + } + }) + }; + let mut mocks = solana_rpc_client::mock_sender::MocksMap::default(); + mocks.insert( + RpcRequest::GetAccountInfo, + account(&borsh::to_vec(&onchain).unwrap(), &pc::default_program_id()), + ); + mocks.insert( + RpcRequest::GetAccountInfo, + if payable { + account(&token_account, &token_program) + } else { + serde_json::json!({ "context": { "slot": 1 }, "value": null }) + }, + ); + let handler = handler.with_rpc_client(RpcClient::new_mock_with_mocks_map( + "succeeds".to_string(), + mocks, + )); + + handler + .finalize_close(std::slice::from_ref(&channel_b58)) + .await + .unwrap(); + let program_id = pc::default_program_id(); + let sent = sent.lock().unwrap().clone(); + let distributes = sent + .iter() + .flatten() + .filter(|program| **program == program_id) + .count(); + rpc.abort(); + let recorded = store + .get_channel(&channel_b58) + .await + .unwrap() + .and_then(|state| state.extra.get(SEALED_AT_KEY)?.as_i64()); + (distributes, recorded) + } + } + + #[tokio::test(flavor = "multi_thread")] + async fn finalize_close_never_distributes_into_an_unusable_refund_account() { + // (on-chain status, payer refund account usable) → programs invoked. + for (status, payable) in [ + (CHANNEL_STATUS_SEALED, false), + (CHANNEL_STATUS_SEALED, true), + (CHANNEL_STATUS_CLOSING, false), + (CHANNEL_STATUS_CLOSING, true), + ] { + let (distributes, sealed_at) = finalize_close_once(status, payable, None).await; + let expected = match (status, payable) { + // Already sealed: distribute only, or nothing this pass. + (CHANNEL_STATUS_SEALED, true) => 1, + (CHANNEL_STATUS_SEALED, false) => 0, + // Closing: seal + distribute, or the seal alone. + (_, true) => 2, + (_, false) => 1, + }; + assert_eq!(distributes, expected, "status {status}, payable {payable}"); + // The seal time a deferred distribute's deadline counts from. + let now = now_unix() as i64; + assert!( + sealed_at.is_some_and(|at| now - at <= 1), + "status {status}, payable {payable}: {sealed_at:?}" + ); + } + } + + /// A deferred distribute is retried on every later pass and, once the + /// channel has been sealed for its grace period, sent anyway: a payer + /// keeping its refund account unusable cannot hold the payout. The first + /// seal time recorded is kept. + #[tokio::test(flavor = "multi_thread")] + async fn a_deferred_distribute_runs_once_the_grace_period_after_the_seal_ends() { + let now = now_unix() as i64; + // Grace 3600 s: inside it the distribute still waits. The margin + // keeps a slow run from crossing the deadline between `now` here and + // the check in `finalize_close`. + let inside = now - 3_000; + assert_eq!( + finalize_close_once(CHANNEL_STATUS_SEALED, false, Some(inside)).await, + (0, Some(inside)) + ); + let past = now - 3_600; + assert_eq!( + finalize_close_once(CHANNEL_STATUS_SEALED, false, Some(past)).await, + (1, Some(past)) + ); + // Positive control: a payable account distributes inside the grace. + assert_eq!( + finalize_close_once(CHANNEL_STATUS_SEALED, true, Some(inside)) + .await + .0, + 1 + ); + } + /// A replayed opening deposit for a channel the chain already holds, sent /// to a store that has no record of it (a restart over the in-memory /// store), is refused instead of seeding a zero watermark that would serve @@ -6002,6 +6535,242 @@ mod tests { assert!(!err.to_string().contains("has no record"), "{err}"); } + /// One channel whose settlement fails on-chain fails the transaction it + /// was packed into; the other channels are submitted again alone and + /// land, and only the failing one is reported. + #[tokio::test(flavor = "multi_thread")] + async fn a_failing_channel_does_not_fail_the_channels_packed_with_it() { + use axum::{routing::post, Json, Router}; + use std::collections::HashSet; + use std::sync::Mutex as StdMutex; + + #[derive(Clone, Default)] + struct Chain { + poison: Arc>>, + failing: Arc>>, + sends: Arc>>, + } + async fn rpc( + axum::extract::State(chain): axum::extract::State, + Json(request): Json, + ) -> Json { + let result = match request["method"].as_str().unwrap_or_default() { + "getLatestBlockhash" => serde_json::json!({ + "context": { "slot": 1 }, + "value": { + "blockhash": solana_hash::Hash::new_unique().to_string(), + "lastValidBlockHeight": 100 + } + }), + "sendTransaction" => { + let tx = + crate::core::tx::decode(request["params"][0].as_str().unwrap()).unwrap(); + let signature = tx.signatures[0].to_string(); + chain + .sends + .lock() + .unwrap() + .push(tx.message.instructions().len()); + let poison = *chain.poison.lock().unwrap(); + if poison.is_some_and(|p| tx.message.static_account_keys().contains(&p)) { + chain.failing.lock().unwrap().insert(signature.clone()); + } + serde_json::json!(signature) + } + "getSignatureStatuses" => { + let failing = chain.failing.lock().unwrap().clone(); + let values: Vec<_> = request["params"][0] + .as_array() + .unwrap() + .iter() + .map(|sig| { + let err = failing + .contains(sig.as_str().unwrap()) + .then(|| serde_json::json!({ "InstructionError": [0, { "Custom": 1 }] })); + serde_json::json!({ + "slot": 1, + "confirmations": null, + "err": err, + "status": match &err { Some(e) => serde_json::json!({ "Err": e }), None => serde_json::json!({ "Ok": null }) }, + "confirmationStatus": "confirmed" + }) + }) + .collect(); + serde_json::json!({ "context": { "slot": 1 }, "value": values }) + } + other => panic!("unexpected RPC method {other}"), + }; + Json(serde_json::json!({ "jsonrpc": "2.0", "id": request["id"], "result": result })) + } + + let chain = Chain::default(); + let app = Router::new() + .route("/", post(rpc)) + .with_state(chain.clone()); + let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap(); + let url = format!("http://{}", listener.local_addr().unwrap()); + tokio::spawn(async move { axum::serve(listener, app).await.unwrap() }); + let pipeline = TxPipeline::new( + url, + TxPipelineConfig { + batch_coalesce_interval: std::time::Duration::from_millis(10), + confirmation_poll_interval: std::time::Duration::from_millis(10), + confirmation_timeout: std::time::Duration::from_secs(2), + ..TxPipelineConfig::default() + }, + ); + let key = SigningKey::from_bytes(&[21u8; 32]); + let mut keypair = [0u8; 64]; + keypair[..32].copy_from_slice(key.as_bytes()); + keypair[32..].copy_from_slice(key.verifying_key().as_bytes()); + let signer = solana_keychain::MemorySigner::from_bytes(&keypair).unwrap(); + let handler = X402BatchSettlement::with_store( + BatchConfig::new(PAY_TO, "localnet", Arc::new(signer)), + Arc::new(MemoryChannelStore::new()), + ) + .unwrap() + .with_tx_pipeline(pipeline); + let groups = |accounts: &[Pubkey]| -> Vec { + accounts + .iter() + .map(|account| ChannelInstructionGroup { + channel_id: pc::pubkey_string(account), + instructions: vec![Instruction::new_with_bytes( + Pubkey::new_unique(), + &[0], + vec![solana_instruction::AccountMeta::new(*account, false)], + )], + }) + .collect() + }; + let accounts: Vec = (0..3).map(|_| Pubkey::new_unique()).collect(); + *chain.poison.lock().unwrap() = Some(accounts[1]); + + let err = handler + .submit_groups(groups(&accounts), MAX_CLAIMS_PER_BATCH) + .await + .expect_err("the failing channel is reported"); + assert!(err.to_string().contains("1 of 3"), "{err}"); + // The packed attempt, then one transaction per channel. + assert_eq!(chain.sends.lock().unwrap().clone(), vec![3, 1, 1, 1]); + + // Positive control: without a failing channel the pack lands as one. + *chain.poison.lock().unwrap() = None; + chain.sends.lock().unwrap().clear(); + let accounts: Vec = (0..3).map(|_| Pubkey::new_unique()).collect(); + let signatures = handler + .submit_groups(groups(&accounts), MAX_CLAIMS_PER_BATCH) + .await + .unwrap(); + assert_eq!(signatures.len(), 1); + assert_eq!(chain.sends.lock().unwrap().clone(), vec![3]); + } + + /// A deposit is broadcast only after the handler runs, so one that cannot + /// land (an expired blockhash, a payer short of the deposit) is refused + /// before the handler, and a failed read refuses too. + /// A retry of a deposit already committed skips the landing check like a + /// pending one: its funds moved, so a balance read now would refuse it. + #[test] + fn a_committed_deposit_retry_skips_the_landing_check() { + let (handler, fee_payer) = handler(Arc::new(MemoryChannelStore::new())); + let requirements = handler.requirements("0.001").unwrap(); + let (_, config, channel) = client(&fee_payer, &requirements); + let mut state = seeded(&channel, &config, 5_000, 0); + state.processed_topup_signatures = vec!["committed".to_string()]; + assert!(deposit_already_recorded(Some(&state), Some("committed"))); + // Positive controls: an unknown deposit, or none at all, is checked. + assert!(!deposit_already_recorded(Some(&state), Some("fresh"))); + assert!(!deposit_already_recorded(None, Some("committed"))); + assert!(!deposit_already_recorded(Some(&state), None)); + state.processed_topup_signatures.clear(); + assert!(!deposit_already_recorded(Some(&state), Some("committed"))); + } + + #[tokio::test(flavor = "multi_thread")] + async fn a_deposit_that_cannot_land_is_refused_before_serving() { + use base64::Engine as _; + let (probe, fee_payer) = handler(Arc::new(MemoryChannelStore::new())); + let (payer, mint, token_program) = ( + Pubkey::new_unique(), + probe.mint().unwrap(), + probe.token_program().unwrap(), + ); + let tx = VersionedTransaction { + signatures: vec![solana_signature::Signature::default()], + message: solana_message::VersionedMessage::V0( + solana_message::v0::Message::try_compile( + &fee_payer, + &[], + &[], + solana_hash::Hash::new_unique(), + ) + .unwrap(), + ), + }; + let chain = |live: bool, balance: u64| { + let mut data = vec![0u8; 165]; + data[..32].copy_from_slice(mint.as_ref()); + data[32..64].copy_from_slice(payer.as_ref()); + data[64..72].copy_from_slice(&balance.to_le_bytes()); + data[108] = 1; + let mut mocks = std::collections::HashMap::new(); + mocks.insert( + solana_rpc_client_api::request::RpcRequest::IsBlockhashValid, + serde_json::json!({ "context": { "slot": 1 }, "value": live }), + ); + mocks.insert( + solana_rpc_client_api::request::RpcRequest::GetAccountInfo, + serde_json::json!({ + "context": { "slot": 1 }, + "value": { + "lamports": 2_039_280, + "data": [base64::engine::general_purpose::STANDARD.encode(&data), "base64"], + "owner": pc::pubkey_string(&token_program), + "executable": false, + "rentEpoch": 0, + "space": 165, + } + }), + ); + let (handler, _) = handler(Arc::new(MemoryChannelStore::new())); + handler.with_rpc_client(RpcClient::new_mock_with_mocks( + "succeeds".to_string(), + mocks, + )) + }; + let check = |handler: X402BatchSettlement| { + let tx = tx.clone(); + async move { + handler + .check_deposit_can_land(&tx, &payer, &mint, &token_program, 5_000) + .await + } + }; + let refused = |result: Result<(), Error>, detail: &str| { + let err = result.expect_err(detail); + assert_eq!( + crate::x402::protocol::schemes::batch_settlement::classify(&err.to_string()), + codes::INVALID_SETTLEMENT_SIMULATION, + "{err}" + ); + assert!(err.to_string().contains(detail), "{err}"); + }; + + refused( + check(chain(true, 4_999)).await, + "less than the 5000 deposit", + ); + refused(check(chain(false, 5_000)).await, "is not live"); + let (unreachable, _) = handler(Arc::new(MemoryChannelStore::new())); + let unreachable = unreachable.with_rpc_client(RpcClient::new_mock("fails".to_string())); + refused(check(unreachable).await, "blockhash check failed"); + // Positive control: a live blockhash and exactly the deposit. + check(chain(true, 5_000)) + .await + .expect("a fundable deposit passes"); + } + /// Channel reads run off the async worker. The blocking RPC client parks /// its calling thread (`block_in_place`, which a current-thread runtime /// refuses outright), so a read made inline from async verification would diff --git a/rust/crates/kit/src/x402/server/upto.rs b/rust/crates/kit/src/x402/server/upto.rs index 6e6f3d8e3..4f84fdee5 100644 --- a/rust/crates/kit/src/x402/server/upto.rs +++ b/rust/crates/kit/src/x402/server/upto.rs @@ -31,6 +31,10 @@ use solana_pubkey::Pubkey; use solana_rpc_client::rpc_client::RpcClient; use solana_transaction::versioned::VersionedTransaction; +use crate::core::payment_channel::payer_refund::{ + payer_refund, DistributeClearance, ObservedAccount, PayerRefund, RefundDeadline, + SealedRefundTerms, +}; use crate::core::payment_channels as pc; use crate::core::payment_channels::generated::accounts::Channel; use crate::core::tx::{TxV1Mode, TxVersion}; @@ -67,7 +71,8 @@ const MIN_SETTLEMENT_VOUCHER_TTL_SECONDS: u64 = 60; pub struct UptoConfig { /// Where settled funds go. The channel payee is always the fee payer /// (zero-share seat); this only decides which beneficiary the bound 100% - /// distribution split pays. + /// distribution split pays. That beneficiary's token account for each + /// offered currency must already exist: opens are refused until it does. pub payout: UptoPayout, /// Non-empty universe of currencies this server offers and accepts. `[0]` /// is the primary/default currency. The `upto` challenge advertises one @@ -734,6 +739,7 @@ impl X402Upto { expires_at, in_flight, } = self.prepare_open(header, &offered, now_unix())?; + self.ensure_payouts_ready(&expected_mint, &token_program, &expected_distribution)?; self.cosign_fee_payer(&mut tx).await?; crate::core::rpc::send_and_confirm_transaction(&self.rpc, &tx) .map_err(|e| Error::Rpc(format!("open broadcast failed: {e}")))?; @@ -914,42 +920,28 @@ impl X402Upto { /// data, not as a transaction signature — so the worker can sign the /// envelope on the caller's behalf. /// - /// When the payer has closed its token account since the open, the - /// `distribute` that refunds it would fail and take the charge down with - /// it, so only `settle_and_seal` is emitted: the charge is locked onchain - /// and the permissionless `distribute` pays both sides once the payer - /// recreates the account to collect its refund. The account is never - /// recreated at the fee payer's expense, which the payer could farm. + /// The bundle ends in `distribute`, which pays `payTo`, refunds the + /// payer, closes the escrow token account to the fee payer and leaves the + /// channel for `reclaim`. When a refund is due and the payer's token + /// account can no longer take it (closed or frozen since the open), the + /// program would forfeit the refund to the treasury, so the bundle only + /// seals and the distribute is deferred to + /// [`distribute_sealed`](Self::distribute_sealed), which runs it once the + /// account is usable, the payer withdrew, or the grace period after the + /// open has passed. The account is never recreated at the fee payer's + /// expense, which the payer could farm. pub async fn settlement_instructions( &self, open: &VerifiedUptoOpen, actual: u64, ) -> Result, Error> { - let (payer_token, _) = - pc::find_associated_token_address(&open.payer, &open.mint, &open.token_program); - // Only a confirmed absence drops `distribute`; on an RPC error the - // atomic transaction itself is the safeguard. - let distribute = !matches!( - self.rpc - .get_account_with_commitment(&payer_token, self.rpc.commitment()) - .map(|response| response.value), - Ok(None) - ); - if !distribute { - tracing::warn!( - channel = %open.channel_id, - "upto payer token account is gone; sealing the charge without distributing" - ); - } - self.build_settlement_instructions(open, actual, distribute) - .await + self.build_settlement_instructions(open, actual).await } async fn build_settlement_instructions( &self, open: &VerifiedUptoOpen, actual: u64, - distribute: bool, ) -> Result, Error> { assert_settlement_within_ceiling(actual, open.max_amount)?; // The voucher is signed by this server, so its deadline is chosen here @@ -990,45 +982,321 @@ impl X402Upto { )? }; - if !distribute { + let now = now_unix(); + let decision = self + .sealed_refund( + &open.channel_id, + SealedRefundTerms { + channel: open.channel_id, + payer: open.payer, + mint: open.mint, + token_program: open.token_program, + deposit: open.deposit, + settled: actual, + payer_withdrawn_at: 0, + }, + // This bundle seals the channel now. + now, + now, + ) + .await?; + let Some(clearance) = decision.clearance() else { return Ok(instructions); - } - let payee = open.payee; - instructions.push(pc::build_create_associated_token_account_instruction( - &self.fee_payer, - &payee, - &open.mint, - &open.token_program, - )); - instructions.push(pc::build_create_associated_token_account_instruction( - &self.fee_payer, - &self.treasury_owner(), - &open.mint, - &open.token_program, - )); - for entry in &open.distribution { - instructions.push(pc::build_create_associated_token_account_instruction( - &self.fee_payer, - &entry.recipient, - &open.mint, - &open.token_program, - )); - } - instructions.push(pc::build_distribute_instruction( - &open.channel_id, + }; + instructions.extend(self.distribute_instructions( + &clearance, &open.payer, &open.rent_payer, - &payee, - &self.treasury_owner(), &open.mint, &open.distribution, &open.token_program, &open.program_id, )); - Ok(instructions) } + /// The payout of a sealed channel this server holds the payee seat of: + /// its own and the treasury's token accounts, then `distribute`. Built + /// only under a [`DistributeClearance`]. + #[allow(clippy::too_many_arguments)] + fn distribute_instructions( + &self, + clearance: &DistributeClearance, + payer: &Pubkey, + rent_payer: &Pubkey, + mint: &Pubkey, + distribution: &[pc::Distribution], + token_program: &Pubkey, + program_id: &Pubkey, + ) -> Vec { + let channel = clearance.channel(); + // Recipient accounts were required to exist before the open + // (`ensure_payouts_ready`) and are never created here: the fee payer + // would fund an account its owner can close for the rent. + vec![ + pc::build_create_associated_token_account_instruction( + &self.fee_payer, + &self.fee_payer, + mint, + token_program, + ), + pc::build_create_associated_token_account_instruction( + &self.fee_payer, + &self.treasury_owner(), + mint, + token_program, + ), + pc::build_distribute_instruction( + channel, + payer, + rent_payer, + &self.fee_payer, + &self.treasury_owner(), + mint, + distribution, + token_program, + program_id, + ), + ] + } + + /// What the sealed `distribute` of `channel` may do (see + /// [`payer_refund`]), reading the payer's refund account when a refund + /// is due. The deadline counts `withdraw_delay` from `sealed_at`. + async fn sealed_refund( + &self, + channel: &Pubkey, + terms: SealedRefundTerms, + sealed_at: i64, + now: i64, + ) -> Result { + let deadline = RefundDeadline { + sealed_at, + grace_period: self.config.withdraw_delay, + }; + if terms.refund_due() == 0 { + return Ok(payer_refund(&terms, None, deadline, now)); + } + let address = terms.payer_token_account(); + let rpc = Arc::clone(&self.rpc); + let account = tokio::task::spawn_blocking(move || { + rpc.get_account_with_commitment(&address, rpc.commitment()) + }) + .await + .map_err(|e| Error::Other(format!("payer refund account read task failed: {e}")))? + .map_err(|e| Error::Rpc(format!("payer refund account {address}: {e}")))? + .value; + let observed = account.as_ref().map(|account| ObservedAccount { + owner: pc::from_address(&account.owner), + data: &account.data, + }); + let decision = payer_refund(&terms, observed, deadline, now); + match &decision { + PayerRefund::Clear(_) => {} + PayerRefund::Deferred { + refund, + payer_token_account, + reason, + until, + } => tracing::warn!( + channel = %channel, + %payer_token_account, + refund, + reason, + until, + "payer refund account cannot be paid; sealing without distributing until it \ + can, or until the deadline (distribute_sealed)" + ), + PayerRefund::Forfeit { + refund, + payer_token_account, + reason, + .. + } => tracing::warn!( + channel = %channel, + %payer_token_account, + refund, + reason, + "payer refund account still unusable past the deadline; distributing, the \ + refund goes to the treasury" + ), + } + Ok(decision) + } + + /// Distribute the sealed channels this server holds the payee seat of + /// whose distribute a settlement deferred (see + /// [`settlement_instructions`](Self::settlement_instructions)), and + /// return the confirmed signatures. + /// + /// The chain is the work queue: channels are discovered by + /// `rent_payer == payee == fee payer` and accepted only when their PDA + /// rederives and their distribution is this server's, so no local state + /// is needed and nothing is lost on restart. A channel is distributed as + /// soon as the payer's refund account can take its refund (or the payer + /// withdrew it), and once `withdraw_delay` has passed since the channel's + /// open, anyway: the program then sends the refund to the treasury, and + /// a payer can never hold the payout and the fee payer's rent hostage. + /// The program records no seal time; an `upto` channel is sealed by the + /// settlement of the request that opened it, so the open's block time + /// stands in for it. + /// + /// Run it periodically, like `reclaim` for other channel schemes. + pub async fn distribute_sealed(&self) -> Result, Error> { + let program_id = self.program_id()?; + let distribution = self.distribution()?; + let distribution_hash = pc::distribution_hash(&distribution); + let sealed = crate::core::payment_channels::generated::types::ChannelStatus::Sealed as u8; + let mut signatures = Vec::new(); + for (channel_id, channel) in self.sealed_channel_candidates(&program_id).await? { + if channel.status != sealed + || pc::from_address(&channel.payee) != self.fee_payer + || channel.distribution_hash != distribution_hash + { + continue; + } + let mint = pc::from_address(&channel.mint); + let Some(token_program) = self + .config + .currencies + .iter() + .find(|cc| self.mint_for(cc).is_ok_and(|candidate| candidate == mint)) + .map(|cc| self.token_program_for(cc)) + .transpose()? + else { + continue; + }; + let rpc = Arc::clone(&self.rpc); + let open_slot = channel.open_slot; + let opened_at = match tokio::task::spawn_blocking(move || rpc.get_block_time(open_slot)) + .await + .map_err(|e| Error::Other(format!("block time read task failed: {e}")))? + { + Ok(time) => time, + Err(error) => { + tracing::warn!(channel = %channel_id, %error, "open block time unavailable; skipping"); + continue; + } + }; + let payer = pc::from_address(&channel.payer); + let decision = self + .sealed_refund( + &channel_id, + SealedRefundTerms { + channel: channel_id, + payer, + mint, + token_program, + deposit: channel.deposit, + settled: channel.settlement.settled, + payer_withdrawn_at: channel.payer_withdrawn_at, + }, + opened_at, + now_unix(), + ) + .await?; + let Some(clearance) = decision.clearance() else { + continue; + }; + let instructions = self.distribute_instructions( + &clearance, + &payer, + &pc::from_address(&channel.rent_payer), + &mint, + &distribution, + &token_program, + &program_id, + ); + let blockhash = self + .rpc + .get_latest_blockhash() + .map_err(|e| Error::Rpc(format!("blockhash fetch failed: {e}")))?; + let mut tx = crate::core::tx::build_unsigned( + self.tx_version(), + &self.fee_payer, + &instructions, + blockhash, + None, + )?; + self.sign_settlement_transaction(&mut tx).await?; + match crate::core::rpc::send_and_confirm_with_outcome( + &self.rpc, + &tx, + crate::core::rpc::PriorBroadcast::None, + ) { + Ok(signature) => signatures.push(signature.to_string()), + Err(failure) => { + tracing::warn!(channel = %channel_id, %failure, "deferred distribute failed"); + } + } + } + Ok(signatures) + } + + /// Channels whose rent this server's fee payer put up, PDA-checked. + async fn sealed_channel_candidates( + &self, + program_id: &Pubkey, + ) -> Result, Error> { + use solana_rpc_client_api::config::{ + RpcAccountInfoConfig, RpcProgramAccountsConfig, UiAccountEncoding, + }; + use solana_rpc_client_api::filter::{Memcmp, RpcFilterType}; + use solana_rpc_client_api::request::RpcRequest; + use solana_rpc_client_api::response::RpcKeyedAccount; + + let config = RpcProgramAccountsConfig { + filters: Some(vec![ + RpcFilterType::DataSize(pc::CHANNEL_ACCOUNT_SIZE as u64), + RpcFilterType::Memcmp(Memcmp::new_raw_bytes( + pc::CHANNEL_RENT_PAYER_OFFSET, + self.fee_payer.to_bytes().to_vec(), + )), + RpcFilterType::Memcmp(Memcmp::new_raw_bytes( + pc::CHANNEL_PAYEE_OFFSET, + self.fee_payer.to_bytes().to_vec(), + )), + ]), + account_config: RpcAccountInfoConfig { + encoding: Some(UiAccountEncoding::Base64), + ..Default::default() + }, + ..Default::default() + }; + let params = serde_json::json!([program_id.to_string(), config]); + let rpc = Arc::clone(&self.rpc); + let keyed: Vec = + tokio::task::spawn_blocking(move || rpc.send(RpcRequest::GetProgramAccounts, params)) + .await + .map_err(|e| Error::Other(format!("channel discovery task failed: {e}")))? + .map_err(|e| Error::Rpc(format!("getProgramAccounts failed: {e}")))?; + let mut found = Vec::new(); + for entry in keyed { + let Ok(address) = Pubkey::from_str(&entry.pubkey) else { + continue; + }; + let Some(data) = entry.account.data.decode() else { + continue; + }; + let Ok(channel) = Channel::from_bytes(&data) else { + continue; + }; + let (derived, _) = pc::find_channel_pda( + &pc::from_address(&channel.payer), + &pc::from_address(&channel.payee), + &pc::from_address(&channel.mint), + &pc::from_address(&channel.authorized_signer), + channel.salt, + channel.open_slot, + program_id, + ); + if derived == address { + found.push((address, channel)); + } + } + Ok(found) + } + /// Build the `PAYMENT-RESPONSE` receipt for a settled `actual` amount and /// its broadcast `signature`. Pure: pairs the settle signature (inline or /// worker-provided) with the open's payer/network. @@ -1210,6 +1478,54 @@ impl X402Upto { Ok(()) } + /// Phase 3 step 8, settlement readiness: every distribution recipient's + /// token account must already exist and be usable before the deposit is + /// escrowed. Settlement never creates them at the fee payer's expense + /// (an owner could close and recreate the account to collect that rent), + /// and the program forfeits a payout to an unusable account. A failed + /// read is a refusal too. + fn ensure_payouts_ready( + &self, + mint: &Pubkey, + token_program: &Pubkey, + distribution: &[pc::Distribution], + ) -> Result<(), Error> { + // The fee payer's own account is the payee seat settlement creates + // itself; only accounts of other owners must already exist. + for entry in distribution + .iter() + .filter(|entry| entry.recipient != self.fee_payer) + { + let (ata, _) = pc::find_associated_token_address(&entry.recipient, mint, token_program); + let account = self + .rpc + .get_account_with_commitment(&ata, self.rpc.commitment()) + .map_err(|e| Error::Rpc(format!("payout token account read failed: {e}")))? + .value; + let problem = match account { + None => Some("does not exist".to_string()), + Some(account) => { + crate::x402::server::batch_settlement::unusable_settlement_account( + &pc::from_address(&account.owner), + &account.data, + &entry.recipient, + mint, + token_program, + ) + } + }; + if let Some(problem) = problem { + return Err(Error::Other(format!( + "payout token account {} of {} {problem}; it must be an initialized \ + token account before payments settle to it", + pc::pubkey_string(&ata), + pc::pubkey_string(&entry.recipient) + ))); + } + } + Ok(()) + } + fn fetch_channel(&self, channel_id: &Pubkey) -> Result { let data = self .rpc @@ -1245,7 +1561,8 @@ pub mod testkit { /// The checks [`X402Upto::verify_open_for_route`] runs before it /// broadcasts the open, at an explicit `now` (Unix seconds) and with the /// route's maximum already in base units, co-signature included (on a - /// local copy). `Ok` means the production path would go on to broadcast. + /// local copy). `Ok` means the production path would go on to its + /// settlement-readiness reads (`ensure_payouts_ready`) and broadcast. pub async fn verify_open_pre_broadcast( server: &X402Upto, header: &str, @@ -1602,6 +1919,7 @@ pub(crate) fn validate_open_instruction( pc::MAX_COMPUTE_UNIT_PRICE_MICROLAMPORTS, crate::core::tx::LoadedDataLimitRule::Present, )?; + crate::core::tx::reject_v1_heap_request(&tx.message)?; let keys = tx.message.static_account_keys(); let ix = find_canonical_open_instruction(tx, keys, program_id, expected_memo)?; @@ -2497,17 +2815,58 @@ mod tests { ]) .is_err()); assert!(validate_layout(&[ + cu_limit_ix(1), cu_price_ix(pc::MAX_COMPUTE_UNIT_PRICE_MICROLAMPORTS), open_placeholder() ]) .is_ok()); assert!(validate_layout(&[ + cu_limit_ix(1), cu_price_ix(pc::MAX_COMPUTE_UNIT_PRICE_MICROLAMPORTS + 1), open_placeholder() ]) .is_err()); } + #[test] + fn bounds_the_priority_fee_the_operator_pays() { + let over_fee_cap = |result: Result<(), Error>| { + result.is_err_and(|e| e.to_string().contains("exceeds the sponsored fee maximum")) + }; + // Both fields at their ceilings: 400,000 x 5 lamports. + assert!(over_fee_cap(validate_layout(&[ + cu_limit_ix(pc::OPEN_MAX_COMPUTE_UNIT_LIMIT), + cu_price_ix(pc::MAX_COMPUTE_UNIT_PRICE_MICROLAMPORTS), + open_placeholder(), + ]))); + // The same price with no declared limit is charged on the runtime + // default for each of the five non-budget instructions. + assert!(over_fee_cap(validate_layout(&[ + cu_price_ix(pc::MAX_COMPUTE_UNIT_PRICE_MICROLAMPORTS), + open_placeholder(), + lighthouse_ix(), + lighthouse_ix(), + lighthouse_ix(), + memo_ix("x"), + ]))); + // Exactly the sponsored maximum, declared or implied. + let at_cap = crate::core::tx::MAX_SPONSORED_PRIORITY_FEE_LAMPORTS * 1_000_000 + / u64::from(pc::OPEN_MAX_COMPUTE_UNIT_LIMIT); + assert!(validate_layout(&[ + cu_limit_ix(pc::OPEN_MAX_COMPUTE_UNIT_LIMIT), + cu_price_ix(at_cap), + open_placeholder(), + ]) + .is_ok()); + // Two non-budget instructions imply the same 400,000 unit limit. + assert!(validate_layout(&[cu_price_ix(at_cap), open_placeholder(), memo_ix("x")]).is_ok()); + assert!(over_fee_cap(validate_layout(&[ + cu_price_ix(at_cap + 1), + open_placeholder(), + memo_ix("x"), + ]))); + } + #[test] fn rejects_an_over_long_or_unknown_suffix() { // A fourth Lighthouse assertion is past what either wallet injects. @@ -2799,13 +3158,19 @@ mod tests { /// up in the settlement voucher: the server signs its own deadline. #[tokio::test] async fn settlement_voucher_deadline_is_server_derived() { - let engine = multi_currency_engine(&["USDC"]); + let mut engine = multi_currency_engine(&["USDC"]); let mut open = engine.test_open(Pubkey::new_unique(), 1_000); + // The payer's refund account is usable, so settlement distributes. + engine.rpc = engine_reading( + token_account_json(&open.mint, &open.payer, &open.token_program), + vec![], + ) + .rpc; let now = now_unix(); open.expires_at = now + 1; let instructions = engine - .build_settlement_instructions(&open, 400, true) + .build_settlement_instructions(&open, 400) .await .unwrap(); let expiry = settled_voucher_expiry(&instructions, &open, 400); @@ -2816,7 +3181,7 @@ mod tests { open.expires_at = now - 10; let instructions = engine - .build_settlement_instructions(&open, 400, true) + .build_settlement_instructions(&open, 400) .await .unwrap(); assert!(settled_voucher_expiry(&instructions, &open, 400) > now); @@ -2888,36 +3253,279 @@ mod tests { assert!(match_offered_requirement(std::slice::from_ref(&a), &accepted_a).is_ok()); } - /// A payer that closed its token account after the open cannot make the - /// settlement fail as a whole: the charge is sealed without the refund. + /// The fee payer funds no account a distribution recipient owns: the + /// recipient could close it after each settlement and keep the rent. #[tokio::test] - async fn settlement_without_a_payer_account_still_seals_the_charge() { - let engine = multi_currency_engine(&["USDC"]); + async fn settlement_never_creates_a_recipient_account() { + let mut engine = multi_currency_engine(&["USDC"]); + let open = engine.test_open(Pubkey::new_unique(), 1_000); + // The payer's refund account is usable, so settlement distributes. + engine.rpc = engine_reading( + token_account_json(&open.mint, &open.payer, &open.token_program), + vec![], + ) + .rpc; + let created_for = |ixs: &[Instruction]| -> Vec { + ixs.iter() + .filter(|ix| ix.program_id == pc::associated_token_program_id()) + .map(|ix| ix.accounts[2].pubkey) + .collect() + }; + for actual in [0, 400, 1_000] { + let ixs = engine + .build_settlement_instructions(&open, actual) + .await + .unwrap(); + let created = created_for(&ixs); + for entry in &open.distribution { + assert!(!created.contains(&entry.recipient), "actual {actual}"); + } + // Positive control: the fee payer's own seat and the treasury. + assert!(created.contains(&engine.fee_payer)); + assert!(created.contains(&engine.treasury_owner())); + } + } + + #[test] + fn an_open_is_refused_until_every_payout_account_is_usable() { + let engine = |rpc: RpcClient| { + let mut engine = multi_currency_engine(&["USDC"]); + engine.rpc = Arc::new(rpc); + engine + }; + let answering = |value: serde_json::Value| { + let mut mocks = std::collections::HashMap::new(); + mocks.insert( + solana_rpc_client_api::request::RpcRequest::GetAccountInfo, + serde_json::json!({ "context": { "slot": 1 }, "value": value }), + ); + RpcClient::new_mock_with_mocks("succeeds".to_string(), mocks) + }; + let probe = multi_currency_engine(&["USDC"]); + let usdc = &probe.config.currencies[0]; + let (mint, token_program) = ( + probe.mint_for(usdc).unwrap(), + probe.token_program_for(usdc).unwrap(), + ); + let distribution = probe.distribution().unwrap(); + let recipient = distribution[0].recipient; + let token_account = |state: u8| { + use base64::Engine as _; + let mut data = vec![0u8; 165]; + data[..32].copy_from_slice(mint.as_ref()); + data[32..64].copy_from_slice(recipient.as_ref()); + data[108] = state; + serde_json::json!({ + "lamports": 2_039_280, + "data": [base64::engine::general_purpose::STANDARD.encode(&data), "base64"], + "owner": pc::pubkey_string(&token_program), + "executable": false, + "rentEpoch": 0, + "space": 165, + }) + }; + let check = + |engine: X402Upto| engine.ensure_payouts_ready(&mint, &token_program, &distribution); + + let err = check(engine(answering(serde_json::Value::Null))).unwrap_err(); + assert!(err.to_string().contains("does not exist"), "{err}"); + let err = check(engine(answering(token_account(2)))).unwrap_err(); + assert!(err.to_string().contains("frozen"), "{err}"); + assert!(check(engine(RpcClient::new_mock("fails".to_string()))).is_err()); + // Positive control: an initialized account of the recipient. + check(engine(answering(token_account(1)))).expect("usable payout account"); + // The default payout to the fee payer itself (`ReceiverKeepsAll` with + // no separate receiver authorizer) needs no account up front: + // settlement creates the fee payer's own seat. + let own = engine(answering(serde_json::Value::Null)); + let to_fee_payer = [pc::Distribution { + recipient: own.fee_payer, + bps: 10_000, + }]; + own.ensure_payouts_ready(&mint, &token_program, &to_fee_payer) + .expect("the fee payer's own payout needs no account yet"); + } + + /// The engine with its RPC answering `getAccountInfo` (the payer's refund + /// account) with `refund_account`, plus `extra` mocks. + fn engine_reading( + refund_account: serde_json::Value, + extra: Vec<( + solana_rpc_client_api::request::RpcRequest, + serde_json::Value, + )>, + ) -> X402Upto { + let mut engine = multi_currency_engine(&["USDC"]); + // A mock answers each request once: queue one answer per read. + let mut mocks = solana_rpc_client::mock_sender::MocksMap::default(); + for _ in 0..8 { + mocks.insert( + solana_rpc_client_api::request::RpcRequest::GetAccountInfo, + serde_json::json!({ "context": { "slot": 1 }, "value": refund_account }), + ); + } + for (request, value) in extra { + mocks.insert(request, value); + } + engine.rpc = Arc::new(RpcClient::new_mock_with_mocks_map( + "succeeds".to_string(), + mocks, + )); + engine + } + + /// A token account of `owner` for `mint`, as `getAccountInfo` returns it. + fn token_account_json( + mint: &Pubkey, + owner: &Pubkey, + token_program: &Pubkey, + ) -> serde_json::Value { + use base64::Engine as _; + let mut data = vec![0u8; 165]; + data[..32].copy_from_slice(mint.as_ref()); + data[32..64].copy_from_slice(owner.as_ref()); + data[108] = 1; + serde_json::json!({ + "lamports": 2_039_280, + "data": [base64::engine::general_purpose::STANDARD.encode(&data), "base64"], + "owner": pc::pubkey_string(token_program), + "executable": false, + "rentEpoch": 0, + "space": 165, + }) + } + + /// A payer that closed its token account after the open would have its + /// refund forfeited to the treasury by `distribute`, so settlement only + /// seals and defers the distribute (to `distribute_sealed`). With nothing + /// to refund, or a usable account, settlement still distributes. + #[tokio::test] + async fn settlement_defers_the_distribute_of_an_unpayable_refund() { + let engine = engine_reading(serde_json::Value::Null, vec![]); let open = engine.test_open(Pubkey::new_unique(), 1_000); let program_id = pc::default_program_id(); let is_distribute = |ix: &Instruction| { ix.program_id == program_id && ix.accounts.iter().any(|meta| meta.pubkey == open.payer) }; + let is_create = |ix: &Instruction| ix.program_id == pc::associated_token_program_id(); + + for actual in [0, 400] { + let ixs = engine.settlement_instructions(&open, actual).await.unwrap(); + assert!(!ixs.iter().any(is_distribute), "actual {actual}"); + assert!(!ixs.iter().any(is_create), "actual {actual}"); + if actual > 0 { + assert!(settled_voucher_expiry(&ixs, &open, actual) > now_unix()); + } + } + // Nothing is due back at the full amount: no account is read. + let ixs = engine.settlement_instructions(&open, 1_000).await.unwrap(); + assert!(ixs.last().is_some_and(is_distribute)); + // Positive control: a usable refund account distributes at once. + let mut engine = engine_reading(serde_json::Value::Null, vec![]); + let open = engine.test_open(Pubkey::new_unique(), 1_000); + engine.rpc = engine_reading( + token_account_json(&open.mint, &open.payer, &open.token_program), + vec![], + ) + .rpc; + let ixs = engine.settlement_instructions(&open, 400).await.unwrap(); + assert!(ixs.last().is_some_and(|ix| { + ix.program_id == program_id && ix.accounts.iter().any(|meta| meta.pubkey == open.payer) + })); + assert!( + !ixs.iter() + .filter(|ix| is_create(ix)) + .any(|ix| ix.accounts[2].pubkey == open.payer), + "the payer's account is never created at the fee payer's expense" + ); + } - let full = engine - .build_settlement_instructions(&open, 400, true) - .await - .unwrap(); - assert!(full.last().is_some_and(is_distribute)); + /// `distribute_sealed` finds this server's sealed channels on chain and + /// distributes a deferred one once the grace period after its open has + /// passed, even with the payer's account still unusable; inside it, + /// nothing is sent. + #[tokio::test(flavor = "multi_thread")] + async fn distribute_sealed_ends_a_deferral_at_the_deadline() { + use base64::Engine as _; + use solana_rpc_client_api::request::RpcRequest; - let sealed_only = engine - .build_settlement_instructions(&open, 400, false) - .await - .unwrap(); - assert!(!sealed_only.iter().any(is_distribute)); + let probe = multi_currency_engine(&["USDC"]); + let usdc = &probe.config.currencies[0]; + let mint = probe.mint_for(usdc).unwrap(); + let program_id = pc::default_program_id(); + let sealed_channel = |engine: &X402Upto| { + let payer = Pubkey::new_unique(); + let authorized = Pubkey::new_unique(); + let channel = Channel { + discriminator: 1, + version: 1, + bump: 1, + status: crate::core::payment_channels::generated::types::ChannelStatus::Sealed + as u8, + salt: 7, + deposit: 1_000, + settlement: crate::core::payment_channels::generated::types::SettlementWatermarks { + settled: 400, + payout_watermark: 0, + }, + closure_started_at: 0, + payer_withdrawn_at: 0, + grace_period: 900, + distribution_hash: pc::distribution_hash(&engine.distribution().unwrap()), + payer: pc::to_address(&payer), + payee: pc::to_address(&engine.fee_payer), + authorized_signer: pc::to_address(&authorized), + mint: pc::to_address(&mint), + rent_payer: pc::to_address(&engine.fee_payer), + open_slot: 42, + }; + let (address, _) = pc::find_channel_pda( + &payer, + &engine.fee_payer, + &mint, + &authorized, + 7, + 42, + &program_id, + ); + serde_json::json!([{ + "pubkey": pc::pubkey_string(&address), + "account": { + "lamports": 2_000_000, + "data": [base64::engine::general_purpose::STANDARD + .encode(borsh::to_vec(&channel).unwrap()), "base64"], + "owner": pc::pubkey_string(&program_id), + "executable": false, + "rentEpoch": 0, + "space": pc::CHANNEL_ACCOUNT_SIZE, + } + }]) + }; + let run = |opened_at: i64| { + let probe = multi_currency_engine(&["USDC"]); + let mut engine = engine_reading(serde_json::Value::Null, vec![]); + engine.fee_payer = probe.fee_payer; + engine.config = probe.config.clone(); + let accounts = sealed_channel(&engine); + let mut mocks = std::collections::HashMap::new(); + mocks.insert( + RpcRequest::GetAccountInfo, + serde_json::json!({ "context": { "slot": 1 }, "value": null }), + ); + mocks.insert(RpcRequest::GetProgramAccounts, accounts); + mocks.insert(RpcRequest::GetBlockTime, serde_json::json!(opened_at)); + engine.rpc = Arc::new(RpcClient::new_mock_with_mocks( + "succeeds".to_string(), + mocks, + )); + async move { engine.distribute_sealed().await.unwrap() } + }; + let now = now_unix(); assert!( - sealed_only - .iter() - .all(|ix| ix.program_id != pc::associated_token_program_id()), - "no account is created at the fee payer's expense" + run(now - 899).await.is_empty(), + "still inside the grace period" ); - assert!(sealed_only.iter().any(|ix| ix.program_id == program_id)); - assert!(settled_voucher_expiry(&sealed_only, &open, 400) > now_unix()); + assert_eq!(run(now - 900).await.len(), 1, "the deadline passed"); } /// A payer-chosen split keeps the channel address (recipients are not a diff --git a/skills/pay-sdk-implementation/codegen/package.json b/skills/pay-sdk-implementation/codegen/package.json index 14c2a3e44..fc893c3be 100644 --- a/skills/pay-sdk-implementation/codegen/package.json +++ b/skills/pay-sdk-implementation/codegen/package.json @@ -19,7 +19,7 @@ }, "devDependencies": { "@types/node": "^22.0.0", - "tsx": "^4.20.6", + "tsx": "^4.23.15", "typescript": "^5.6.3" } } diff --git a/skills/pay-sdk-implementation/codegen/pnpm-lock.yaml b/skills/pay-sdk-implementation/codegen/pnpm-lock.yaml index d71675b0d..af250c748 100644 --- a/skills/pay-sdk-implementation/codegen/pnpm-lock.yaml +++ b/skills/pay-sdk-implementation/codegen/pnpm-lock.yaml @@ -28,8 +28,8 @@ importers: specifier: ^22.0.0 version: 22.20.5 tsx: - specifier: ^4.20.6 - version: 4.22.4 + specifier: ^4.23.15 + version: 4.23.15 typescript: specifier: ^5.6.3 version: 5.9.3 @@ -99,158 +99,158 @@ packages: '@codama/visitors@1.10.2': resolution: {integrity: sha512-DUkpq9TEuevg4mEOW9fyBJiYHGzj6ByNtgVAyLRWcUEz6Mz3Qn8+lRDpqqVyuzRbAdurf9bWsO8ln+zswPP4hg==} - '@esbuild/aix-ppc64@0.28.0': - resolution: {integrity: sha512-lhRUCeuOyJQURhTxl4WkpFTjIsbDayJHih5kZC1giwE+MhIzAb7mEsQMqMf18rHLsrb5qI1tafG20mLxEWcWlA==} + '@esbuild/aix-ppc64@0.28.2': + resolution: {integrity: sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.28.0': - resolution: {integrity: sha512-+WzIXQOSaGs33tLEgYPYe/yQHf0WTU0X42Jca3y8NWMbUVhp7rUnw+vAsRC/QiDrdD31IszMrZy+qwPOPjd+rw==} + '@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.0': - resolution: {integrity: sha512-wqh0ByljabXLKHeWXYLqoJ5jKC4XBaw6Hk08OfMrCRd2nP2ZQ5eleDZC41XHyCNgktBGYMbqnrJKq/K/lzPMSQ==} + '@esbuild/android-arm@0.28.2': + resolution: {integrity: sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==} engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-x64@0.28.0': - resolution: {integrity: sha512-+VJggoaKhk2VNNqVL7f6S189UzShHC/mR9EE8rDdSkdpN0KflSwWY/gWjDrNxxisg8Fp1ZCD9jLMo4m0OUfeUA==} + '@esbuild/android-x64@0.28.2': + resolution: {integrity: sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==} engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.28.0': - resolution: {integrity: sha512-0T+A9WZm+bZ84nZBtk1ckYsOvyA3x7e2Acj1KdVfV4/2tdG4fzUp91YHx+GArWLtwqp77pBXVCPn2We7Letr0Q==} + '@esbuild/darwin-arm64@0.28.2': + resolution: {integrity: sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.28.0': - resolution: {integrity: sha512-fyzLm/DLDl/84OCfp2f/XQ4flmORsjU7VKt8HLjvIXChJoFFOIL6pLJPH4Yhd1n1gGFF9mPwtlN5Wf82DZs+LQ==} + '@esbuild/darwin-x64@0.28.2': + resolution: {integrity: sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==} engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.28.0': - resolution: {integrity: sha512-l9GeW5UZBT9k9brBYI+0WDffcRxgHQD8ShN2Ur4xWq/NFzUKm3k5lsH4PdaRgb2w7mI9u61nr2gI2mLI27Nh3Q==} + '@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.0': - resolution: {integrity: sha512-BXoQai/A0wPO6Es3yFJ7APCiKGc1tdAEOgeTNy3SsB491S3aHn4S4r3e976eUnPdU+NbdtmBuLncYir2tMU9Nw==} + '@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.0': - resolution: {integrity: sha512-RVyzfb3FWsGA55n6WY0MEIEPURL1FcbhFE6BffZEMEekfCzCIMtB5yyDcFnVbTnwk+CLAgTujmV/Lgvih56W+A==} + '@esbuild/linux-arm64@0.28.2': + resolution: {integrity: sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==} engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.28.0': - resolution: {integrity: sha512-CjaaREJagqJp7iTaNQjjidaNbCKYcd4IDkzbwwxtSvjI7NZm79qiHc8HqciMddQ6CKvJT6aBd8lO9kN/ZudLlw==} + '@esbuild/linux-arm@0.28.2': + resolution: {integrity: sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==} engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.28.0': - resolution: {integrity: sha512-KBnSTt1kxl9x70q+ydterVdl+Cn0H18ngRMRCEQfrbqdUuntQQ0LoMZv47uB97NljZFzY6HcfqEZ2SAyIUTQBQ==} + '@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.0': - resolution: {integrity: sha512-zpSlUce1mnxzgBADvxKXX5sl8aYQHo2ezvMNI8I0lbblJtp8V4odlm3Yzlj7gPyt3T8ReksE6bK+pT3WD+aJRg==} + '@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.0': - resolution: {integrity: sha512-2jIfP6mmjkdmeTlsX/9vmdmhBmKADrWqN7zcdtHIeNSCH1SqIoNI63cYsjQR8J+wGa4Y5izRcSHSm8K3QWmk3w==} + '@esbuild/linux-mips64el@0.28.2': + resolution: {integrity: sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.28.0': - resolution: {integrity: sha512-bc0FE9wWeC0WBm49IQMPSPILRocGTQt3j5KPCA8os6VprfuJ7KD+5PzESSrJ6GmPIPJK965ZJHTUlSA6GNYEhg==} + '@esbuild/linux-ppc64@0.28.2': + resolution: {integrity: sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.28.0': - resolution: {integrity: sha512-SQPZOwoTTT/HXFXQJG/vBX8sOFagGqvZyXcgLA3NhIqcBv1BJU1d46c0rGcrij2B56Z2rNiSLaZOYW5cUk7yLQ==} + '@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.0': - resolution: {integrity: sha512-SCfR0HN8CEEjnYnySJTd2cw0k9OHB/YFzt5zgJEwa+wL/T/raGWYMBqwDNAC6dqFKmJYZoQBRfHjgwLHGSrn3Q==} + '@esbuild/linux-s390x@0.28.2': + resolution: {integrity: sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==} engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.28.0': - resolution: {integrity: sha512-us0dSb9iFxIi8srnpl931Nvs65it/Jd2a2K3qs7fz2WfGPHqzfzZTfec7oxZJRNPXPnNYZtanmRc4AL/JwVzHQ==} + '@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.0': - resolution: {integrity: sha512-CR/RYotgtCKwtftMwJlUU7xCVNg3lMYZ0RzTmAHSfLCXw3NtZtNpswLEj/Kkf6kEL3Gw+BpOekRX0BYCtklhUw==} + '@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.0': - resolution: {integrity: sha512-nU1yhmYutL+fQ71Kxnhg8uEOdC0pwEW9entHykTgEbna2pw2dkbFSMeqjjyHZoCmt8SBkOSvV+yNmm94aUrrqw==} + '@esbuild/netbsd-x64@0.28.2': + resolution: {integrity: sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.28.0': - resolution: {integrity: sha512-cXb5vApOsRsxsEl4mcZ1XY3D4DzcoMxR/nnc4IyqYs0rTI8ZKmW6kyyg+11Z8yvgMfAEldKzP7AdP64HnSC/6g==} + '@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.0': - resolution: {integrity: sha512-8wZM2qqtv9UP3mzy7HiGYNH/zjTA355mpeuA+859TyR+e+Tc08IHYpLJuMsfpDJwoLo1ikIJI8jC3GFjnRClzA==} + '@esbuild/openbsd-x64@0.28.2': + resolution: {integrity: sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/openharmony-arm64@0.28.0': - resolution: {integrity: sha512-FLGfyizszcef5C3YtoyQDACyg95+dndv79i2EekILBofh5wpCa1KuBqOWKrEHZg3zrL3t5ouE5jgr94vA+Wb2w==} + '@esbuild/openharmony-arm64@0.28.2': + resolution: {integrity: sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] - '@esbuild/sunos-x64@0.28.0': - resolution: {integrity: sha512-1ZgjUoEdHZZl/YlV76TSCz9Hqj9h9YmMGAgAPYd+q4SicWNX3G5GCyx9uhQWSLcbvPW8Ni7lj4gDa1T40akdlw==} + '@esbuild/sunos-x64@0.28.2': + resolution: {integrity: sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==} engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.28.0': - resolution: {integrity: sha512-Q9StnDmQ/enxnpxCCLSg0oo4+34B9TdXpuyPeTedN/6+iXBJ4J+zwfQI28u/Jl40nOYAxGoNi7mFP40RUtkmUA==} + '@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.0': - resolution: {integrity: sha512-zF3ag/gfiCe6U2iczcRzSYJKH1DCI+ByzSENHlM2FcDbEeo5Zd2C86Aq0tKUYAJJ1obRP84ymxIAksZUcdztHA==} + '@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.0': - resolution: {integrity: sha512-pEl1bO9mfAmIC+tW5btTmrKaujg3zGtUmWNdCw/xs70FBjwAL3o9OEKNHvNmnyylD6ubxUERiEhdsL0xBQ9efw==} + '@esbuild/win32-x64@0.28.2': + resolution: {integrity: sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==} engines: {node: '>=18'} cpu: [x64] os: [win32] @@ -439,8 +439,8 @@ packages: resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==} engines: {node: '>= 0.4'} - esbuild@0.28.0: - resolution: {integrity: sha512-sNR9MHpXSUV/XB4zmsFKN+QgVG82Cc7+/aaxJ8Adi8hyOac+EXptIp45QBPaVyX3N70664wRbTcLTOemCAnyqw==} + esbuild@0.28.2: + resolution: {integrity: sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==} engines: {node: '>=18'} hasBin: true @@ -531,8 +531,8 @@ packages: sisteransi@1.0.5: resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} - tsx@4.22.4: - resolution: {integrity: sha512-X8EX+XV4QR5xCsrgxaED954zTDfY8KqlDtskKEL0cHhyS/P8b4IFOvGDQpsC9Q1XnLq915wEfwwY/zzskCtmhg==} + tsx@4.23.15: + resolution: {integrity: sha512-Yiex1Ovn8z2xPpOWckIiysV1SSyRMY9BkLF++q0yKiDxCqRhosKfMg3janKkiLBwZ5c/YryloKwGZcrEmtwxKw==} engines: {node: '>=18.0.0'} hasBin: true @@ -679,82 +679,82 @@ snapshots: '@codama/nodes': 1.10.2 '@codama/visitors-core': 1.10.2 - '@esbuild/aix-ppc64@0.28.0': + '@esbuild/aix-ppc64@0.28.2': optional: true - '@esbuild/android-arm64@0.28.0': + '@esbuild/android-arm64@0.28.2': optional: true - '@esbuild/android-arm@0.28.0': + '@esbuild/android-arm@0.28.2': optional: true - '@esbuild/android-x64@0.28.0': + '@esbuild/android-x64@0.28.2': optional: true - '@esbuild/darwin-arm64@0.28.0': + '@esbuild/darwin-arm64@0.28.2': optional: true - '@esbuild/darwin-x64@0.28.0': + '@esbuild/darwin-x64@0.28.2': optional: true - '@esbuild/freebsd-arm64@0.28.0': + '@esbuild/freebsd-arm64@0.28.2': optional: true - '@esbuild/freebsd-x64@0.28.0': + '@esbuild/freebsd-x64@0.28.2': optional: true - '@esbuild/linux-arm64@0.28.0': + '@esbuild/linux-arm64@0.28.2': optional: true - '@esbuild/linux-arm@0.28.0': + '@esbuild/linux-arm@0.28.2': optional: true - '@esbuild/linux-ia32@0.28.0': + '@esbuild/linux-ia32@0.28.2': optional: true - '@esbuild/linux-loong64@0.28.0': + '@esbuild/linux-loong64@0.28.2': optional: true - '@esbuild/linux-mips64el@0.28.0': + '@esbuild/linux-mips64el@0.28.2': optional: true - '@esbuild/linux-ppc64@0.28.0': + '@esbuild/linux-ppc64@0.28.2': optional: true - '@esbuild/linux-riscv64@0.28.0': + '@esbuild/linux-riscv64@0.28.2': optional: true - '@esbuild/linux-s390x@0.28.0': + '@esbuild/linux-s390x@0.28.2': optional: true - '@esbuild/linux-x64@0.28.0': + '@esbuild/linux-x64@0.28.2': optional: true - '@esbuild/netbsd-arm64@0.28.0': + '@esbuild/netbsd-arm64@0.28.2': optional: true - '@esbuild/netbsd-x64@0.28.0': + '@esbuild/netbsd-x64@0.28.2': optional: true - '@esbuild/openbsd-arm64@0.28.0': + '@esbuild/openbsd-arm64@0.28.2': optional: true - '@esbuild/openbsd-x64@0.28.0': + '@esbuild/openbsd-x64@0.28.2': optional: true - '@esbuild/openharmony-arm64@0.28.0': + '@esbuild/openharmony-arm64@0.28.2': optional: true - '@esbuild/sunos-x64@0.28.0': + '@esbuild/sunos-x64@0.28.2': optional: true - '@esbuild/win32-arm64@0.28.0': + '@esbuild/win32-arm64@0.28.2': optional: true - '@esbuild/win32-ia32@0.28.0': + '@esbuild/win32-ia32@0.28.2': optional: true - '@esbuild/win32-x64@0.28.0': + '@esbuild/win32-x64@0.28.2': optional: true '@iarna/toml@2.2.5': {} @@ -918,34 +918,34 @@ snapshots: dependencies: es-errors: 1.3.0 - esbuild@0.28.0: + esbuild@0.28.2: optionalDependencies: - '@esbuild/aix-ppc64': 0.28.0 - '@esbuild/android-arm': 0.28.0 - '@esbuild/android-arm64': 0.28.0 - '@esbuild/android-x64': 0.28.0 - '@esbuild/darwin-arm64': 0.28.0 - '@esbuild/darwin-x64': 0.28.0 - '@esbuild/freebsd-arm64': 0.28.0 - '@esbuild/freebsd-x64': 0.28.0 - '@esbuild/linux-arm': 0.28.0 - '@esbuild/linux-arm64': 0.28.0 - '@esbuild/linux-ia32': 0.28.0 - '@esbuild/linux-loong64': 0.28.0 - '@esbuild/linux-mips64el': 0.28.0 - '@esbuild/linux-ppc64': 0.28.0 - '@esbuild/linux-riscv64': 0.28.0 - '@esbuild/linux-s390x': 0.28.0 - '@esbuild/linux-x64': 0.28.0 - '@esbuild/netbsd-arm64': 0.28.0 - '@esbuild/netbsd-x64': 0.28.0 - '@esbuild/openbsd-arm64': 0.28.0 - '@esbuild/openbsd-x64': 0.28.0 - '@esbuild/openharmony-arm64': 0.28.0 - '@esbuild/sunos-x64': 0.28.0 - '@esbuild/win32-arm64': 0.28.0 - '@esbuild/win32-ia32': 0.28.0 - '@esbuild/win32-x64': 0.28.0 + '@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 fsevents@2.3.3: optional: true @@ -1028,9 +1028,9 @@ snapshots: sisteransi@1.0.5: {} - tsx@4.22.4: + tsx@4.23.15: dependencies: - esbuild: 0.28.0 + esbuild: 0.28.2 optionalDependencies: fsevents: 2.3.3 diff --git a/typescript/.x402-vendor/x402-core-2.26.0.tgz b/typescript/.x402-vendor/x402-core-2.26.0.tgz deleted file mode 100644 index 4164286f3..000000000 Binary files a/typescript/.x402-vendor/x402-core-2.26.0.tgz and /dev/null differ diff --git a/typescript/.x402-vendor/x402-core-2.28.0.tgz b/typescript/.x402-vendor/x402-core-2.28.0.tgz new file mode 100644 index 000000000..d567f017e Binary files /dev/null and b/typescript/.x402-vendor/x402-core-2.28.0.tgz differ diff --git a/typescript/.x402-vendor/x402-svm-2.26.0.tgz b/typescript/.x402-vendor/x402-svm-2.26.0.tgz deleted file mode 100644 index 8486e11ad..000000000 Binary files a/typescript/.x402-vendor/x402-svm-2.26.0.tgz and /dev/null differ diff --git a/typescript/.x402-vendor/x402-svm-2.28.0.tgz b/typescript/.x402-vendor/x402-svm-2.28.0.tgz new file mode 100644 index 000000000..8d928775c Binary files /dev/null and b/typescript/.x402-vendor/x402-svm-2.28.0.tgz differ diff --git a/typescript/examples/playground-api/package.json b/typescript/examples/playground-api/package.json index 192ea9bce..2161b311e 100644 --- a/typescript/examples/playground-api/package.json +++ b/typescript/examples/playground-api/package.json @@ -9,8 +9,8 @@ "build": "tsc -p tsconfig.json" }, "dependencies": { - "@solana-program/token": "^0.11.0", - "@solana/kit": "^6.5.0", + "@solana-program/token": "^0.18.0", + "@solana/kit": "^8.5.0", "@solana/mpp": "file:../../packages/mpp", "@solana/pay-kit": "file:../../packages/pay-kit", "cors": "^2.8.5", diff --git a/typescript/examples/playground-api/pnpm-lock.yaml b/typescript/examples/playground-api/pnpm-lock.yaml index 9d6698356..fda1526db 100644 --- a/typescript/examples/playground-api/pnpm-lock.yaml +++ b/typescript/examples/playground-api/pnpm-lock.yaml @@ -8,8 +8,10 @@ overrides: '@hono/node-server': 1.19.15 '@modelcontextprotocol/sdk': 1.31.0 fast-uri: 4.1.5 - hono: 4.13.7 - ip-address: 10.7.2 + hono: 4.13.14 + body-parser@1: 1.20.9 + zod: 4.6.7 + ip-address: 10.7.4 proxy-addr: 2.0.8 qs: 6.16.0 ws: 8.21.0 @@ -19,17 +21,17 @@ importers: .: dependencies: '@solana-program/token': - specifier: ^0.11.0 - version: 0.11.0(@solana/kit@6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)) + specifier: ^0.18.0 + version: 0.18.0(@solana/kit@8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)) '@solana/kit': - specifier: ^6.5.0 - version: 6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) + specifier: ^8.5.0 + version: 8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) '@solana/mpp': specifier: file:../../packages/mpp - version: file:../../packages/mpp(@solana/kit@6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10))(mppx@0.8.19(express@4.22.2)(hono@4.13.7)(typescript@5.9.3)(viem@2.56.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.4.3)))(typescript@5.9.3) + version: file:../../packages/mpp(@solana/kit@8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10))(mppx@0.8.19(express@4.22.2)(typescript@5.9.3)(viem@2.56.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.6.7)))(typescript@5.9.3) '@solana/pay-kit': specifier: file:../../packages/pay-kit - version: file:../../packages/pay-kit(@solana/addresses@7.1.1(typescript@5.9.3))(@solana/codecs-core@7.1.1(typescript@5.9.3))(@solana/codecs-strings@7.1.1(typescript@5.9.3))(@solana/keys@7.1.1(typescript@5.9.3))(@solana/signers@7.1.1(typescript@5.9.3))(@solana/transactions@7.1.1(typescript@5.9.3))(bufferutil@4.1.0)(express@4.22.2)(hono@4.13.7)(typescript@5.9.3)(utf-8-validate@5.0.10)(viem@2.56.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.4.3)) + version: file:../../packages/pay-kit(@solana/addresses@8.5.0(typescript@5.9.3))(@solana/codecs-core@8.5.0(typescript@5.9.3))(@solana/codecs-strings@8.5.0(typescript@5.9.3))(@solana/keys@8.5.0(typescript@5.9.3))(@solana/signers@8.5.0(typescript@5.9.3))(@solana/transactions@8.5.0(typescript@5.9.3))(bufferutil@4.1.0)(express@4.22.2)(typescript@5.9.3)(utf-8-validate@5.0.10)(viem@2.56.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.6.7)) cors: specifier: ^2.8.5 version: 2.8.6 @@ -41,7 +43,7 @@ importers: version: 8.7.1(express@4.22.2) mppx: specifier: ^0.8.15 - version: 0.8.19(express@4.22.2)(hono@4.13.7)(typescript@5.9.3)(viem@2.56.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.4.3)) + version: 0.8.19(express@4.22.2)(typescript@5.9.3)(viem@2.56.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.6.7)) devDependencies: '@types/cors': specifier: ^2.8.17 @@ -250,12 +252,22 @@ packages: peerDependencies: '@solana/kit': ^6.3.0 + '@solana-program/compute-budget@0.20.0': + resolution: {integrity: sha512-7SrwpFVNX6R5sjmPnqHUohCwZ3167TsWtE1Htg5wVrnsSoKfS8o1JxH033S/mYE56jGLwusYgNAwJn+Md1JmTQ==} + peerDependencies: + '@solana/kit': ^8.5.0 + '@solana-program/record@0.3.0': resolution: {integrity: sha512-q8z86INfXRQ5357qgVBrw05vC+u3xg8Vb4E1gEwnYUvAkL3cbJSjWVfTlGRiGWYmPNq/FYIWbsFrhsxXyhaJ+w==} engines: {node: '>=24.0.0'} peerDependencies: '@solana/kit': ^7.0.0 + '@solana-program/record@0.6.0': + resolution: {integrity: sha512-8NeDjYA8OVWiL7sZqURsYFPXoT/i1c2A1Wt4k5MOMEItehX8fUOj7uCspU85lC+so+tsEmJ09qO0t8vN8kk/ZQ==} + peerDependencies: + '@solana/kit': ^8.5.0 + '@solana-program/system@0.12.2': resolution: {integrity: sha512-MaBeOxlvTruQhA7UYkOb3hVTEHPPagOtd+PvTm6a8rGgvEAP0kD4BbC37NceOaR4ABNqdaCmD5OMVRKgrE6KAg==} peerDependencies: @@ -266,15 +278,10 @@ packages: peerDependencies: '@solana/kit': ^7.0.0 - '@solana-program/token-2022@0.11.0': - resolution: {integrity: sha512-4yhSajmlZdMl98vJvt63kW6L0ERtV7UFcfZGJFyUVfTMxTrgghp8BNyhh5S1Ho3p4yHqfgL4N9VgVQ9GCnqqbg==} + '@solana-program/system@0.16.0': + resolution: {integrity: sha512-/RG6q2E2vG/XpdOt8Jj/kbQktPlL5JyJuNGAeN9wDcxKDKQtrGTJpDrJgQUxiEy23fsPNXQbLN8XeCtYoMof3Q==} peerDependencies: - '@solana/kit': ^6.0.0 - '@solana/sysvars': ^5.0 - '@solana/zk-sdk': ^0.4.2 - peerDependenciesMeta: - '@solana/zk-sdk': - optional: true + '@solana/kit': ^8.5.0 '@solana-program/token-2022@0.14.1': resolution: {integrity: sha512-8yDF8xgEYU3HyfT4o7nLKHKMWQr3r2+1zBFojWYMkRyVh6YjuPO6Sxzf+p9trvL9Ddwp0d8SvqmMdYeErBZROA==} @@ -287,32 +294,42 @@ packages: '@solana/zk-sdk': optional: true + '@solana-program/token-2022@0.20.0': + resolution: {integrity: sha512-MMi+1szfgSHUdtk1drBbQsMVdTOOdGjzgH9i3IN42EZC07x5ZrXcgraZanrFSoS+DnSlTF+vFVOvmFE38rQBXA==} + peerDependencies: + '@solana/kit': ^8.5.0 + '@solana/sysvars': ^8.0.0 + '@solana/zk-sdk': ^0.5.4 + peerDependenciesMeta: + '@solana/zk-sdk': + optional: true + '@solana-program/token@0.11.0': resolution: {integrity: sha512-/lB72Pcmkn5kjUfP1Vd8F86HBlhN9RN4hJYgUG5csc23w9LCdYom2CiRdGsK25KkR9UFf6ndCCAMh83hMo+ftw==} peerDependencies: '@solana/kit': ^6.1.0 - '@solana-program/token@0.13.0': - resolution: {integrity: sha512-/Apjrd5lwOJGrPB0J5Rv7EBeclvyEBQPAGA85Scm7wBH+GpkbdLDM9uK3TNg8jjFKyWQYai/JtPHbrx7VgFLSg==} - peerDependencies: - '@solana/kit': ^6.5.0 - '@solana-program/token@0.15.0': resolution: {integrity: sha512-SeLm08EYIfT453I6lo7wTGgfMbz1s7bJ1jSHFHBFebSJHD3xF46zRgMxq3YKRlr/RM8jN0cG8SjZVu+IDvMxEA==} engines: {node: '>=24.0.0'} peerDependencies: '@solana/kit': ^7.0.0 - '@solana-program/zk-elgamal-proof@0.1.0': - resolution: {integrity: sha512-MKyeapz8P7SqkkC7h53ARFLoanb59ylVzokSMyINDH7hxY3JyiZs92/VfPa/qedhLAEHLd8jcc8sQ3pr3GyXtw==} + '@solana-program/token@0.18.0': + resolution: {integrity: sha512-YNN13I4BxBnGPGk0NzP/LLQMCmJVdunbtgqjl7/Gfp1fDXQrKXh9df8xu+2ayNdvjGJYC4c9D5vZpVetHdyJaQ==} peerDependencies: - '@solana/kit': ^5.0 + '@solana/kit': ^8.5.0 '@solana-program/zk-elgamal-proof@0.3.2': resolution: {integrity: sha512-bCiRVKtqYZpajgC2RVypZL4A0xHjQYVEsVSNMTtPJ1jjE5KOUvsXhnngGMYShK6BHv+fQP4F8QKvEVW/HOSFAg==} peerDependencies: '@solana/kit': ^7.0.0 + '@solana-program/zk-elgamal-proof@0.5.0': + resolution: {integrity: sha512-2shlu/0a/WFjERyFyhZevXG7WXRUz0kmy5DPEse3TOjH0s4fTU+Uk9kE5ijPhF85Fh662m4xT1ZZm+KBGq5y1g==} + peerDependencies: + '@solana/kit': ^8.5.0 + '@solana/accounts@6.10.0': resolution: {integrity: sha512-+FxfDOrnifoPlBkF+fr8eeQdgM6xtIgAg9xKMu3WnIz60oZd4Xnry6+ff6t+ePPoZZp397FSg9ZJet68VCWm5Q==} engines: {node: '>=20.18.0'} @@ -322,8 +339,8 @@ packages: typescript: optional: true - '@solana/accounts@6.9.0': - resolution: {integrity: sha512-g36AJreJrgf9AAjOfbdFHEFUTymBgzbWHoEDElZ+fDKvqBINDiUVKzDApwc7C7kGPMFqQBaoEHnQRxf2IqfKZQ==} + '@solana/accounts@7.1.1': + resolution: {integrity: sha512-7sy9VIFMdmu/7+2kVBRMU6mEvYx/DDjfam8DsBXbh+JszaTNZH3V8FutQYHRxrca3jxiumVfsy5USwKfVg8ElQ==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -331,8 +348,8 @@ packages: typescript: optional: true - '@solana/accounts@7.1.1': - resolution: {integrity: sha512-7sy9VIFMdmu/7+2kVBRMU6mEvYx/DDjfam8DsBXbh+JszaTNZH3V8FutQYHRxrca3jxiumVfsy5USwKfVg8ElQ==} + '@solana/accounts@8.5.0': + resolution: {integrity: sha512-vwwXYCobg1oG4kFeUEsGiNORjPujI2ff3yKLp6lCa7QBIlKaD7kZ2QRI3PZFYcNrMJ6HYNwNeZXR7ixg02pWdA==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -349,8 +366,8 @@ packages: typescript: optional: true - '@solana/addresses@6.9.0': - resolution: {integrity: sha512-tWnG2L6lo/ZhcMT019F3myDsH87MM8EZbTO0cgwgvVPlEdIGblROFF3tGVrb7FVCOlbPI0ONCFyPbnrmR58LsA==} + '@solana/addresses@7.1.1': + resolution: {integrity: sha512-/Tk2aTOT7UEcaJrdEcB3+SK09v5cZ/92NWqHBzEobxusTPNoeOFxa3MwV74Q1MgPecWdLz7TPreEhAKpcvV/vw==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -358,8 +375,8 @@ packages: typescript: optional: true - '@solana/addresses@7.1.1': - resolution: {integrity: sha512-/Tk2aTOT7UEcaJrdEcB3+SK09v5cZ/92NWqHBzEobxusTPNoeOFxa3MwV74Q1MgPecWdLz7TPreEhAKpcvV/vw==} + '@solana/addresses@8.5.0': + resolution: {integrity: sha512-LwTrDbDSJBng9y0vwiKqb/kSS9daspTGrSYoZPafeMWpAlpmutdD1KXPDHVTa4Xz00hcAfOJXYxRXX5VAoiOag==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -376,8 +393,8 @@ packages: typescript: optional: true - '@solana/assertions@6.9.0': - resolution: {integrity: sha512-FjWWD6e0in+HFsHMvU2zKCbyPfKtDW6iGXZZ9+Qg1QUYpO1AEObsya3F7hb9RkZKUueK4WwWAQnIuvEUp3A1uA==} + '@solana/assertions@7.1.1': + resolution: {integrity: sha512-tD07UKuw5i9Tw5xloVH+TUMrLzbHKixaB4DlGXumMEQU+JbYRPtFNqtMlrpVLuVM45nkbPfFp2Da0sXNRIqFHA==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -385,8 +402,8 @@ packages: typescript: optional: true - '@solana/assertions@7.1.1': - resolution: {integrity: sha512-tD07UKuw5i9Tw5xloVH+TUMrLzbHKixaB4DlGXumMEQU+JbYRPtFNqtMlrpVLuVM45nkbPfFp2Da0sXNRIqFHA==} + '@solana/assertions@8.5.0': + resolution: {integrity: sha512-EZDY5rJIV8Mv9xYJ7P+jvE5pihG7pmKZ6pTqbunba/4uZSQN4Klw0FX54LDDklfDvhzmAdXN0nYAnjovTGAPEg==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -403,8 +420,8 @@ packages: typescript: optional: true - '@solana/codecs-core@6.9.0': - resolution: {integrity: sha512-F2BmLecG/1nTtnjyD509NsEc254pxJKa2bpvotymv1lL1WfEn3zchcZ9SMIiLyL4G6J8b9F3OKIq2YSZho2AOQ==} + '@solana/codecs-core@7.1.1': + resolution: {integrity: sha512-C1UOAQ7LH8RuCTfaij6hthTZeBlpp8GuD2g9Nag/xgiNKJGvAfVrcorb+kO/sufdYI8Lu+BiVvPeKOjQDQiKqg==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -412,8 +429,8 @@ packages: typescript: optional: true - '@solana/codecs-core@7.1.1': - resolution: {integrity: sha512-C1UOAQ7LH8RuCTfaij6hthTZeBlpp8GuD2g9Nag/xgiNKJGvAfVrcorb+kO/sufdYI8Lu+BiVvPeKOjQDQiKqg==} + '@solana/codecs-core@8.5.0': + resolution: {integrity: sha512-ou38qNrf9XOzCWsu/I4sTzRmnrKqhblwMVvpXwXPKAAUZwkSAKQXonwgZFY68I5HK6nkfq1NLWfZFmTEIZYLiw==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -430,8 +447,8 @@ packages: typescript: optional: true - '@solana/codecs-data-structures@6.9.0': - resolution: {integrity: sha512-f7GYtiHafvJDhqiwzUUSr/6AYSK4DCw6quPmA80NZGtkNiFa+g6LoJy2wbC0wp2dxvCwNpxf6x3ILCYRutAvvg==} + '@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' @@ -439,8 +456,8 @@ packages: typescript: optional: true - '@solana/codecs-data-structures@7.1.1': - resolution: {integrity: sha512-MO+wMAuaatAQ96N3HhTsd7Uno+79rJw88P+OiU2n+pHK/rZuyu1yB2j12veqK4jUNWPR0aOyCuZ4rB2idrDjpg==} + '@solana/codecs-data-structures@8.5.0': + resolution: {integrity: sha512-CnnNriyltkgxZAKgAJoVRsRnrtdW4KCX37BUoIsquCM+AgSvhSbxaZNz0iaHjGOX7o1Z4s6+j7nAUgad0N/w5A==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -457,8 +474,8 @@ packages: typescript: optional: true - '@solana/codecs-numbers@6.9.0': - resolution: {integrity: sha512-XMI0FOHV2h7yPAllxWCX8z+J1msidNjXzN1mRjH5KR6C+vfzyKa2xWHve0bNSV/bjVAhqqhc7dQCpBKuF4+ScQ==} + '@solana/codecs-numbers@7.1.1': + resolution: {integrity: sha512-TWWrQq6Wp5Yf5bSc6RbxDDYCRUBBmRtRgjvUMHGp0P9K+4uFwxllRjSZFzBPHgXj3UTeZmFJdcoD271QhAgibg==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -466,8 +483,8 @@ packages: typescript: optional: true - '@solana/codecs-numbers@7.1.1': - resolution: {integrity: sha512-TWWrQq6Wp5Yf5bSc6RbxDDYCRUBBmRtRgjvUMHGp0P9K+4uFwxllRjSZFzBPHgXj3UTeZmFJdcoD271QhAgibg==} + '@solana/codecs-numbers@8.5.0': + resolution: {integrity: sha512-6Vtf52rHzjf98ykejn9bNGMaQ2k1f4UMIa+BGMbBy4mIRQ5ggdI5oCAb3sZPfJcel2JQHwDlsLHCYdpqC+n6Mg==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -487,8 +504,8 @@ packages: typescript: optional: true - '@solana/codecs-strings@6.9.0': - resolution: {integrity: sha512-PTqYQxMsmdfEEq29bV1AnALD4FjFEsSxOj1fYNqooOSTEQEpUoYEQtsd55/kBsnIKltXbvYwXYXBusm19n1sQA==} + '@solana/codecs-strings@7.1.1': + resolution: {integrity: sha512-6qWl+atG60D2LmP47GyGapQFhVsG1sVhVrEaM3lV09vwrGOMeOZARZ4ObaQ5m6uQmM04G+f8dY9d17nCMbGHGg==} engines: {node: '>=20.18.0'} peerDependencies: fastestsmallesttextencoderdecoder: ^1.0.22 @@ -499,8 +516,8 @@ packages: typescript: optional: true - '@solana/codecs-strings@7.1.1': - resolution: {integrity: sha512-6qWl+atG60D2LmP47GyGapQFhVsG1sVhVrEaM3lV09vwrGOMeOZARZ4ObaQ5m6uQmM04G+f8dY9d17nCMbGHGg==} + '@solana/codecs-strings@8.5.0': + resolution: {integrity: sha512-9lCSCUVkbPLb1o9PLDsaOatdVgrUqqWMrAqJvZPyyuvrC5++wPuKRIGq+5iU3lICY+AwWxrzVyiwdu4xaZVCiw==} engines: {node: '>=20.18.0'} peerDependencies: fastestsmallesttextencoderdecoder: ^1.0.22 @@ -511,8 +528,8 @@ packages: typescript: optional: true - '@solana/codecs@6.9.0': - resolution: {integrity: sha512-oWOybKa1PTGI1D/FyrvGKralADM1jmVZC2AtgEo+4JTKG0+i1p9ZbwNY2UcJqdYsDMDaGHAx0LMAid9LDCxXTQ==} + '@solana/codecs@8.5.0': + resolution: {integrity: sha512-wALOoEuL7HAaahZnrhxCwYz10p23hku/LPNfXjlvwgjVYJL08PH3uyWDFO8e9zhcNLOaR13IREE9z8zPUhJjDQ==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -530,8 +547,8 @@ packages: typescript: optional: true - '@solana/errors@6.9.0': - resolution: {integrity: sha512-7i+b07KMnkbHvFlz7uWade3jvyc22UmVm8o9taxPK8YV3JNM/NkS8oQFvMac2MIaLPAlEs7I8MHyVLUal1yY4g==} + '@solana/errors@7.1.1': + resolution: {integrity: sha512-q35qck8rBnNvJlPU00mnHEQm7gWvghzYz8khqVoLhjgodTzGp46VqnIOyI1LXOAF6XDal58bMNDO980MQgq8yw==} engines: {node: '>=20.18.0'} hasBin: true peerDependencies: @@ -540,8 +557,8 @@ packages: typescript: optional: true - '@solana/errors@7.1.1': - resolution: {integrity: sha512-q35qck8rBnNvJlPU00mnHEQm7gWvghzYz8khqVoLhjgodTzGp46VqnIOyI1LXOAF6XDal58bMNDO980MQgq8yw==} + '@solana/errors@8.5.0': + resolution: {integrity: sha512-y/XTiwAZsm2kHoEDJ3ac3NUq/0E4uCbOnBe2m5mmBXF3TGmF562tDKgN5pQ+thiRABvi7b2LqwTBCg4kAdtgRg==} engines: {node: '>=20.18.0'} hasBin: true peerDependencies: @@ -550,8 +567,8 @@ packages: typescript: optional: true - '@solana/fast-stable-stringify@6.9.0': - resolution: {integrity: sha512-l14zGVsURbT5Aox/kLFQywqV4VaE9/j3h2EvCu9oULVPMwzQB6yezJb1/KyiDwhm/RscooPd0gFQFIKEGQbayw==} + '@solana/fast-stable-stringify@8.5.0': + resolution: {integrity: sha512-CTIoOwJ0NScrB8KTzr/V4PJrNHrBAz1zvamM0opgDPQZGzLrBhca1e4eQcGmF6o7Dv3Ve0HdvDJx0B2uG6YxVA==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -568,8 +585,8 @@ packages: typescript: optional: true - '@solana/fixed-points@6.9.0': - resolution: {integrity: sha512-0K7mbYC4jdAZFlXqXjpNanmEyZxk7K9NtXDLc1zuhGuxwH8J9guvohwdw2V7TQ9bfjCYsprY3Tp2kUVQpECGmA==} + '@solana/fixed-points@7.1.1': + resolution: {integrity: sha512-qPj/V7kcFG/P0kuEa1U529+5L6mbkMwRIwvYBTDgBqPOt6wOdk9/c7Qn2VUQgSV0HgCXWxdHUdwaxBrYqO2ibg==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -577,8 +594,8 @@ packages: typescript: optional: true - '@solana/fixed-points@7.1.1': - resolution: {integrity: sha512-qPj/V7kcFG/P0kuEa1U529+5L6mbkMwRIwvYBTDgBqPOt6wOdk9/c7Qn2VUQgSV0HgCXWxdHUdwaxBrYqO2ibg==} + '@solana/fixed-points@8.5.0': + resolution: {integrity: sha512-hkB7dUAD/oxXeNOvdMXVqfKZAvOJ1o50gBwzh8yLP1ihdSxVgssb36Vg7806C5HzmIxmTKZclJJokG0cRUXVSw==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -595,8 +612,8 @@ packages: typescript: optional: true - '@solana/functional@6.9.0': - resolution: {integrity: sha512-sgNHOaIjETZZuziZdlwPsU5EjBVj5M0dUbwrSQTTNZe0SxX3pQ1QFVcs5KyvdS7AQcpBVdLjx4CfQjdKXk52GA==} + '@solana/functional@7.1.1': + resolution: {integrity: sha512-AnFohvUHGrqAu3kTxxC0rZyU4JddA08hOUZ1/DT9XogCZWetBpNJktX9uNuXQe+sN4FKTX2MfL//iBFBAsxtDA==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -604,8 +621,8 @@ packages: typescript: optional: true - '@solana/functional@7.1.1': - resolution: {integrity: sha512-AnFohvUHGrqAu3kTxxC0rZyU4JddA08hOUZ1/DT9XogCZWetBpNJktX9uNuXQe+sN4FKTX2MfL//iBFBAsxtDA==} + '@solana/functional@8.5.0': + resolution: {integrity: sha512-+8pgF1rVW78FfT0d+ceADFLKpSh/8/o9Ldx5tEkI6paiv0QeClL1rlU5nFs5tjoFkf+92x8PpiLEEGkm0CifOQ==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -622,8 +639,8 @@ packages: typescript: optional: true - '@solana/instruction-plans@6.9.0': - resolution: {integrity: sha512-SxTSOetEKD+WPzvDuYRsP1+KkwUp8KqL1n7oFx9ThxjyfEY0ly0i9KdbvX5yYVDOA2TSwrltgdu14y/Pf6y3Cg==} + '@solana/instruction-plans@7.1.1': + resolution: {integrity: sha512-KQGpsjeDflMcbKCdcF4KZVHcotYMS94DveRs0ZiBOsxb45dgkYrFmQ6ExJ/2exUOVF/rlp73knAP5ACrPMIAzA==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -631,8 +648,8 @@ packages: typescript: optional: true - '@solana/instruction-plans@7.1.1': - resolution: {integrity: sha512-KQGpsjeDflMcbKCdcF4KZVHcotYMS94DveRs0ZiBOsxb45dgkYrFmQ6ExJ/2exUOVF/rlp73knAP5ACrPMIAzA==} + '@solana/instruction-plans@8.5.0': + resolution: {integrity: sha512-cES8TzRGuJ5cdVn3hr6GskwwG68rLd8R0FqmzB9NeU/nzPnW/50nRrg36DYX1Nh+OwuU/ehg6zkNNu1Vo72lKQ==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -649,8 +666,8 @@ packages: typescript: optional: true - '@solana/instructions@6.9.0': - resolution: {integrity: sha512-LZfJx3bGdUSbGaswoOEPHygticqkCg3TusRczPJXyCmKhoQzPCcGQQ99qMzP7Wg8pEV5tWA5t7tycf8E237ydg==} + '@solana/instructions@7.1.1': + resolution: {integrity: sha512-VxMpJI++RTwaqSBLIP1GTjOPLtlYOqxOJ93ug6DlSdu9jku8M/or77DiXDUi62VmEh3bbsECR646vTJXUaPArw==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -658,8 +675,8 @@ packages: typescript: optional: true - '@solana/instructions@7.1.1': - resolution: {integrity: sha512-VxMpJI++RTwaqSBLIP1GTjOPLtlYOqxOJ93ug6DlSdu9jku8M/or77DiXDUi62VmEh3bbsECR646vTJXUaPArw==} + '@solana/instructions@8.5.0': + resolution: {integrity: sha512-LSMOQRicz8OalMM2DT60PtAaPjvkHPhIvmPEI8KpyWOuNRwABJBRAfn5ypcdSa69VVj4IdOY10tDWZzjN4dviA==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -695,8 +712,8 @@ packages: typescript: optional: true - '@solana/keys@6.9.0': - resolution: {integrity: sha512-1g2QARiqSjNqT0EIqLDLQ5vRm7hCsbqgFwFAp5GsMV/8BTYT8s1Ct2wLHDZiJ4eAX6beTHVf8LbOBfVejtn3oQ==} + '@solana/keys@7.1.1': + resolution: {integrity: sha512-Rx+vzWAXUa/Ko7W6wG1HOG9B3nQFZ5dALz113WoAmBZf7iQvaLG7U4ECDM/ydR+Nbdy6wYww7zQKRIye+1d+Nw==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -704,8 +721,8 @@ packages: typescript: optional: true - '@solana/keys@7.1.1': - resolution: {integrity: sha512-Rx+vzWAXUa/Ko7W6wG1HOG9B3nQFZ5dALz113WoAmBZf7iQvaLG7U4ECDM/ydR+Nbdy6wYww7zQKRIye+1d+Nw==} + '@solana/keys@8.5.0': + resolution: {integrity: sha512-mq6amguPYLklpAOC9A+boXQhpcHGjcn4QN40J0l1TvUkfWyFJ4HBbNb35fyWldqqDUV5ujOpaPZmmVvWJBK2Kw==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -728,8 +745,8 @@ packages: peerDependencies: '@solana/kit': ^7.0.0 - '@solana/kit@6.9.0': - resolution: {integrity: sha512-k7BRz7Akfv8wiRtlCR/xUyDLfuMfYMelMR1+AC5KgwaRRJReDF0BucMLNN1In7WoI+KuWwr1OKv4na/oKpyeAQ==} + '@solana/kit@8.5.0': + resolution: {integrity: sha512-bMnXXADeyZFe3XyqzPhlQAIsmPYRiojaRO4JQxwGOmMwiQ5f13ZQodmsOqnt8W/n40P7r/+/pDqWuqG0TUv+yA==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -752,8 +769,8 @@ packages: typescript: optional: true - '@solana/nominal-types@6.9.0': - resolution: {integrity: sha512-ouhrnY7a6nsLXRGcariwcmHDdXroCNqOuzwtdjKt2c8e8Drwao9yxPH2VoViNgpq8IGNJeQMEI1TVnoJZRn0gw==} + '@solana/nominal-types@7.1.1': + resolution: {integrity: sha512-do4rmmOlSplVYN92zV6nROJxkiRn0c7juoH1lka2Pmq+cAC3QhQXKYAwWffTFYDJJDO9qCOh00uv2hhSZi6RDw==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -761,8 +778,8 @@ packages: typescript: optional: true - '@solana/nominal-types@7.1.1': - resolution: {integrity: sha512-do4rmmOlSplVYN92zV6nROJxkiRn0c7juoH1lka2Pmq+cAC3QhQXKYAwWffTFYDJJDO9qCOh00uv2hhSZi6RDw==} + '@solana/nominal-types@8.5.0': + resolution: {integrity: sha512-OfTZ+w/C59Zkp51RJ3dzn2GXUojf9p/PMmSrOpxrj+hci3bdh4e6XDGY+mvP8HGPH+m0nfKWTBCygEslfoX6bg==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -779,8 +796,8 @@ packages: typescript: optional: true - '@solana/offchain-messages@6.9.0': - resolution: {integrity: sha512-qK3tqRPb+E0kmTz5qFXZbEdF4pyzfOWRZjyVESHVGemDDeGzZ1SV3zAxcA6HBCnv4wCBnlyaDPw8t+5sryNMAw==} + '@solana/offchain-messages@7.1.1': + resolution: {integrity: sha512-Py0/8HaIF0y+KSXHAWdQYDdZlGNoaqOZonTFuGKyDsrkgvod3wRc0cpZ5I/D/Rei4tVpvjNUfCXLpyoiJAZ7kg==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -788,8 +805,8 @@ packages: typescript: optional: true - '@solana/offchain-messages@7.1.1': - resolution: {integrity: sha512-Py0/8HaIF0y+KSXHAWdQYDdZlGNoaqOZonTFuGKyDsrkgvod3wRc0cpZ5I/D/Rei4tVpvjNUfCXLpyoiJAZ7kg==} + '@solana/offchain-messages@8.5.0': + resolution: {integrity: sha512-C7qBBD1Gfbdv99uoQnuc8XZYwttTQJOYEG2v6z7q3mAL03PN7zdItAlBa+M2tpeRKjTJObRYnUUJDfiIyyGD/Q==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -797,8 +814,8 @@ packages: typescript: optional: true - '@solana/options@6.9.0': - resolution: {integrity: sha512-H5ZRWNzzLMwHU/fRU9aVx+3TaMN4gDNCUYxsZxq0h7mqiwxFy6mpy95xPsfdldthCHDYtYnUTxe2sBatGbNHig==} + '@solana/options@8.5.0': + resolution: {integrity: sha512-Ron9FrWDkwxlmuI6D+NmrZZRngC1MUncglgyN77ThAoxDE1gGMOB88mQvEILeeqONeTA1rDg1uBvbewQcILp+w==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -809,8 +826,8 @@ packages: '@solana/pay-kit@file:../../packages/pay-kit': resolution: {directory: ../../packages/pay-kit, type: directory} - '@solana/plugin-core@6.9.0': - resolution: {integrity: sha512-KslLSnzY8zbGZibEBVMVUm2ZS8T2xf+cut7F65VjWPoWNAxU+p7933wsMz/az6CF7b65RI7iU3HhCr5/5QF50w==} + '@solana/plugin-core@8.5.0': + resolution: {integrity: sha512-1zmh+UC47yxsZHleDpH4AEVkm9yXIATkWm8v33DJuXaqX3TQXMXuxP39cXAyObIQEpCG8DK8lyAeFTUrIFcDmA==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -827,8 +844,8 @@ packages: typescript: optional: true - '@solana/plugin-interfaces@6.9.0': - resolution: {integrity: sha512-Qj4sk9thkM1UgnFXvWIoezd/CbqpX/2jigLBDsMB5Ed/gmFlkBSTL127LFDSY3OtzBpXl4hROs+Zqv+5xqtguA==} + '@solana/plugin-interfaces@7.1.1': + resolution: {integrity: sha512-2SHkGiftGmxg5xA5esxbwiY5wf+BOUsJG5rxD64/SHadUMaN3L0SDUSJfAXETJq5dCmVWxWGGPf2yVox4RIfdA==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -836,8 +853,8 @@ packages: typescript: optional: true - '@solana/plugin-interfaces@7.1.1': - resolution: {integrity: sha512-2SHkGiftGmxg5xA5esxbwiY5wf+BOUsJG5rxD64/SHadUMaN3L0SDUSJfAXETJq5dCmVWxWGGPf2yVox4RIfdA==} + '@solana/plugin-interfaces@8.5.0': + resolution: {integrity: sha512-+s/+cCuzk23/a1ViTIugvXFYHN0txxmvqfuL4qx81NlmGawqEYws6xD+L02wNzJ5rbJeAaBhw2pUFStMfG4vYg==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -854,8 +871,8 @@ packages: typescript: optional: true - '@solana/program-client-core@6.9.0': - resolution: {integrity: sha512-+iUnsddhs72QoBJoUO+/yHUXoBvYWa1sGCBRJk35zeg8j7ZXEwRkk6eX0VOrUPxhEpQbYJsIOCrIYApNIt8RFw==} + '@solana/program-client-core@7.1.1': + resolution: {integrity: sha512-zoMq8Qg6psj6tFYpA35xKhSrF/LpdiVflV6nKohxZg3ocwtRqRhQfbY8/mjCA9EfH8vqvsn5il5CnxALRqmJJA==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -863,8 +880,8 @@ packages: typescript: optional: true - '@solana/program-client-core@7.1.1': - resolution: {integrity: sha512-zoMq8Qg6psj6tFYpA35xKhSrF/LpdiVflV6nKohxZg3ocwtRqRhQfbY8/mjCA9EfH8vqvsn5il5CnxALRqmJJA==} + '@solana/program-client-core@8.5.0': + resolution: {integrity: sha512-HJcnbuvQRcWOV3nTUjzgmQRIs0Of1973UU8uOvSEEW7rxycQwNxJ7fVgxQ5sYOCbT+7rlqqTkDeczvB7I4OwoA==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -872,8 +889,8 @@ packages: typescript: optional: true - '@solana/programs@6.9.0': - resolution: {integrity: sha512-L9LAnQtfFFcCDLcbbnxhUtgAmu/kS4aRmrVncdnX5CFyQshlpo0/Qhrq3UA7vnhute4gjYV4pFT+64onH5qGEQ==} + '@solana/programs@8.5.0': + resolution: {integrity: sha512-8PC2E/d5rwCRw1tFwQlpG65YDN56bYmPiBl99QqCP2RzhNdFJ/52xgFumL2G0uLfD3xsuFaWuOIGNxkyfXYm/Q==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -890,8 +907,8 @@ packages: typescript: optional: true - '@solana/promises@6.9.0': - resolution: {integrity: sha512-227PlXRi6KZX4ODYTkJitr9InSa79NTquI72slay4gzxO9VmMepgvYdMAX6kawdN5pt+VzaklKhNhWXk50Pi9g==} + '@solana/promises@7.1.1': + resolution: {integrity: sha512-d3lhCfiFwiVyTRR6zhy1lcjDIh+l0a5gp1WPe64Vfa2gP0myC8P5C1Tknfjrp4d97DF3uBPqKAb5vV8hahNcNA==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -899,8 +916,8 @@ packages: typescript: optional: true - '@solana/promises@7.1.1': - resolution: {integrity: sha512-d3lhCfiFwiVyTRR6zhy1lcjDIh+l0a5gp1WPe64Vfa2gP0myC8P5C1Tknfjrp4d97DF3uBPqKAb5vV8hahNcNA==} + '@solana/promises@8.5.0': + resolution: {integrity: sha512-qWJbU6RGuZVrtvsGZ+2F46jccaIZDX4czYRRhS3m38cCdE+wKMbqGvWND50xP7D9egOxYKHMqJAJbLQH4gspvQ==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -917,8 +934,8 @@ packages: typescript: optional: true - '@solana/rpc-api@6.9.0': - resolution: {integrity: sha512-3KhXS6A1ie6GqTywW/KEMSXJ1VJEU66fxjhuiiqPILuJstP7kex3ycr3H6DirKydUsy6gaKaPN43rE+LfyS7OA==} + '@solana/rpc-api@7.1.1': + resolution: {integrity: sha512-ELGIqNbz8apeAxCLdD1PEPAnu6KtgHmWvUbH4VqqNg2jgWquyUOfTI5rblvdflx2Hcb7GK05w8/iiUaknOQKnw==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -926,8 +943,8 @@ packages: typescript: optional: true - '@solana/rpc-api@7.1.1': - resolution: {integrity: sha512-ELGIqNbz8apeAxCLdD1PEPAnu6KtgHmWvUbH4VqqNg2jgWquyUOfTI5rblvdflx2Hcb7GK05w8/iiUaknOQKnw==} + '@solana/rpc-api@8.5.0': + resolution: {integrity: sha512-qlRZ2yC8WEWNg3VX8UEqlZOitKZaeE6KWbn3A/ybtJAYz+mvr3RMDhnQ89RDqIuxPuAFZNV21BRJv3yB9xR44Q==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -944,8 +961,8 @@ packages: typescript: optional: true - '@solana/rpc-parsed-types@6.9.0': - resolution: {integrity: sha512-6ThH8izY+DWDyrVOOlS40vTcFjwjCinjfqnId7zhRk8OxhkfHQ/iEj+OnGwD4Yhe8pGdVa7GNVYlrQgQgzQ3eQ==} + '@solana/rpc-parsed-types@7.1.1': + resolution: {integrity: sha512-DiQSj2rNnhOKOTs6YDjQ2y4KuOkv8lh6moLFiQnY0+TvanJrGrQjxLSrHdCUQxymQcUxzrraZL9k6vxNzId4gw==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -953,8 +970,8 @@ packages: typescript: optional: true - '@solana/rpc-parsed-types@7.1.1': - resolution: {integrity: sha512-DiQSj2rNnhOKOTs6YDjQ2y4KuOkv8lh6moLFiQnY0+TvanJrGrQjxLSrHdCUQxymQcUxzrraZL9k6vxNzId4gw==} + '@solana/rpc-parsed-types@8.5.0': + resolution: {integrity: sha512-ktygZ019trgAyjr8y1GN1x4x6wJYw2Ola6UogAfJT5LoNs6kV3k84yCNAlGv34xRPqCVxlWo4nsIWJf8yWQQ2w==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -971,8 +988,8 @@ packages: typescript: optional: true - '@solana/rpc-spec-types@6.9.0': - resolution: {integrity: sha512-A4fY1JRrcKqX3EfttO4Q8L97nGPqdjfekAV0eDyxN5nu9ngf5p7GKenkl7AYDoHLNr6ZX/C96cRADxXjsRJ0iA==} + '@solana/rpc-spec-types@7.1.1': + resolution: {integrity: sha512-FDDgXfAPfq28sQNnGhZr/+2kp5QTTcNZ5m/Q9y9Jrlux6brdPsbf9Sh1Q/lgz7i76arzNW/rzRY125RzqGWANg==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -980,8 +997,8 @@ packages: typescript: optional: true - '@solana/rpc-spec-types@7.1.1': - resolution: {integrity: sha512-FDDgXfAPfq28sQNnGhZr/+2kp5QTTcNZ5m/Q9y9Jrlux6brdPsbf9Sh1Q/lgz7i76arzNW/rzRY125RzqGWANg==} + '@solana/rpc-spec-types@8.5.0': + resolution: {integrity: sha512-YUTMKWWlHCGBmA1wxhIilbxJlad5vEsvc8dDO9VWr7GVkQUlipEU79iGaKk4xQ6Oo1mZWxpGz5mAJUqGraTK4A==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -998,8 +1015,8 @@ packages: typescript: optional: true - '@solana/rpc-spec@6.9.0': - resolution: {integrity: sha512-3yHRoChc0IpsJbUq0/94l+ar3t9U3Ax58W0HON7eyYe7zFP10UAxpkHn7DPch9DeALyuGph8kVnvl+kXRgJlGg==} + '@solana/rpc-spec@7.1.1': + resolution: {integrity: sha512-1FwhgL18qasRYlWffdBNIUoxQyGLzdh3YMQW3y33M61vk/q1ldEGJRypV9B/SrXmxwqDiUbQ+m+zgainCTp1ZA==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1007,8 +1024,8 @@ packages: typescript: optional: true - '@solana/rpc-spec@7.1.1': - resolution: {integrity: sha512-1FwhgL18qasRYlWffdBNIUoxQyGLzdh3YMQW3y33M61vk/q1ldEGJRypV9B/SrXmxwqDiUbQ+m+zgainCTp1ZA==} + '@solana/rpc-spec@8.5.0': + resolution: {integrity: sha512-0oET5yc880zFGqBMJE2UB7sxW8sIs4hmsP4bmkR2y4ipm1aScC5U+Rd8GaIrupBOVOFj+RXIorC7kQycN/9nhw==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1016,8 +1033,8 @@ packages: typescript: optional: true - '@solana/rpc-subscriptions-api@6.9.0': - resolution: {integrity: sha512-UA/rPQeNx6zQMUFcS8PPPuB4vzUOtSzIY/igMH0DRoP020NyES2GguIb7Zo7sqDNi4n0gkQRhoW4dPVotcNKdA==} + '@solana/rpc-subscriptions-api@8.5.0': + resolution: {integrity: sha512-PJaAyqZkpG8vuzdxmdWMwp1JS5pyZ6PuL8OMhx6nCt3phkseqIs1NmAf8pQc/RZjIV3hJMMVCwSDG1DE8DY64w==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1025,8 +1042,8 @@ packages: typescript: optional: true - '@solana/rpc-subscriptions-channel-websocket@6.9.0': - resolution: {integrity: sha512-kT8Yne9HjJD2gooaOFNSyKrvaIfOy2GR0Ymv8OfecBCwFStdz+SPo5eYXq8ZWoZbr5E/MMpHgqsHBanqa2Ffyg==} + '@solana/rpc-subscriptions-channel-websocket@8.5.0': + resolution: {integrity: sha512-sRYYwBFg31z77zfKpJBcAO9MaUWa+bO1PlBcDiToa4luXGuR3dC8TSpi1Yip4T4NCONNzK3yhyeI6sHhGHc8Qw==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1043,8 +1060,8 @@ packages: typescript: optional: true - '@solana/rpc-subscriptions-spec@6.9.0': - resolution: {integrity: sha512-DbaG67s99vRZQxFMK80UQ7DEKkRJK6JEZeYg/U5UttD6n7ax/vct7qopxGnrt4RCkaaac2fU8Sr+fcnvWQweUg==} + '@solana/rpc-subscriptions-spec@7.1.1': + resolution: {integrity: sha512-yrqd+fV2Ae4hkzXX42aKRmTrz3FwvzKqO4h0ahs88dzSvXpy8l6Svu1k+uRgMlZ64g2P83jfQW+3Pj5fBoxmdw==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1052,8 +1069,8 @@ packages: typescript: optional: true - '@solana/rpc-subscriptions-spec@7.1.1': - resolution: {integrity: sha512-yrqd+fV2Ae4hkzXX42aKRmTrz3FwvzKqO4h0ahs88dzSvXpy8l6Svu1k+uRgMlZ64g2P83jfQW+3Pj5fBoxmdw==} + '@solana/rpc-subscriptions-spec@8.5.0': + resolution: {integrity: sha512-YdCPLHOcQWz8JhMaT/E+YC56nFDJ6D+XOTr6qRWHGe/1PIYGQDVvaFzI7+tF0b6tuv49GoMbpGdkiTX2v6KeUw==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1061,8 +1078,8 @@ packages: typescript: optional: true - '@solana/rpc-subscriptions@6.9.0': - resolution: {integrity: sha512-IMctZQaMxzvRACQ6ooW98lP+7tVoUJnRgOZtkAdzgBizldQAYPIKd3MulP0jbQPCMfdPsa2Hs0NBcUwfgonq3w==} + '@solana/rpc-subscriptions@8.5.0': + resolution: {integrity: sha512-8hdWSDKKtMK3kRrR8TExwFo/bWHxVTu4zJ/JkePTQgNtm95kX25/hy+9JHKRtSsNUfXXYM60sQVE18cGgMU7dA==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1079,8 +1096,8 @@ packages: typescript: optional: true - '@solana/rpc-transformers@6.9.0': - resolution: {integrity: sha512-dg4LK2wEBpaY+KRk/SJIkYvrvjdsc1AwD4bkmGY4Fp7EwVlvwBQShAQn78Qi4IP0WQ/0n9ncFyUxgcB1Y01ZuQ==} + '@solana/rpc-transformers@7.1.1': + resolution: {integrity: sha512-k8a/JZFso/nvPBgurOGJ/ZC6sXCtYE3lCvTj95i29pl45C4SgjdetJrAH/pWEEhQXcxaJs7OLBGmCh2enazlJw==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1088,8 +1105,8 @@ packages: typescript: optional: true - '@solana/rpc-transformers@7.1.1': - resolution: {integrity: sha512-k8a/JZFso/nvPBgurOGJ/ZC6sXCtYE3lCvTj95i29pl45C4SgjdetJrAH/pWEEhQXcxaJs7OLBGmCh2enazlJw==} + '@solana/rpc-transformers@8.5.0': + resolution: {integrity: sha512-JYq+EyfzJ1ksZubU9VHynQY1Z3k1tosdxG6KE4Cua/rFuXPosSn7o5h9FLLbSB5cTVcnj0lGNrBaVYW4AVK4iA==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1097,8 +1114,8 @@ packages: typescript: optional: true - '@solana/rpc-transport-http@6.9.0': - resolution: {integrity: sha512-4gy30fWJcS6jrcXCoP/optFpGJ/gD9xdkE8wDbe1Ys/Y+e4XjyBt45xtTnbdmMdukvdRX+oXS3zgUIYoagpNzQ==} + '@solana/rpc-transport-http@8.5.0': + resolution: {integrity: sha512-xfIFZa+oxXLgA6BXaE2bXjiy2yZM1qO1URzzF0lmTekJM/okS8EZAQwEicWpYkvfdHJZ2x/oagD3AOSBBCWrsw==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1115,8 +1132,8 @@ packages: typescript: optional: true - '@solana/rpc-types@6.9.0': - resolution: {integrity: sha512-iFhPzZK3qiQ1lhfNTNBTI7BIs5PfWZSgRLD3enKm8ZAQggzvUklfO3KPh47jVsc/Jsr1UGPH8M3o3m17qjO1Cg==} + '@solana/rpc-types@7.1.1': + resolution: {integrity: sha512-yHlSUWgynaaqevuqipGhhcZnmFVNs+F6KIlbUZ0kQY6NMVtaSzx5AQrtQjbtAQzNRsRTDYkKuQg8nOruiDoseQ==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1124,8 +1141,8 @@ packages: typescript: optional: true - '@solana/rpc-types@7.1.1': - resolution: {integrity: sha512-yHlSUWgynaaqevuqipGhhcZnmFVNs+F6KIlbUZ0kQY6NMVtaSzx5AQrtQjbtAQzNRsRTDYkKuQg8nOruiDoseQ==} + '@solana/rpc-types@8.5.0': + resolution: {integrity: sha512-L050pZqQ8gaFABF26NAYoatyZZeJo52AKvQQ3i58LRtUc6wcrpCF+4x4U/EDER2YVAc6Qx1xWvGnAomGhI6vzw==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1133,8 +1150,8 @@ packages: typescript: optional: true - '@solana/rpc@6.9.0': - resolution: {integrity: sha512-ny1Kt20+oq3xZErNA56+Magmb2JKYfQgHwZTsBmHKVl/9mBpv1y1+ygV+KNiiX/wWXWstLbdIo1jgPwZPbU2Vg==} + '@solana/rpc@8.5.0': + resolution: {integrity: sha512-7CQFNOMhXrY/LT0qdsi3h0chy4A/Ao93pyBLqFQqxzlub0st8dC5wl+MDXhkxaBos/DZOu1V4EleWv6qbLMlow==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1151,8 +1168,8 @@ packages: typescript: optional: true - '@solana/signers@6.9.0': - resolution: {integrity: sha512-x7WyoRm9IORMqeSqNivZgyY+RERPkmqWxpINPD13kUH+oaZzonORIgxk2Lz+u5iPRXiJPkdRPrQ4FoFWv8i6kQ==} + '@solana/signers@7.1.1': + resolution: {integrity: sha512-UfWYnAglm21q5hS3Op1bU5mYiWfx0VesovZcIur0uYPc3EJlfBVikl8pf745x+bB77xG6lIzNbb+99t48SQbkg==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1160,8 +1177,8 @@ packages: typescript: optional: true - '@solana/signers@7.1.1': - resolution: {integrity: sha512-UfWYnAglm21q5hS3Op1bU5mYiWfx0VesovZcIur0uYPc3EJlfBVikl8pf745x+bB77xG6lIzNbb+99t48SQbkg==} + '@solana/signers@8.5.0': + resolution: {integrity: sha512-F9VvFsG9Av+Sbs4mQpuVlszb6msujxnqKQqa4TsRT24GOqKOFr4Xvs7HqgVJV/BPIDnz7u0omUhUILesHJDfkQ==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1178,8 +1195,8 @@ packages: typescript: optional: true - '@solana/subscribable@6.9.0': - resolution: {integrity: sha512-YV0/BrJNfepf10CTfLwD7kRY1kkELDHd+BbHJZhBeiuiXTY3xQTvvx1RFs3NtfFCcTHG25Uh8NpRacQJnxSSIQ==} + '@solana/subscribable@7.1.1': + resolution: {integrity: sha512-l4Wzc2L+7WQPeC/kaCiia1aaUY/SJJdrNHnLibKchS2pb7YbF7J2OygsweHXliWCVpG0jZwcvIVpusgygbZQLw==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1187,8 +1204,8 @@ packages: typescript: optional: true - '@solana/subscribable@7.1.1': - resolution: {integrity: sha512-l4Wzc2L+7WQPeC/kaCiia1aaUY/SJJdrNHnLibKchS2pb7YbF7J2OygsweHXliWCVpG0jZwcvIVpusgygbZQLw==} + '@solana/subscribable@8.5.0': + resolution: {integrity: sha512-v1/hL/l4kubwYVuaMNmtQcmTgDuKG6e9Hjv9fCxkYCdDIUERgmm9DX/So1386+6rkQBVRC7wTSH86Jq+RIqNGQ==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1201,8 +1218,8 @@ packages: peerDependencies: '@solana/kit': ^7.0.0 - '@solana/sysvars@6.9.0': - resolution: {integrity: sha512-e0e+QKr/th9t/O2N1oUoJmcodLghzAtWKUlGb1zyYub0/WJrPImnKqJqp/gDP4tK98mJxopPMcprCeHk4B+TQg==} + '@solana/sysvars@8.5.0': + resolution: {integrity: sha512-vidKFEOAujEVizDUHFCmmIpHsS3Zu/fXJKcDUtbUn+bwD9Z1fRiper8rZW3Qdtgu1GmrH3O8MoyL2Nrp7k6QNw==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1210,8 +1227,8 @@ packages: typescript: optional: true - '@solana/transaction-confirmation@6.9.0': - resolution: {integrity: sha512-fzYCOih7hhtBzzNSkAnxMjeFeQ8U7e27k9i0RsgQc3/e3OCynF5HoIVNhhqZbwfIBKiaD4ginJR6slRnfqO32Q==} + '@solana/transaction-confirmation@8.5.0': + resolution: {integrity: sha512-dUVHhyaJ9tt535ZJfgPAdKo6zycCAn1mqKKP/FYvCz/4FiAKnyvqj8rxd66yvvuJVhkpjbcPDDagm/P8JEYUug==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1219,8 +1236,8 @@ packages: typescript: optional: true - '@solana/transaction-messages@6.10.0': - resolution: {integrity: sha512-s7v8G3BTxGlKYIj3eWCG0g1296v+1LBt16mVnlRH5FuyaJ5AdhlhtRho5HUDpdwE8EXun+y1c48V6uhcZ8wdbQ==} + '@solana/transaction-introspection@8.5.0': + resolution: {integrity: sha512-VPYVLcpieu5YwwC1wmh3zZ/KHWmqJWPS7iMPVpf90L79/1Dvkg+YYQHnVeN4VQdb7VFnfpTqUnSQpfERDk0Sag==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1228,8 +1245,8 @@ packages: typescript: optional: true - '@solana/transaction-messages@6.9.0': - resolution: {integrity: sha512-OWpryt0w6SHlwHx12Vd1wvx2QwSGBXAIUEHTCtkctcM3AaZRy5cIl7CAq9iD5PgahUsaOyRLBV0zlCJcC2JrJA==} + '@solana/transaction-messages@6.10.0': + resolution: {integrity: sha512-s7v8G3BTxGlKYIj3eWCG0g1296v+1LBt16mVnlRH5FuyaJ5AdhlhtRho5HUDpdwE8EXun+y1c48V6uhcZ8wdbQ==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1246,8 +1263,8 @@ packages: typescript: optional: true - '@solana/transactions@6.10.0': - resolution: {integrity: sha512-VADSqP9OTYmhrox4pcgDd4+RjVmednXSE0+8Y7SPK4PN1pK5Az2RJ0nSsy0xcTnaOr8mF/crwFktqPrRQwSbQA==} + '@solana/transaction-messages@8.5.0': + resolution: {integrity: sha512-8SHxirU5K0kFmOwwD6XTGI5LWP/bLvLBDbemT4xDOaL+6xkLzlTMtzlgKb/Td5UtqyYOoew0FBVLJzJx/QApOw==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1255,8 +1272,8 @@ packages: typescript: optional: true - '@solana/transactions@6.9.0': - resolution: {integrity: sha512-uKPzLwHbjwChfVl82he17ntkh02PfgnMMhN7uOAC+VbkIt1O+EEw8sX87gi6kdG/EV+QBDQXm9PLAo5W0tYylw==} + '@solana/transactions@6.10.0': + resolution: {integrity: sha512-VADSqP9OTYmhrox4pcgDd4+RjVmednXSE0+8Y7SPK4PN1pK5Az2RJ0nSsy0xcTnaOr8mF/crwFktqPrRQwSbQA==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1273,6 +1290,15 @@ packages: typescript: optional: true + '@solana/transactions@8.5.0': + resolution: {integrity: sha512-IGRWI38rq5b94gy93wn/gVSQBuwNPSUv3GnWkd6R6Tc7jLbfRlYbYHJNHH5o28Fmlr+nlEn4bgu3BiqMWxuLmg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + '@stripe/stripe-js@9.13.0': resolution: {integrity: sha512-/0c72BUgzzVkVTlsw5uBn8x3waTdVJ/PZGfQ6jY1eu6K7olUPf4d9lgDPA9/0sIdsR8j7o3QIG8fOCO6ItcL7A==} engines: {node: '>=12.16'} @@ -1314,7 +1340,7 @@ packages: resolution: {integrity: sha512-Ofer5QUnuUdTFsBRwARMoWKOH1ND5ehwYhJ3OJ/BQO+StkwQjHw0XyVh4vDttzHB7QOFhPHa/o413PJ82gU/Tg==} peerDependencies: typescript: '>=5.0.4' - zod: ^3.22.0 || ^4.0.0 + zod: 4.6.7 peerDependenciesMeta: typescript: optional: true @@ -1325,7 +1351,7 @@ packages: resolution: {integrity: sha512-dpKH+N27vRjarMVTFFkeY445VTKftzGWpL0FiT7xmVmzQRKazZexzC5uHG0f6XKsVLAuUlndnbGau6lRejClxg==} peerDependencies: typescript: '>=5.0.4' - zod: ^3.22.0 || ^4.0.0 + zod: 4.6.7 peerDependenciesMeta: typescript: optional: true @@ -1339,8 +1365,8 @@ packages: array-flatten@1.1.1: resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} - body-parser@1.20.5: - resolution: {integrity: sha512-3grm+/2tUOvu2cjJkvsIxrv/wVpfXQW4PsQHYm7yk4vfpu7Ekl6nEsYBoJUL6qDwZUx8wUhQ8tR2qz+ad9c9OA==} + body-parser@1.20.9: + resolution: {integrity: sha512-FISIQxV5u91Y9gvuFq3q/tA/qTqLJn3AhRcEvyozyhJTh5OBFFtv827AdHU7Rbyct4r+Ba1/99oFa1Y3yuFsdw==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} bufferutil@4.1.0: @@ -1363,10 +1389,6 @@ packages: resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} - commander@14.0.3: - resolution: {integrity: sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==} - engines: {node: '>=20'} - commander@15.0.0: resolution: {integrity: sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==} engines: {node: '>=22.12.0'} @@ -1507,10 +1529,6 @@ packages: resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} engines: {node: '>= 0.4'} - hono@4.13.7: - resolution: {integrity: sha512-c8/gF9ac8Y78/agExVocyLevgR+JlpNB444Py0FSX8pJoPdYUfUzRcXtYEYGwt6l19qIlVZPN5Mfsw9jFShmQQ==} - engines: {node: '>=16.9.0'} - http-errors@2.0.1: resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} engines: {node: '>= 0.8'} @@ -1522,8 +1540,8 @@ packages: inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - ip-address@10.7.2: - resolution: {integrity: sha512-7H/2gFSIitxc0hG3nOI1glS8QLo/EHBFFLk8vEUjXY/xu0AdL8jZ9U1IzO2PUm0d2D/ofQcAifb0g6OBkt8U7w==} + ip-address@10.7.4: + resolution: {integrity: sha512-DWBMKyeM25D70nrIiTkgQth59/G+naKOTep6huF9j+GmeK3DMD60Zvxg5d5qQnz+38AHgou6ean2LECX+lrKDg==} engines: {node: '>= 12'} ipaddr.js@1.9.1: @@ -1570,7 +1588,7 @@ packages: '@modelcontextprotocol/sdk': 1.31.0 elysia: '>=1' express: '>=5' - hono: 4.13.7 + hono: 4.13.14 viem: '>=2.54.0' peerDependenciesMeta: '@modelcontextprotocol/sdk': @@ -1709,8 +1727,8 @@ packages: undici-types@7.24.6: resolution: {integrity: sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==} - undici-types@8.4.1: - resolution: {integrity: sha512-iIXDNrTeaM0lDZvNUY1Urfs9dVgOWdQCkv6VMiePh644EKce0qoz6FNxxg7/DS4CxbFI36Atlz0VgHKS2qL1Dw==} + undici-types@8.12.3: + resolution: {integrity: sha512-EXE4ydL3S76dFb27UFjNVZHTyv/TLdATj/KUe29ptdcg6qXL48J2tZ3126E5kICj5jn781OR+XlVH1N6Mz8jbA==} unpipe@1.0.0: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} @@ -1748,8 +1766,8 @@ packages: utf-8-validate: optional: true - zod@4.4.3: - resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} + zod@4.6.7: + resolution: {integrity: sha512-g8W2D2kU6a8untc053fX1uVBKzM7yqAxW/3zwk83+6RyF2+SKOuV+c0wBDhUwzV1PaGapmZH+rmcUzPf+3CGwg==} snapshots: @@ -1858,59 +1876,73 @@ snapshots: '@noble/hashes': 1.8.0 '@scure/base': 1.2.6 - '@solana-program/compute-budget@0.15.0(@solana/kit@6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10))': + '@solana-program/compute-budget@0.15.0(@solana/kit@8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10))': dependencies: - '@solana/kit': 6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) + '@solana/kit': 8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) - '@solana-program/record@0.3.0(@solana/kit@6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10))': + '@solana-program/compute-budget@0.20.0(@solana/kit@8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10))': dependencies: - '@solana/kit': 6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) + '@solana/kit': 8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) - '@solana-program/system@0.12.2(@solana/kit@6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10))': + '@solana-program/record@0.3.0(@solana/kit@8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10))': dependencies: - '@solana/kit': 6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) + '@solana/kit': 8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) - '@solana-program/system@0.13.0(@solana/kit@6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10))': + '@solana-program/record@0.6.0(@solana/kit@8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10))': dependencies: - '@solana/kit': 6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) + '@solana-program/system': 0.16.0(@solana/kit@8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)) + '@solana/kit': 8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) - '@solana-program/token-2022@0.11.0(@solana/kit@6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10))': + '@solana-program/system@0.12.2(@solana/kit@8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10))': dependencies: - '@noble/curves': 1.9.7 - '@solana-program/zk-elgamal-proof': 0.1.0(@solana/kit@6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)) - '@solana/kit': 6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) + '@solana/kit': 8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) + + '@solana-program/system@0.13.0(@solana/kit@8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10))': + dependencies: + '@solana/kit': 8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) + + '@solana-program/system@0.16.0(@solana/kit@8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10))': + dependencies: + '@solana/kit': 8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) - '@solana-program/token-2022@0.14.1(@solana/kit@6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10))': + '@solana-program/token-2022@0.14.1(@solana/kit@8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10))': dependencies: '@noble/curves': 1.9.7 - '@solana-program/record': 0.3.0(@solana/kit@6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)) - '@solana-program/zk-elgamal-proof': 0.3.2(@solana/kit@6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)) - '@solana/kit': 6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) + '@solana-program/record': 0.3.0(@solana/kit@8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)) + '@solana-program/zk-elgamal-proof': 0.3.2(@solana/kit@8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)) + '@solana/kit': 8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) - '@solana-program/token@0.11.0(@solana/kit@6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10))': + '@solana-program/token-2022@0.20.0(@solana/kit@8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10))': dependencies: - '@solana-program/system': 0.12.2(@solana/kit@6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)) - '@solana/kit': 6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) + '@solana-program/record': 0.6.0(@solana/kit@8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)) + '@solana-program/system': 0.16.0(@solana/kit@8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)) + '@solana-program/zk-elgamal-proof': 0.5.0(@solana/kit@8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)) + '@solana/kit': 8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) - '@solana-program/token@0.13.0(@solana/kit@6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10))': + '@solana-program/token@0.11.0(@solana/kit@8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10))': dependencies: - '@solana-program/system': 0.12.2(@solana/kit@6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)) - '@solana/kit': 6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) + '@solana-program/system': 0.12.2(@solana/kit@8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)) + '@solana/kit': 8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) - '@solana-program/token@0.15.0(@solana/kit@6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10))': + '@solana-program/token@0.15.0(@solana/kit@8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10))': dependencies: - '@solana-program/system': 0.13.0(@solana/kit@6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)) - '@solana/kit': 6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) + '@solana-program/system': 0.13.0(@solana/kit@8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)) + '@solana/kit': 8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) - '@solana-program/zk-elgamal-proof@0.1.0(@solana/kit@6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10))': + '@solana-program/token@0.18.0(@solana/kit@8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10))': dependencies: - '@solana-program/system': 0.12.2(@solana/kit@6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)) - '@solana/kit': 6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) + '@solana-program/system': 0.16.0(@solana/kit@8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)) + '@solana/kit': 8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) - '@solana-program/zk-elgamal-proof@0.3.2(@solana/kit@6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10))': + '@solana-program/zk-elgamal-proof@0.3.2(@solana/kit@8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10))': dependencies: - '@solana-program/system': 0.13.0(@solana/kit@6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)) - '@solana/kit': 6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) + '@solana-program/system': 0.13.0(@solana/kit@8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)) + '@solana/kit': 8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) + + '@solana-program/zk-elgamal-proof@0.5.0(@solana/kit@8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10))': + dependencies: + '@solana-program/system': 0.16.0(@solana/kit@8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)) + '@solana/kit': 8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) '@solana/accounts@6.10.0(typescript@5.9.3)': dependencies: @@ -1925,19 +1957,6 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/accounts@6.9.0(typescript@5.9.3)': - dependencies: - '@solana/addresses': 6.9.0(typescript@5.9.3) - '@solana/codecs-core': 6.9.0(typescript@5.9.3) - '@solana/codecs-strings': 6.9.0(typescript@5.9.3) - '@solana/errors': 6.9.0(typescript@5.9.3) - '@solana/rpc-spec': 6.9.0(typescript@5.9.3) - '@solana/rpc-types': 6.9.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - '@solana/accounts@7.1.1(typescript@5.9.3)': dependencies: '@solana/addresses': 7.1.1(typescript@5.9.3) @@ -1951,25 +1970,26 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/addresses@6.10.0(typescript@5.9.3)': + '@solana/accounts@8.5.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/addresses': 8.5.0(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-strings': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/rpc-spec': 8.5.0(typescript@5.9.3) + '@solana/rpc-types': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/addresses@6.9.0(typescript@5.9.3)': + '@solana/addresses@6.10.0(typescript@5.9.3)': dependencies: - '@solana/assertions': 6.9.0(typescript@5.9.3) - '@solana/codecs-core': 6.9.0(typescript@5.9.3) - '@solana/codecs-strings': 6.9.0(typescript@5.9.3) - '@solana/errors': 6.9.0(typescript@5.9.3) - '@solana/nominal-types': 6.9.0(typescript@5.9.3) + '@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: @@ -1987,15 +2007,21 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/assertions@6.10.0(typescript@5.9.3)': + '@solana/addresses@8.5.0(typescript@5.9.3)': dependencies: - '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/assertions': 8.5.0(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-strings': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/nominal-types': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder - '@solana/assertions@6.9.0(typescript@5.9.3)': + '@solana/assertions@6.10.0(typescript@5.9.3)': dependencies: - '@solana/errors': 6.9.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 @@ -2005,15 +2031,15 @@ snapshots: optionalDependencies: typescript: 5.9.3 - '@solana/codecs-core@6.10.0(typescript@5.9.3)': + '@solana/assertions@8.5.0(typescript@5.9.3)': dependencies: - '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 - '@solana/codecs-core@6.9.0(typescript@5.9.3)': + '@solana/codecs-core@6.10.0(typescript@5.9.3)': dependencies: - '@solana/errors': 6.9.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 @@ -2023,19 +2049,17 @@ snapshots: optionalDependencies: typescript: 5.9.3 - '@solana/codecs-data-structures@6.10.0(typescript@5.9.3)': + '@solana/codecs-core@8.5.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) + '@solana/errors': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 - '@solana/codecs-data-structures@6.9.0(typescript@5.9.3)': + '@solana/codecs-data-structures@6.10.0(typescript@5.9.3)': dependencies: - '@solana/codecs-core': 6.9.0(typescript@5.9.3) - '@solana/codecs-numbers': 6.9.0(typescript@5.9.3) - '@solana/errors': 6.9.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/errors': 6.10.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 @@ -2047,17 +2071,18 @@ snapshots: optionalDependencies: typescript: 5.9.3 - '@solana/codecs-numbers@6.10.0(typescript@5.9.3)': + '@solana/codecs-data-structures@8.5.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) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 - '@solana/codecs-numbers@6.9.0(typescript@5.9.3)': + '@solana/codecs-numbers@6.10.0(typescript@5.9.3)': dependencies: - '@solana/codecs-core': 6.9.0(typescript@5.9.3) - '@solana/errors': 6.9.0(typescript@5.9.3) + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 @@ -2068,19 +2093,18 @@ snapshots: optionalDependencies: typescript: 5.9.3 - '@solana/codecs-strings@6.10.0(typescript@5.9.3)': + '@solana/codecs-numbers@8.5.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) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 - '@solana/codecs-strings@6.9.0(typescript@5.9.3)': + '@solana/codecs-strings@6.10.0(typescript@5.9.3)': dependencies: - '@solana/codecs-core': 6.9.0(typescript@5.9.3) - '@solana/codecs-numbers': 6.9.0(typescript@5.9.3) - '@solana/errors': 6.9.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/errors': 6.10.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 @@ -2092,14 +2116,22 @@ snapshots: optionalDependencies: typescript: 5.9.3 - '@solana/codecs@6.9.0(typescript@5.9.3)': + '@solana/codecs-strings@8.5.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/codecs@8.5.0(typescript@5.9.3)': dependencies: - '@solana/codecs-core': 6.9.0(typescript@5.9.3) - '@solana/codecs-data-structures': 6.9.0(typescript@5.9.3) - '@solana/codecs-numbers': 6.9.0(typescript@5.9.3) - '@solana/codecs-strings': 6.9.0(typescript@5.9.3) - '@solana/fixed-points': 6.9.0(typescript@5.9.3) - '@solana/options': 6.9.0(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-data-structures': 8.5.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.5.0(typescript@5.9.3) + '@solana/codecs-strings': 8.5.0(typescript@5.9.3) + '@solana/fixed-points': 8.5.0(typescript@5.9.3) + '@solana/options': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: @@ -2112,21 +2144,21 @@ snapshots: optionalDependencies: typescript: 5.9.3 - '@solana/errors@6.9.0(typescript@5.9.3)': + '@solana/errors@7.1.1(typescript@5.9.3)': dependencies: chalk: 5.6.2 - commander: 14.0.3 + commander: 15.0.0 optionalDependencies: typescript: 5.9.3 - '@solana/errors@7.1.1(typescript@5.9.3)': + '@solana/errors@8.5.0(typescript@5.9.3)': dependencies: chalk: 5.6.2 commander: 15.0.0 optionalDependencies: typescript: 5.9.3 - '@solana/fast-stable-stringify@6.9.0(typescript@5.9.3)': + '@solana/fast-stable-stringify@8.5.0(typescript@5.9.3)': optionalDependencies: typescript: 5.9.3 @@ -2137,17 +2169,17 @@ snapshots: optionalDependencies: typescript: 5.9.3 - '@solana/fixed-points@6.9.0(typescript@5.9.3)': + '@solana/fixed-points@7.1.1(typescript@5.9.3)': dependencies: - '@solana/codecs-core': 6.9.0(typescript@5.9.3) - '@solana/errors': 6.9.0(typescript@5.9.3) + '@solana/codecs-core': 7.1.1(typescript@5.9.3) + '@solana/errors': 7.1.1(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 - '@solana/fixed-points@7.1.1(typescript@5.9.3)': + '@solana/fixed-points@8.5.0(typescript@5.9.3)': dependencies: - '@solana/codecs-core': 7.1.1(typescript@5.9.3) - '@solana/errors': 7.1.1(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 @@ -2155,11 +2187,11 @@ snapshots: optionalDependencies: typescript: 5.9.3 - '@solana/functional@6.9.0(typescript@5.9.3)': + '@solana/functional@7.1.1(typescript@5.9.3)': optionalDependencies: typescript: 5.9.3 - '@solana/functional@7.1.1(typescript@5.9.3)': + '@solana/functional@8.5.0(typescript@5.9.3)': optionalDependencies: typescript: 5.9.3 @@ -2176,19 +2208,6 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/instruction-plans@6.9.0(typescript@5.9.3)': - dependencies: - '@solana/errors': 6.9.0(typescript@5.9.3) - '@solana/instructions': 6.9.0(typescript@5.9.3) - '@solana/keys': 6.9.0(typescript@5.9.3) - '@solana/promises': 6.9.0(typescript@5.9.3) - '@solana/transaction-messages': 6.9.0(typescript@5.9.3) - '@solana/transactions': 6.9.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - '@solana/instruction-plans@7.1.1(typescript@5.9.3)': dependencies: '@solana/errors': 7.1.1(typescript@5.9.3) @@ -2202,17 +2221,23 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/instructions@6.10.0(typescript@5.9.3)': + '@solana/instruction-plans@8.5.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) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/instructions': 8.5.0(typescript@5.9.3) + '@solana/keys': 8.5.0(typescript@5.9.3) + '@solana/promises': 8.5.0(typescript@5.9.3) + '@solana/transaction-messages': 8.5.0(typescript@5.9.3) + '@solana/transactions': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder - '@solana/instructions@6.9.0(typescript@5.9.3)': + '@solana/instructions@6.10.0(typescript@5.9.3)': dependencies: - '@solana/codecs-core': 6.9.0(typescript@5.9.3) - '@solana/errors': 6.9.0(typescript@5.9.3) + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 @@ -2223,23 +2248,30 @@ snapshots: optionalDependencies: typescript: 5.9.3 - '@solana/keychain-core@1.3.0(@solana/addresses@7.1.1(typescript@5.9.3))(@solana/codecs-core@7.1.1(typescript@5.9.3))(@solana/codecs-strings@7.1.1(typescript@5.9.3))(@solana/keys@7.1.1(typescript@5.9.3))(@solana/signers@7.1.1(typescript@5.9.3))(@solana/transactions@7.1.1(typescript@5.9.3))': + '@solana/instructions@8.5.0(typescript@5.9.3)': dependencies: - '@solana/addresses': 7.1.1(typescript@5.9.3) - '@solana/codecs-core': 7.1.1(typescript@5.9.3) - '@solana/codecs-strings': 7.1.1(typescript@5.9.3) - '@solana/keys': 7.1.1(typescript@5.9.3) - '@solana/signers': 7.1.1(typescript@5.9.3) - '@solana/transactions': 7.1.1(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 - '@solana/keychain-memory@1.3.0(@solana/addresses@7.1.1(typescript@5.9.3))(@solana/codecs-core@7.1.1(typescript@5.9.3))(@solana/codecs-strings@7.1.1(typescript@5.9.3))(@solana/keys@7.1.1(typescript@5.9.3))(@solana/signers@7.1.1(typescript@5.9.3))(@solana/transactions@7.1.1(typescript@5.9.3))': + '@solana/keychain-core@1.3.0(@solana/addresses@8.5.0(typescript@5.9.3))(@solana/codecs-core@8.5.0(typescript@5.9.3))(@solana/codecs-strings@8.5.0(typescript@5.9.3))(@solana/keys@8.5.0(typescript@5.9.3))(@solana/signers@8.5.0(typescript@5.9.3))(@solana/transactions@8.5.0(typescript@5.9.3))': dependencies: - '@solana/addresses': 7.1.1(typescript@5.9.3) - '@solana/codecs-strings': 7.1.1(typescript@5.9.3) - '@solana/keychain-core': 1.3.0(@solana/addresses@7.1.1(typescript@5.9.3))(@solana/codecs-core@7.1.1(typescript@5.9.3))(@solana/codecs-strings@7.1.1(typescript@5.9.3))(@solana/keys@7.1.1(typescript@5.9.3))(@solana/signers@7.1.1(typescript@5.9.3))(@solana/transactions@7.1.1(typescript@5.9.3)) - '@solana/keys': 7.1.1(typescript@5.9.3) - '@solana/signers': 7.1.1(typescript@5.9.3) - '@solana/transactions': 7.1.1(typescript@5.9.3) + '@solana/addresses': 8.5.0(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-strings': 8.5.0(typescript@5.9.3) + '@solana/keys': 8.5.0(typescript@5.9.3) + '@solana/signers': 8.5.0(typescript@5.9.3) + '@solana/transactions': 8.5.0(typescript@5.9.3) + + '@solana/keychain-memory@1.3.0(@solana/addresses@8.5.0(typescript@5.9.3))(@solana/codecs-core@8.5.0(typescript@5.9.3))(@solana/codecs-strings@8.5.0(typescript@5.9.3))(@solana/keys@8.5.0(typescript@5.9.3))(@solana/signers@8.5.0(typescript@5.9.3))(@solana/transactions@8.5.0(typescript@5.9.3))': + dependencies: + '@solana/addresses': 8.5.0(typescript@5.9.3) + '@solana/codecs-strings': 8.5.0(typescript@5.9.3) + '@solana/keychain-core': 1.3.0(@solana/addresses@8.5.0(typescript@5.9.3))(@solana/codecs-core@8.5.0(typescript@5.9.3))(@solana/codecs-strings@8.5.0(typescript@5.9.3))(@solana/keys@8.5.0(typescript@5.9.3))(@solana/signers@8.5.0(typescript@5.9.3))(@solana/transactions@8.5.0(typescript@5.9.3)) + '@solana/keys': 8.5.0(typescript@5.9.3) + '@solana/signers': 8.5.0(typescript@5.9.3) + '@solana/transactions': 8.5.0(typescript@5.9.3) transitivePeerDependencies: - '@solana/codecs-core' @@ -2256,19 +2288,6 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/keys@6.9.0(typescript@5.9.3)': - dependencies: - '@solana/assertions': 6.9.0(typescript@5.9.3) - '@solana/codecs-core': 6.9.0(typescript@5.9.3) - '@solana/codecs-strings': 6.9.0(typescript@5.9.3) - '@solana/errors': 6.9.0(typescript@5.9.3) - '@solana/nominal-types': 6.9.0(typescript@5.9.3) - '@solana/promises': 6.9.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - '@solana/keys@7.1.1(typescript@5.9.3)': dependencies: '@solana/assertions': 7.1.1(typescript@5.9.3) @@ -2282,46 +2301,61 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/kit-plugin-instruction-plan@0.13.0(@solana/kit@6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10))': - dependencies: - '@solana/kit': 6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) - - '@solana/kit-plugin-rpc@0.15.0(@solana/kit@6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10))': + '@solana/keys@8.5.0(typescript@5.9.3)': dependencies: - '@solana/kit': 6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) - '@solana/kit-plugin-instruction-plan': 0.13.0(@solana/kit@6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)) - - '@solana/kit-plugin-signer@0.13.0(@solana/kit@6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10))': - dependencies: - '@solana/kit': 6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) + '@solana/assertions': 8.5.0(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-strings': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/nominal-types': 8.5.0(typescript@5.9.3) + '@solana/promises': 8.5.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder - '@solana/kit@6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)': - dependencies: - '@solana/accounts': 6.9.0(typescript@5.9.3) - '@solana/addresses': 6.9.0(typescript@5.9.3) - '@solana/codecs': 6.9.0(typescript@5.9.3) - '@solana/errors': 6.9.0(typescript@5.9.3) - '@solana/functional': 6.9.0(typescript@5.9.3) - '@solana/instruction-plans': 6.9.0(typescript@5.9.3) - '@solana/instructions': 6.9.0(typescript@5.9.3) - '@solana/keys': 6.9.0(typescript@5.9.3) - '@solana/offchain-messages': 6.9.0(typescript@5.9.3) - '@solana/plugin-core': 6.9.0(typescript@5.9.3) - '@solana/plugin-interfaces': 6.9.0(typescript@5.9.3) - '@solana/program-client-core': 6.9.0(typescript@5.9.3) - '@solana/programs': 6.9.0(typescript@5.9.3) - '@solana/rpc': 6.9.0(typescript@5.9.3) - '@solana/rpc-api': 6.9.0(typescript@5.9.3) - '@solana/rpc-parsed-types': 6.9.0(typescript@5.9.3) - '@solana/rpc-spec-types': 6.9.0(typescript@5.9.3) - '@solana/rpc-subscriptions': 6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) - '@solana/rpc-types': 6.9.0(typescript@5.9.3) - '@solana/signers': 6.9.0(typescript@5.9.3) - '@solana/subscribable': 6.9.0(typescript@5.9.3) - '@solana/sysvars': 6.9.0(typescript@5.9.3) - '@solana/transaction-confirmation': 6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) - '@solana/transaction-messages': 6.9.0(typescript@5.9.3) - '@solana/transactions': 6.9.0(typescript@5.9.3) + '@solana/kit-plugin-instruction-plan@0.13.0(@solana/kit@8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10))': + dependencies: + '@solana/kit': 8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) + + '@solana/kit-plugin-rpc@0.15.0(@solana/kit@8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10))': + dependencies: + '@solana/kit': 8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) + '@solana/kit-plugin-instruction-plan': 0.13.0(@solana/kit@8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)) + + '@solana/kit-plugin-signer@0.13.0(@solana/kit@8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10))': + dependencies: + '@solana/kit': 8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) + + '@solana/kit@8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)': + dependencies: + '@solana/accounts': 8.5.0(typescript@5.9.3) + '@solana/addresses': 8.5.0(typescript@5.9.3) + '@solana/codecs': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/functional': 8.5.0(typescript@5.9.3) + '@solana/instruction-plans': 8.5.0(typescript@5.9.3) + '@solana/instructions': 8.5.0(typescript@5.9.3) + '@solana/keys': 8.5.0(typescript@5.9.3) + '@solana/offchain-messages': 8.5.0(typescript@5.9.3) + '@solana/plugin-core': 8.5.0(typescript@5.9.3) + '@solana/plugin-interfaces': 8.5.0(typescript@5.9.3) + '@solana/program-client-core': 8.5.0(typescript@5.9.3) + '@solana/programs': 8.5.0(typescript@5.9.3) + '@solana/promises': 8.5.0(typescript@5.9.3) + '@solana/rpc': 8.5.0(typescript@5.9.3) + '@solana/rpc-api': 8.5.0(typescript@5.9.3) + '@solana/rpc-parsed-types': 8.5.0(typescript@5.9.3) + '@solana/rpc-spec-types': 8.5.0(typescript@5.9.3) + '@solana/rpc-subscriptions': 8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) + '@solana/rpc-types': 8.5.0(typescript@5.9.3) + '@solana/signers': 8.5.0(typescript@5.9.3) + '@solana/subscribable': 8.5.0(typescript@5.9.3) + '@solana/sysvars': 8.5.0(typescript@5.9.3) + '@solana/transaction-confirmation': 8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) + '@solana/transaction-introspection': 8.5.0(typescript@5.9.3) + '@solana/transaction-messages': 8.5.0(typescript@5.9.3) + '@solana/transactions': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: @@ -2329,17 +2363,17 @@ snapshots: - fastestsmallesttextencoderdecoder - utf-8-validate - '@solana/mpp@file:../../packages/mpp(@solana/kit@6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10))(mppx@0.8.19(express@4.22.2)(hono@4.13.7)(typescript@5.9.3)(viem@2.56.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.4.3)))(typescript@5.9.3)': + '@solana/mpp@file:../../packages/mpp(@solana/kit@8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10))(mppx@0.8.19(express@4.22.2)(typescript@5.9.3)(viem@2.56.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.6.7)))(typescript@5.9.3)': dependencies: - '@solana-program/compute-budget': 0.15.0(@solana/kit@6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)) - '@solana-program/system': 0.12.2(@solana/kit@6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)) - '@solana-program/token': 0.11.0(@solana/kit@6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)) + '@solana-program/compute-budget': 0.15.0(@solana/kit@8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)) + '@solana-program/system': 0.12.2(@solana/kit@8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)) + '@solana-program/token': 0.11.0(@solana/kit@8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)) '@solana/addresses': 6.10.0(typescript@5.9.3) - '@solana/kit': 6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) + '@solana/kit': 8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) '@solana/program-client-core': 6.10.0(typescript@5.9.3) - '@solana/subscriptions': 0.5.0(@solana/kit@6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10))(typescript@5.9.3) - mppx: 0.8.19(express@4.22.2)(hono@4.13.7)(typescript@5.9.3)(viem@2.56.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.4.3)) - zod: 4.4.3 + '@solana/subscriptions': 0.5.0(@solana/kit@8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10))(typescript@5.9.3) + mppx: 0.8.19(express@4.22.2)(typescript@5.9.3)(viem@2.56.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.6.7)) + zod: 4.6.7 transitivePeerDependencies: - '@solana/sysvars' - '@solana/zk-sdk' @@ -2350,11 +2384,11 @@ snapshots: optionalDependencies: typescript: 5.9.3 - '@solana/nominal-types@6.9.0(typescript@5.9.3)': + '@solana/nominal-types@7.1.1(typescript@5.9.3)': optionalDependencies: typescript: 5.9.3 - '@solana/nominal-types@7.1.1(typescript@5.9.3)': + '@solana/nominal-types@8.5.0(typescript@5.9.3)': optionalDependencies: typescript: 5.9.3 @@ -2373,21 +2407,6 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/offchain-messages@6.9.0(typescript@5.9.3)': - dependencies: - '@solana/addresses': 6.9.0(typescript@5.9.3) - '@solana/codecs-core': 6.9.0(typescript@5.9.3) - '@solana/codecs-data-structures': 6.9.0(typescript@5.9.3) - '@solana/codecs-numbers': 6.9.0(typescript@5.9.3) - '@solana/codecs-strings': 6.9.0(typescript@5.9.3) - '@solana/errors': 6.9.0(typescript@5.9.3) - '@solana/keys': 6.9.0(typescript@5.9.3) - '@solana/nominal-types': 6.9.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - '@solana/offchain-messages@7.1.1(typescript@5.9.3)': dependencies: '@solana/addresses': 7.1.1(typescript@5.9.3) @@ -2403,26 +2422,41 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/options@6.9.0(typescript@5.9.3)': + '@solana/offchain-messages@8.5.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.5.0(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-data-structures': 8.5.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.5.0(typescript@5.9.3) + '@solana/codecs-strings': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/keys': 8.5.0(typescript@5.9.3) + '@solana/nominal-types': 8.5.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/options@8.5.0(typescript@5.9.3)': dependencies: - '@solana/codecs-core': 6.9.0(typescript@5.9.3) - '@solana/codecs-data-structures': 6.9.0(typescript@5.9.3) - '@solana/codecs-numbers': 6.9.0(typescript@5.9.3) - '@solana/codecs-strings': 6.9.0(typescript@5.9.3) - '@solana/errors': 6.9.0(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-data-structures': 8.5.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.5.0(typescript@5.9.3) + '@solana/codecs-strings': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/pay-kit@file:../../packages/pay-kit(@solana/addresses@7.1.1(typescript@5.9.3))(@solana/codecs-core@7.1.1(typescript@5.9.3))(@solana/codecs-strings@7.1.1(typescript@5.9.3))(@solana/keys@7.1.1(typescript@5.9.3))(@solana/signers@7.1.1(typescript@5.9.3))(@solana/transactions@7.1.1(typescript@5.9.3))(bufferutil@4.1.0)(express@4.22.2)(hono@4.13.7)(typescript@5.9.3)(utf-8-validate@5.0.10)(viem@2.56.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.4.3))': + '@solana/pay-kit@file:../../packages/pay-kit(@solana/addresses@8.5.0(typescript@5.9.3))(@solana/codecs-core@8.5.0(typescript@5.9.3))(@solana/codecs-strings@8.5.0(typescript@5.9.3))(@solana/keys@8.5.0(typescript@5.9.3))(@solana/signers@8.5.0(typescript@5.9.3))(@solana/transactions@8.5.0(typescript@5.9.3))(bufferutil@4.1.0)(express@4.22.2)(typescript@5.9.3)(utf-8-validate@5.0.10)(viem@2.56.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.6.7))': dependencies: - '@solana-program/compute-budget': 0.15.0(@solana/kit@6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)) - '@solana-program/token': 0.13.0(@solana/kit@6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)) - '@solana-program/token-2022': 0.11.0(@solana/kit@6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)) - '@solana/keychain-memory': 1.3.0(@solana/addresses@7.1.1(typescript@5.9.3))(@solana/codecs-core@7.1.1(typescript@5.9.3))(@solana/codecs-strings@7.1.1(typescript@5.9.3))(@solana/keys@7.1.1(typescript@5.9.3))(@solana/signers@7.1.1(typescript@5.9.3))(@solana/transactions@7.1.1(typescript@5.9.3)) - '@solana/kit': 6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) - mppx: 0.8.19(express@4.22.2)(hono@4.13.7)(typescript@5.9.3)(viem@2.56.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.4.3)) + '@solana-program/compute-budget': 0.20.0(@solana/kit@8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)) + '@solana-program/token': 0.18.0(@solana/kit@8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)) + '@solana-program/token-2022': 0.20.0(@solana/kit@8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)) + '@solana/keychain-memory': 1.3.0(@solana/addresses@8.5.0(typescript@5.9.3))(@solana/codecs-core@8.5.0(typescript@5.9.3))(@solana/codecs-strings@8.5.0(typescript@5.9.3))(@solana/keys@8.5.0(typescript@5.9.3))(@solana/signers@8.5.0(typescript@5.9.3))(@solana/transactions@8.5.0(typescript@5.9.3)) + '@solana/kit': 8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) + mppx: 0.8.19(express@4.22.2)(typescript@5.9.3)(viem@2.56.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.6.7)) transitivePeerDependencies: - '@modelcontextprotocol/sdk' - '@solana/addresses' @@ -2442,7 +2476,7 @@ snapshots: - utf-8-validate - viem - '@solana/plugin-core@6.9.0(typescript@5.9.3)': + '@solana/plugin-core@8.5.0(typescript@5.9.3)': optionalDependencies: typescript: 5.9.3 @@ -2460,20 +2494,6 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/plugin-interfaces@6.9.0(typescript@5.9.3)': - dependencies: - '@solana/addresses': 6.9.0(typescript@5.9.3) - '@solana/instruction-plans': 6.9.0(typescript@5.9.3) - '@solana/keys': 6.9.0(typescript@5.9.3) - '@solana/rpc-spec': 6.9.0(typescript@5.9.3) - '@solana/rpc-subscriptions-spec': 6.9.0(typescript@5.9.3) - '@solana/rpc-types': 6.9.0(typescript@5.9.3) - '@solana/signers': 6.9.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - '@solana/plugin-interfaces@7.1.1(typescript@5.9.3)': dependencies: '@solana/accounts': 7.1.1(typescript@5.9.3) @@ -2489,6 +2509,22 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/plugin-interfaces@8.5.0(typescript@5.9.3)': + dependencies: + '@solana/accounts': 8.5.0(typescript@5.9.3) + '@solana/addresses': 8.5.0(typescript@5.9.3) + '@solana/instruction-plans': 8.5.0(typescript@5.9.3) + '@solana/keys': 8.5.0(typescript@5.9.3) + '@solana/rpc-spec': 8.5.0(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 8.5.0(typescript@5.9.3) + '@solana/rpc-types': 8.5.0(typescript@5.9.3) + '@solana/signers': 8.5.0(typescript@5.9.3) + '@solana/transactions': 8.5.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) @@ -2505,22 +2541,6 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/program-client-core@6.9.0(typescript@5.9.3)': - dependencies: - '@solana/accounts': 6.9.0(typescript@5.9.3) - '@solana/addresses': 6.9.0(typescript@5.9.3) - '@solana/codecs-core': 6.9.0(typescript@5.9.3) - '@solana/errors': 6.9.0(typescript@5.9.3) - '@solana/instruction-plans': 6.9.0(typescript@5.9.3) - '@solana/instructions': 6.9.0(typescript@5.9.3) - '@solana/plugin-interfaces': 6.9.0(typescript@5.9.3) - '@solana/rpc-api': 6.9.0(typescript@5.9.3) - '@solana/signers': 6.9.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - '@solana/program-client-core@7.1.1(typescript@5.9.3)': dependencies: '@solana/accounts': 7.1.1(typescript@5.9.3) @@ -2537,20 +2557,32 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/programs@6.9.0(typescript@5.9.3)': + '@solana/program-client-core@8.5.0(typescript@5.9.3)': dependencies: - '@solana/addresses': 6.9.0(typescript@5.9.3) - '@solana/errors': 6.9.0(typescript@5.9.3) + '@solana/accounts': 8.5.0(typescript@5.9.3) + '@solana/addresses': 8.5.0(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/instruction-plans': 8.5.0(typescript@5.9.3) + '@solana/instructions': 8.5.0(typescript@5.9.3) + '@solana/plugin-interfaces': 8.5.0(typescript@5.9.3) + '@solana/rpc-api': 8.5.0(typescript@5.9.3) + '@solana/signers': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/promises@6.10.0(typescript@5.9.3)': + '@solana/programs@8.5.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder - '@solana/promises@6.9.0(typescript@5.9.3)': + '@solana/promises@6.10.0(typescript@5.9.3)': optionalDependencies: typescript: 5.9.3 @@ -2558,6 +2590,10 @@ snapshots: optionalDependencies: typescript: 5.9.3 + '@solana/promises@8.5.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) @@ -2576,24 +2612,6 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/rpc-api@6.9.0(typescript@5.9.3)': - dependencies: - '@solana/addresses': 6.9.0(typescript@5.9.3) - '@solana/codecs-core': 6.9.0(typescript@5.9.3) - '@solana/codecs-strings': 6.9.0(typescript@5.9.3) - '@solana/errors': 6.9.0(typescript@5.9.3) - '@solana/keys': 6.9.0(typescript@5.9.3) - '@solana/rpc-parsed-types': 6.9.0(typescript@5.9.3) - '@solana/rpc-spec': 6.9.0(typescript@5.9.3) - '@solana/rpc-transformers': 6.9.0(typescript@5.9.3) - '@solana/rpc-types': 6.9.0(typescript@5.9.3) - '@solana/transaction-messages': 6.9.0(typescript@5.9.3) - '@solana/transactions': 6.9.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - '@solana/rpc-api@7.1.1(typescript@5.9.3)': dependencies: '@solana/addresses': 7.1.1(typescript@5.9.3) @@ -2612,11 +2630,25 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/rpc-parsed-types@6.10.0(typescript@5.9.3)': + '@solana/rpc-api@8.5.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.5.0(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-strings': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/keys': 8.5.0(typescript@5.9.3) + '@solana/rpc-parsed-types': 8.5.0(typescript@5.9.3) + '@solana/rpc-spec': 8.5.0(typescript@5.9.3) + '@solana/rpc-transformers': 8.5.0(typescript@5.9.3) + '@solana/rpc-types': 8.5.0(typescript@5.9.3) + '@solana/transaction-messages': 8.5.0(typescript@5.9.3) + '@solana/transactions': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder - '@solana/rpc-parsed-types@6.9.0(typescript@5.9.3)': + '@solana/rpc-parsed-types@6.10.0(typescript@5.9.3)': optionalDependencies: typescript: 5.9.3 @@ -2624,11 +2656,11 @@ snapshots: optionalDependencies: typescript: 5.9.3 - '@solana/rpc-spec-types@6.10.0(typescript@5.9.3)': + '@solana/rpc-parsed-types@8.5.0(typescript@5.9.3)': optionalDependencies: typescript: 5.9.3 - '@solana/rpc-spec-types@6.9.0(typescript@5.9.3)': + '@solana/rpc-spec-types@6.10.0(typescript@5.9.3)': optionalDependencies: typescript: 5.9.3 @@ -2638,18 +2670,17 @@ snapshots: optionalDependencies: typescript: 5.9.3 - '@solana/rpc-spec@6.10.0(typescript@5.9.3)': + '@solana/rpc-spec-types@8.5.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) + '@solana/errors': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 - '@solana/rpc-spec@6.9.0(typescript@5.9.3)': + '@solana/rpc-spec@6.10.0(typescript@5.9.3)': dependencies: - '@solana/errors': 6.9.0(typescript@5.9.3) - '@solana/rpc-spec-types': 6.9.0(typescript@5.9.3) + '@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 @@ -2661,26 +2692,34 @@ snapshots: optionalDependencies: typescript: 5.9.3 - '@solana/rpc-subscriptions-api@6.9.0(typescript@5.9.3)': + '@solana/rpc-spec@8.5.0(typescript@5.9.3)': dependencies: - '@solana/addresses': 6.9.0(typescript@5.9.3) - '@solana/keys': 6.9.0(typescript@5.9.3) - '@solana/rpc-subscriptions-spec': 6.9.0(typescript@5.9.3) - '@solana/rpc-transformers': 6.9.0(typescript@5.9.3) - '@solana/rpc-types': 6.9.0(typescript@5.9.3) - '@solana/transaction-messages': 6.9.0(typescript@5.9.3) - '@solana/transactions': 6.9.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/rpc-spec-types': 8.5.0(typescript@5.9.3) + '@solana/subscribable': 8.5.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/rpc-subscriptions-api@8.5.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.5.0(typescript@5.9.3) + '@solana/keys': 8.5.0(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 8.5.0(typescript@5.9.3) + '@solana/rpc-transformers': 8.5.0(typescript@5.9.3) + '@solana/rpc-types': 8.5.0(typescript@5.9.3) + '@solana/transaction-messages': 8.5.0(typescript@5.9.3) + '@solana/transactions': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/rpc-subscriptions-channel-websocket@6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)': + '@solana/rpc-subscriptions-channel-websocket@8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)': dependencies: - '@solana/errors': 6.9.0(typescript@5.9.3) - '@solana/functional': 6.9.0(typescript@5.9.3) - '@solana/rpc-subscriptions-spec': 6.9.0(typescript@5.9.3) - '@solana/subscribable': 6.9.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/functional': 8.5.0(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 8.5.0(typescript@5.9.3) + '@solana/subscribable': 8.5.0(typescript@5.9.3) ws: 8.21.0(bufferutil@4.1.0)(utf-8-validate@5.0.10) optionalDependencies: typescript: 5.9.3 @@ -2697,15 +2736,6 @@ snapshots: optionalDependencies: typescript: 5.9.3 - '@solana/rpc-subscriptions-spec@6.9.0(typescript@5.9.3)': - dependencies: - '@solana/errors': 6.9.0(typescript@5.9.3) - '@solana/promises': 6.9.0(typescript@5.9.3) - '@solana/rpc-spec-types': 6.9.0(typescript@5.9.3) - '@solana/subscribable': 6.9.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - '@solana/rpc-subscriptions-spec@7.1.1(typescript@5.9.3)': dependencies: '@solana/errors': 7.1.1(typescript@5.9.3) @@ -2715,19 +2745,28 @@ snapshots: optionalDependencies: typescript: 5.9.3 - '@solana/rpc-subscriptions@6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)': + '@solana/rpc-subscriptions-spec@8.5.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/promises': 8.5.0(typescript@5.9.3) + '@solana/rpc-spec-types': 8.5.0(typescript@5.9.3) + '@solana/subscribable': 8.5.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/rpc-subscriptions@8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)': dependencies: - '@solana/errors': 6.9.0(typescript@5.9.3) - '@solana/fast-stable-stringify': 6.9.0(typescript@5.9.3) - '@solana/functional': 6.9.0(typescript@5.9.3) - '@solana/promises': 6.9.0(typescript@5.9.3) - '@solana/rpc-spec-types': 6.9.0(typescript@5.9.3) - '@solana/rpc-subscriptions-api': 6.9.0(typescript@5.9.3) - '@solana/rpc-subscriptions-channel-websocket': 6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) - '@solana/rpc-subscriptions-spec': 6.9.0(typescript@5.9.3) - '@solana/rpc-transformers': 6.9.0(typescript@5.9.3) - '@solana/rpc-types': 6.9.0(typescript@5.9.3) - '@solana/subscribable': 6.9.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/fast-stable-stringify': 8.5.0(typescript@5.9.3) + '@solana/functional': 8.5.0(typescript@5.9.3) + '@solana/promises': 8.5.0(typescript@5.9.3) + '@solana/rpc-spec-types': 8.5.0(typescript@5.9.3) + '@solana/rpc-subscriptions-api': 8.5.0(typescript@5.9.3) + '@solana/rpc-subscriptions-channel-websocket': 8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) + '@solana/rpc-subscriptions-spec': 8.5.0(typescript@5.9.3) + '@solana/rpc-transformers': 8.5.0(typescript@5.9.3) + '@solana/rpc-types': 8.5.0(typescript@5.9.3) + '@solana/subscribable': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: @@ -2747,18 +2786,6 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/rpc-transformers@6.9.0(typescript@5.9.3)': - dependencies: - '@solana/errors': 6.9.0(typescript@5.9.3) - '@solana/functional': 6.9.0(typescript@5.9.3) - '@solana/nominal-types': 6.9.0(typescript@5.9.3) - '@solana/rpc-spec-types': 6.9.0(typescript@5.9.3) - '@solana/rpc-types': 6.9.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - '@solana/rpc-transformers@7.1.1(typescript@5.9.3)': dependencies: '@solana/errors': 7.1.1(typescript@5.9.3) @@ -2771,12 +2798,24 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/rpc-transport-http@6.9.0(typescript@5.9.3)': + '@solana/rpc-transformers@8.5.0(typescript@5.9.3)': dependencies: - '@solana/errors': 6.9.0(typescript@5.9.3) - '@solana/rpc-spec': 6.9.0(typescript@5.9.3) - '@solana/rpc-spec-types': 6.9.0(typescript@5.9.3) - undici-types: 8.4.1 + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/functional': 8.5.0(typescript@5.9.3) + '@solana/nominal-types': 8.5.0(typescript@5.9.3) + '@solana/rpc-spec-types': 8.5.0(typescript@5.9.3) + '@solana/rpc-types': 8.5.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/rpc-transport-http@8.5.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/rpc-spec': 8.5.0(typescript@5.9.3) + '@solana/rpc-spec-types': 8.5.0(typescript@5.9.3) + undici-types: 8.12.3 optionalDependencies: typescript: 5.9.3 @@ -2794,20 +2833,6 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/rpc-types@6.9.0(typescript@5.9.3)': - dependencies: - '@solana/addresses': 6.9.0(typescript@5.9.3) - '@solana/codecs-core': 6.9.0(typescript@5.9.3) - '@solana/codecs-numbers': 6.9.0(typescript@5.9.3) - '@solana/codecs-strings': 6.9.0(typescript@5.9.3) - '@solana/errors': 6.9.0(typescript@5.9.3) - '@solana/fixed-points': 6.9.0(typescript@5.9.3) - '@solana/nominal-types': 6.9.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - '@solana/rpc-types@7.1.1(typescript@5.9.3)': dependencies: '@solana/addresses': 7.1.1(typescript@5.9.3) @@ -2822,17 +2847,31 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/rpc@6.9.0(typescript@5.9.3)': + '@solana/rpc-types@8.5.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.5.0(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.5.0(typescript@5.9.3) + '@solana/codecs-strings': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/fixed-points': 8.5.0(typescript@5.9.3) + '@solana/nominal-types': 8.5.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/rpc@8.5.0(typescript@5.9.3)': dependencies: - '@solana/errors': 6.9.0(typescript@5.9.3) - '@solana/fast-stable-stringify': 6.9.0(typescript@5.9.3) - '@solana/functional': 6.9.0(typescript@5.9.3) - '@solana/rpc-api': 6.9.0(typescript@5.9.3) - '@solana/rpc-spec': 6.9.0(typescript@5.9.3) - '@solana/rpc-spec-types': 6.9.0(typescript@5.9.3) - '@solana/rpc-transformers': 6.9.0(typescript@5.9.3) - '@solana/rpc-transport-http': 6.9.0(typescript@5.9.3) - '@solana/rpc-types': 6.9.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/fast-stable-stringify': 8.5.0(typescript@5.9.3) + '@solana/functional': 8.5.0(typescript@5.9.3) + '@solana/rpc-api': 8.5.0(typescript@5.9.3) + '@solana/rpc-spec': 8.5.0(typescript@5.9.3) + '@solana/rpc-spec-types': 8.5.0(typescript@5.9.3) + '@solana/rpc-transformers': 8.5.0(typescript@5.9.3) + '@solana/rpc-transport-http': 8.5.0(typescript@5.9.3) + '@solana/rpc-types': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: @@ -2854,22 +2893,6 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/signers@6.9.0(typescript@5.9.3)': - dependencies: - '@solana/addresses': 6.9.0(typescript@5.9.3) - '@solana/codecs-core': 6.9.0(typescript@5.9.3) - '@solana/errors': 6.9.0(typescript@5.9.3) - '@solana/instructions': 6.9.0(typescript@5.9.3) - '@solana/keys': 6.9.0(typescript@5.9.3) - '@solana/nominal-types': 6.9.0(typescript@5.9.3) - '@solana/offchain-messages': 6.9.0(typescript@5.9.3) - '@solana/transaction-messages': 6.9.0(typescript@5.9.3) - '@solana/transactions': 6.9.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - '@solana/signers@7.1.1(typescript@5.9.3)': dependencies: '@solana/addresses': 7.1.1(typescript@5.9.3) @@ -2886,16 +2909,26 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/subscribable@6.10.0(typescript@5.9.3)': + '@solana/signers@8.5.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/addresses': 8.5.0(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/instructions': 8.5.0(typescript@5.9.3) + '@solana/keys': 8.5.0(typescript@5.9.3) + '@solana/nominal-types': 8.5.0(typescript@5.9.3) + '@solana/offchain-messages': 8.5.0(typescript@5.9.3) + '@solana/transaction-messages': 8.5.0(typescript@5.9.3) + '@solana/transactions': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder - '@solana/subscribable@6.9.0(typescript@5.9.3)': + '@solana/subscribable@6.10.0(typescript@5.9.3)': dependencies: - '@solana/errors': 6.9.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/promises': 6.10.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 @@ -2906,13 +2939,20 @@ snapshots: optionalDependencies: typescript: 5.9.3 - '@solana/subscriptions@0.5.0(@solana/kit@6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10))(typescript@5.9.3)': + '@solana/subscribable@8.5.0(typescript@5.9.3)': dependencies: - '@solana-program/token': 0.15.0(@solana/kit@6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)) - '@solana-program/token-2022': 0.14.1(@solana/kit@6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)) - '@solana/kit': 6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) - '@solana/kit-plugin-rpc': 0.15.0(@solana/kit@6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)) - '@solana/kit-plugin-signer': 0.13.0(@solana/kit@6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/promises': 8.5.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/subscriptions@0.5.0(@solana/kit@8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10))(typescript@5.9.3)': + dependencies: + '@solana-program/token': 0.15.0(@solana/kit@8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)) + '@solana-program/token-2022': 0.14.1(@solana/kit@8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)) + '@solana/kit': 8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) + '@solana/kit-plugin-rpc': 0.15.0(@solana/kit@8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)) + '@solana/kit-plugin-signer': 0.13.0(@solana/kit@8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)) '@solana/program-client-core': 7.1.1(typescript@5.9.3) transitivePeerDependencies: - '@solana/sysvars' @@ -2920,31 +2960,31 @@ snapshots: - fastestsmallesttextencoderdecoder - typescript - '@solana/sysvars@6.9.0(typescript@5.9.3)': + '@solana/sysvars@8.5.0(typescript@5.9.3)': dependencies: - '@solana/accounts': 6.9.0(typescript@5.9.3) - '@solana/codecs-core': 6.9.0(typescript@5.9.3) - '@solana/codecs-data-structures': 6.9.0(typescript@5.9.3) - '@solana/codecs-numbers': 6.9.0(typescript@5.9.3) - '@solana/errors': 6.9.0(typescript@5.9.3) - '@solana/rpc-types': 6.9.0(typescript@5.9.3) + '@solana/accounts': 8.5.0(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-data-structures': 8.5.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/rpc-types': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/transaction-confirmation@6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)': + '@solana/transaction-confirmation@8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)': dependencies: - '@solana/addresses': 6.9.0(typescript@5.9.3) - '@solana/codecs-strings': 6.9.0(typescript@5.9.3) - '@solana/errors': 6.9.0(typescript@5.9.3) - '@solana/keys': 6.9.0(typescript@5.9.3) - '@solana/promises': 6.9.0(typescript@5.9.3) - '@solana/rpc': 6.9.0(typescript@5.9.3) - '@solana/rpc-subscriptions': 6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) - '@solana/rpc-types': 6.9.0(typescript@5.9.3) - '@solana/transaction-messages': 6.9.0(typescript@5.9.3) - '@solana/transactions': 6.9.0(typescript@5.9.3) + '@solana/addresses': 8.5.0(typescript@5.9.3) + '@solana/codecs-strings': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/keys': 8.5.0(typescript@5.9.3) + '@solana/promises': 8.5.0(typescript@5.9.3) + '@solana/rpc': 8.5.0(typescript@5.9.3) + '@solana/rpc-subscriptions': 8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) + '@solana/rpc-types': 8.5.0(typescript@5.9.3) + '@solana/transaction-messages': 8.5.0(typescript@5.9.3) + '@solana/transactions': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: @@ -2952,6 +2992,21 @@ snapshots: - fastestsmallesttextencoderdecoder - utf-8-validate + '@solana/transaction-introspection@8.5.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.5.0(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-strings': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/instructions': 8.5.0(typescript@5.9.3) + '@solana/rpc-types': 8.5.0(typescript@5.9.3) + '@solana/transaction-messages': 8.5.0(typescript@5.9.3) + '@solana/transactions': 8.5.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) @@ -2968,22 +3023,6 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/transaction-messages@6.9.0(typescript@5.9.3)': - dependencies: - '@solana/addresses': 6.9.0(typescript@5.9.3) - '@solana/codecs-core': 6.9.0(typescript@5.9.3) - '@solana/codecs-data-structures': 6.9.0(typescript@5.9.3) - '@solana/codecs-numbers': 6.9.0(typescript@5.9.3) - '@solana/errors': 6.9.0(typescript@5.9.3) - '@solana/functional': 6.9.0(typescript@5.9.3) - '@solana/instructions': 6.9.0(typescript@5.9.3) - '@solana/nominal-types': 6.9.0(typescript@5.9.3) - '@solana/rpc-types': 6.9.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - '@solana/transaction-messages@7.1.1(typescript@5.9.3)': dependencies: '@solana/addresses': 7.1.1(typescript@5.9.3) @@ -3000,6 +3039,22 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/transaction-messages@8.5.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.5.0(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-data-structures': 8.5.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/functional': 8.5.0(typescript@5.9.3) + '@solana/instructions': 8.5.0(typescript@5.9.3) + '@solana/nominal-types': 8.5.0(typescript@5.9.3) + '@solana/rpc-types': 8.5.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) @@ -3019,25 +3074,6 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/transactions@6.9.0(typescript@5.9.3)': - dependencies: - '@solana/addresses': 6.9.0(typescript@5.9.3) - '@solana/codecs-core': 6.9.0(typescript@5.9.3) - '@solana/codecs-data-structures': 6.9.0(typescript@5.9.3) - '@solana/codecs-numbers': 6.9.0(typescript@5.9.3) - '@solana/codecs-strings': 6.9.0(typescript@5.9.3) - '@solana/errors': 6.9.0(typescript@5.9.3) - '@solana/functional': 6.9.0(typescript@5.9.3) - '@solana/instructions': 6.9.0(typescript@5.9.3) - '@solana/keys': 6.9.0(typescript@5.9.3) - '@solana/nominal-types': 6.9.0(typescript@5.9.3) - '@solana/rpc-types': 6.9.0(typescript@5.9.3) - '@solana/transaction-messages': 6.9.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - '@solana/transactions@7.1.1(typescript@5.9.3)': dependencies: '@solana/addresses': 7.1.1(typescript@5.9.3) @@ -3057,6 +3093,25 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/transactions@8.5.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.5.0(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-data-structures': 8.5.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.5.0(typescript@5.9.3) + '@solana/codecs-strings': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/functional': 8.5.0(typescript@5.9.3) + '@solana/instructions': 8.5.0(typescript@5.9.3) + '@solana/keys': 8.5.0(typescript@5.9.3) + '@solana/nominal-types': 8.5.0(typescript@5.9.3) + '@solana/rpc-types': 8.5.0(typescript@5.9.3) + '@solana/transaction-messages': 8.5.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@stripe/stripe-js@9.13.0': {} '@types/body-parser@1.19.6': @@ -3104,15 +3159,15 @@ snapshots: '@types/http-errors': 2.0.5 '@types/node': 25.9.3 - abitype@1.2.3(typescript@5.9.3)(zod@4.4.3): + abitype@1.2.3(typescript@5.9.3)(zod@4.6.7): optionalDependencies: typescript: 5.9.3 - zod: 4.4.3 + zod: 4.6.7 - abitype@1.2.4(typescript@5.9.3)(zod@4.4.3): + abitype@1.2.4(typescript@5.9.3)(zod@4.6.7): optionalDependencies: typescript: 5.9.3 - zod: 4.4.3 + zod: 4.6.7 accepts@1.3.8: dependencies: @@ -3121,7 +3176,7 @@ snapshots: array-flatten@1.1.1: {} - body-parser@1.20.5: + body-parser@1.20.9: dependencies: bytes: 3.1.2 content-type: 1.0.5 @@ -3157,8 +3212,6 @@ snapshots: chalk@5.6.2: {} - commander@14.0.3: {} - commander@15.0.0: {} content-disposition@0.5.4: @@ -3247,7 +3300,7 @@ snapshots: dependencies: debug: 4.4.3 express: 4.22.2 - ip-address: 10.7.2 + ip-address: 10.7.4 transitivePeerDependencies: - supports-color @@ -3255,7 +3308,7 @@ snapshots: dependencies: accepts: 1.3.8 array-flatten: 1.1.1 - body-parser: 1.20.5 + body-parser: 1.20.9 content-disposition: 0.5.4 content-type: 1.0.5 cookie: 0.7.2 @@ -3334,9 +3387,6 @@ snapshots: dependencies: function-bind: 1.1.2 - hono@4.13.7: - optional: true - http-errors@2.0.1: dependencies: depd: 2.0.0 @@ -3351,7 +3401,7 @@ snapshots: inherits@2.0.4: {} - ip-address@10.7.2: {} + ip-address@10.7.4: {} ipaddr.js@1.9.1: {} @@ -3375,17 +3425,16 @@ snapshots: mime@1.6.0: {} - mppx@0.8.19(express@4.22.2)(hono@4.13.7)(typescript@5.9.3)(viem@2.56.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.4.3)): + mppx@0.8.19(express@4.22.2)(typescript@5.9.3)(viem@2.56.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.6.7)): dependencies: '@stripe/stripe-js': 9.13.0 eventsource-parser: 3.1.1 - ox: 0.14.33(typescript@5.9.3)(zod@4.4.3) + ox: 0.14.33(typescript@5.9.3)(zod@4.6.7) structured-headers: 2.0.3 - viem: 2.56.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.4.3) - zod: 4.4.3 + viem: 2.56.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.6.7) + zod: 4.6.7 optionalDependencies: express: 4.22.2 - hono: 4.13.7 transitivePeerDependencies: - typescript @@ -3406,7 +3455,7 @@ snapshots: dependencies: ee-first: 1.1.1 - ox@0.14.33(typescript@5.9.3)(zod@4.4.3): + ox@0.14.33(typescript@5.9.3)(zod@4.6.7): dependencies: '@adraffy/ens-normalize': 1.11.1 '@noble/ciphers': 1.3.0 @@ -3414,14 +3463,14 @@ snapshots: '@noble/hashes': 1.8.0 '@scure/bip32': 1.7.0 '@scure/bip39': 1.6.0 - abitype: 1.2.4(typescript@5.9.3)(zod@4.4.3) + abitype: 1.2.4(typescript@5.9.3)(zod@4.6.7) eventemitter3: 5.0.1 optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: - zod - ox@0.14.44(typescript@5.9.3)(zod@4.4.3): + ox@0.14.44(typescript@5.9.3)(zod@4.6.7): dependencies: '@adraffy/ens-normalize': 1.11.1 '@noble/ciphers': 1.3.0 @@ -3429,7 +3478,7 @@ snapshots: '@noble/hashes': 1.8.0 '@scure/bip32': 1.7.0 '@scure/bip39': 1.6.0 - abitype: 1.2.4(typescript@5.9.3)(zod@4.4.3) + abitype: 1.2.4(typescript@5.9.3)(zod@4.6.7) eventemitter3: 5.0.1 optionalDependencies: typescript: 5.9.3 @@ -3541,7 +3590,7 @@ snapshots: undici-types@7.24.6: {} - undici-types@8.4.1: {} + undici-types@8.12.3: {} unpipe@1.0.0: {} @@ -3554,15 +3603,15 @@ snapshots: vary@1.1.2: {} - viem@2.56.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.4.3): + viem@2.56.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.6.7): dependencies: '@noble/curves': 1.9.1 '@noble/hashes': 1.8.0 '@scure/bip32': 1.7.0 '@scure/bip39': 1.6.0 - abitype: 1.2.3(typescript@5.9.3)(zod@4.4.3) + abitype: 1.2.3(typescript@5.9.3)(zod@4.6.7) isows: 1.0.7(ws@8.21.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)) - ox: 0.14.44(typescript@5.9.3)(zod@4.4.3) + ox: 0.14.44(typescript@5.9.3)(zod@4.6.7) ws: 8.21.0(bufferutil@4.1.0)(utf-8-validate@5.0.10) optionalDependencies: typescript: 5.9.3 @@ -3576,4 +3625,4 @@ snapshots: bufferutil: 4.1.0 utf-8-validate: 5.0.10 - zod@4.4.3: {} + zod@4.6.7: {} diff --git a/typescript/examples/playground-api/pnpm-workspace.yaml b/typescript/examples/playground-api/pnpm-workspace.yaml index 0678df252..fcb412b80 100644 --- a/typescript/examples/playground-api/pnpm-workspace.yaml +++ b/typescript/examples/playground-api/pnpm-workspace.yaml @@ -9,8 +9,10 @@ overrides: '@hono/node-server': '1.19.15' '@modelcontextprotocol/sdk': '1.31.0' fast-uri: '4.1.5' - hono: '4.13.7' - ip-address: '10.7.2' + hono: '4.13.14' + 'body-parser@1': '1.20.9' + zod: '4.6.7' + ip-address: '10.7.4' proxy-addr: '2.0.8' qs: '6.16.0' ws: '8.21.0' diff --git a/typescript/external/x402 b/typescript/external/x402 index 03b3919b3..d411aea10 160000 --- a/typescript/external/x402 +++ b/typescript/external/x402 @@ -1 +1 @@ -Subproject commit 03b3919b3d422d2b094ea3539e0b577558e1ae86 +Subproject commit d411aea104d17926465c91755fdfe12b0f445fc0 diff --git a/typescript/package.json b/typescript/package.json index 7bb687118..21ce36d1c 100644 --- a/typescript/package.json +++ b/typescript/package.json @@ -27,12 +27,12 @@ "@solana/prettier-config-solana": "^0.0.6", "@typescript-eslint/eslint-plugin": "^8.57.1", "@typescript-eslint/parser": "^8.57.1", - "@vitest/coverage-v8": "4.1.11", + "@vitest/coverage-v8": "4.1.12", "eslint": "^9.39.4", "prettier": "^3.8.1", "typedoc": "^0.28.0", "typedoc-plugin-markdown": "^4.12.0", "typescript": "^5.7.0", - "vitest": "4.1.11" + "vitest": "4.1.12" } } diff --git a/typescript/packages/mpp/package.json b/typescript/packages/mpp/package.json index dbbca2ce3..060ce8ee9 100644 --- a/typescript/packages/mpp/package.json +++ b/typescript/packages/mpp/package.json @@ -1,6 +1,6 @@ { "name": "@solana/mpp", - "version": "0.11.0", + "version": "0.11.1", "description": "Solana payment method for the MPP protocol", "repository": { "type": "git", @@ -37,7 +37,7 @@ "@solana/addresses": "^6.10.0", "@solana/program-client-core": "^6.10.0", "@solana/subscriptions": "^0.5.0", - "zod": "^4.4.3" + "zod": "^4.6.6" }, "peerDependencies": { "@solana/kit": ">=6.10.0", diff --git a/typescript/packages/mpp/src/Methods.ts b/typescript/packages/mpp/src/Methods.ts index 37a39f920..49fef5e8e 100644 --- a/typescript/packages/mpp/src/Methods.ts +++ b/typescript/packages/mpp/src/Methods.ts @@ -1,5 +1,7 @@ import { Method, z } from 'mppx'; +import { TOKEN_2022_PROGRAM, TOKEN_PROGRAM } from './constants.js'; + const sessionVoucherSigner = z.enum(['client', 'operator']); const sessionAuthentication = z.object({ challengeId: z.string(), @@ -125,6 +127,45 @@ export const charge = Method.from({ const subscriptionPeriodUnit = z.enum(['day', 'week']); +/** + * draft-solana-subscription-00 §Shared Fields: `amount` and `periodCount` + * "MUST be a string representation of a positive integer in base 10 with no + * sign, decimal point, exponent, or surrounding whitespace. Leading zeros + * MUST NOT be used." + */ +const SUBSCRIPTION_POSITIVE_INTEGER = /^[1-9][0-9]*$/; +const U64_MAX = (1n << 64n) - 1n; + +const subscriptionAmount = z.string().check( + z.regex( + SUBSCRIPTION_POSITIVE_INTEGER, + 'amount must be a positive base-10 integer with no sign, decimal point, exponent, whitespace, or leading zeros', + ), + z.refine( + value => !SUBSCRIPTION_POSITIVE_INTEGER.test(value) || BigInt(value) <= U64_MAX, + 'amount must fit in a u64', + ), +); + +const subscriptionPeriodCount = z + .string() + .check( + z.regex( + SUBSCRIPTION_POSITIVE_INTEGER, + 'periodCount must be a positive base-10 integer with no sign, decimal point, exponent, whitespace, or leading zeros', + ), + ); + +/** §Method Details: tokenProgram "MUST be the SPL Token program or the SPL Token-2022 program". */ +const subscriptionTokenProgram = z + .string() + .check( + z.refine( + value => value === TOKEN_PROGRAM || value === TOKEN_2022_PROGRAM, + `tokenProgram must be ${TOKEN_PROGRAM} or ${TOKEN_2022_PROGRAM}`, + ), + ); + /** * Solana subscription method — shared schema used by both server and client. * @@ -167,8 +208,8 @@ export const subscription = Method.from({ ]), }, request: z.object({ - /** Per-period token amount in base units. */ - amount: z.string(), + /** Per-period token amount in base units (positive base-10 integer, no leading zeros). */ + amount: subscriptionAmount, /** Base58 SPL token mint address. */ currency: z.string(), /** Human-readable subscription description. */ @@ -210,10 +251,10 @@ export const subscription = Method.from({ /** Base58 of the subscriptions program deployment. */ subscriptionProgram: z.string(), /** Base58 of the SPL Token or Token-2022 program ID. */ - tokenProgram: z.string(), + tokenProgram: subscriptionTokenProgram, }), - /** Positive integer count of `periodUnit` values per billing period. */ - periodCount: z.string(), + /** Positive integer count of `periodUnit` values per billing period (base 10, no leading zeros). */ + periodCount: subscriptionPeriodCount, /** Billing period unit. The Solana profile supports `day` and `week` only. */ periodUnit: subscriptionPeriodUnit, /** Primary recipient's wallet pubkey (base58). */ @@ -257,6 +298,12 @@ export const session = Method.from({ payer: z.string(), salt: z.string(), transaction: z.string(), + /** + * draft-solana-session-00 Action open: the open payload + * "MUST NOT carry an initial voucher". Rejected here rather + * than silently stripped as an unknown key. + */ + voucher: z.optional(z.never()), }), z.object({ action: z.literal('voucher'), diff --git a/typescript/packages/mpp/src/__tests__/charge.test.ts b/typescript/packages/mpp/src/__tests__/charge.test.ts index 24efbd46c..2d63608e8 100644 --- a/typescript/packages/mpp/src/__tests__/charge.test.ts +++ b/typescript/packages/mpp/src/__tests__/charge.test.ts @@ -4031,3 +4031,85 @@ test('#3 interpretPostTimeoutStatus: rpc error returns timeout with detail', () const outcome = interpretPostTimeoutStatus(null, 'connection refused'); expect(outcome).toEqual({ detail: 'connection refused', kind: 'timeout' }); }); + +// draft-solana-charge-00 §Transaction payload: "The transaction MUST be a valid +// Solana versioned transaction that does not exceed the 1232-byte transaction +// size limit." +test('verifyChargeTransaction rejects a transaction over the 1232-byte limit', async () => { + const signer = await generateKeyPairSigner(); + const memo = (char: string) => char.repeat(560); + const request = { + amount: '1000000', + currency: 'sol', + externalId: memo('a'), + methodDetails: { + network: 'devnet', + recentBlockhash: BLOCKHASH, + splits: [ + { amount: '1000', memo: memo('b'), recipient: '3pF8Kg2aHbNvJkLMwEqR7YtDxZ5sGhJn4UV6mWcXrT9A' }, + { amount: '1000', memo: memo('c'), recipient: '11111111111111111111111111111112' }, + ], + }, + recipient: RECIPIENT, + }; + // The client builder does not bound the size; the verifier must. + const tx = await buildChargeTransaction({ request, signer }); + expect(getBase64Codec().encode(tx).byteLength).toBeGreaterThan(1232); + await expect(verifyChargeTransaction(tx, request)).rejects.toThrow( + /Transaction is \d+ bytes, over the 1232-byte limit/, + ); +}); + +test('verifyChargeTransaction accepts a transaction within the 1232-byte limit', async () => { + const signer = await generateKeyPairSigner(); + const request = { + amount: '1000000', + currency: 'sol', + externalId: 'a'.repeat(400), + methodDetails: { network: 'devnet', recentBlockhash: BLOCKHASH }, + recipient: RECIPIENT, + }; + const tx = await buildChargeTransaction({ request, signer }); + expect(getBase64Codec().encode(tx).byteLength).toBeLessThanOrEqual(1232); + await expect(verifyChargeTransaction(tx, request)).resolves.toBeUndefined(); +}); + +// An ATA Create (non-idempotent) instruction carries empty data, which the kit +// decoder omits; the policy check must reject it, not crash with a TypeError. +test('verifyChargeTransaction rejects a non-idempotent (empty-data) ATA creation as a policy violation', async () => { + const payer = await generateKeyPairSigner(); + const split = '3pF8Kg2aHbNvJkLMwEqR7YtDxZ5sGhJn4UV6mWcXrT9A'; + const mint = address(USDC_MINT); + const tokenProgram = address(TOKEN_PROGRAM); + const ataOf = async (owner: string) => + (await findAssociatedTokenPda({ mint, owner: address(owner), tokenProgram }))[0]; + const sourceAta = await ataOf(payer.address); + const transfer = async (owner: string, amount: bigint) => + getTransferCheckedInstruction( + { amount, authority: payer, decimals: 6, destination: await ataOf(owner), mint, source: sourceAta }, + { programAddress: tokenProgram }, + ); + const idempotent = await createAssociatedTokenAccountIdempotent(payer.address, address(split), mint, tokenProgram); + const createNonIdempotent: Instruction = { ...idempotent, data: new Uint8Array() }; + const instructions = [await transfer(RECIPIENT, 750n), createNonIdempotent, await transfer(split, 250n)]; + const message = pipe( + createTransactionMessage({ version: 0 }), + msg => setTransactionMessageFeePayerSigner(payer, msg), + msg => setTransactionMessageLifetimeUsingBlockhash({ blockhash: BLOCKHASH, lastValidBlockHeight: 1n }, msg), + msg => appendTransactionMessageInstructions(instructions, msg), + ); + const tx = getBase64EncodedWireTransaction(await partiallySignTransactionMessageWithSigners(message)); + await expect( + verifyChargeTransaction(tx, { + amount: '1000', + currency: USDC_MINT, + methodDetails: { + decimals: 6, + network: 'devnet', + splits: [{ amount: '250', ataCreationRequired: true, recipient: split }], + tokenProgram: TOKEN_PROGRAM, + }, + recipient: RECIPIENT, + }), + ).rejects.toThrow(/Only idempotent ATA creation is allowed/); +}); diff --git a/typescript/packages/mpp/src/__tests__/client-charge-validation.test.ts b/typescript/packages/mpp/src/__tests__/client-charge-validation.test.ts index 0231140e0..5e430c56a 100644 --- a/typescript/packages/mpp/src/__tests__/client-charge-validation.test.ts +++ b/typescript/packages/mpp/src/__tests__/client-charge-validation.test.ts @@ -465,3 +465,131 @@ test('#10 createCredential rejects a network that does not match expectedNetwork }); await expect(method.createCredential({ challenge })).rejects.toThrow(/does not match the expected network/); }); + +// ── draft-solana-charge-00 challenge checks the client applies before any RPC ── + +/** An RPC endpoint that fails the test if the builder asks it anything. */ +const UNREACHABLE_RPC = 'http://127.0.0.1:1'; + +function splRequest( + overrides: { amount?: string; network?: string; splits?: Array<{ amount: string; recipient: string }> } = {}, +) { + return { + amount: overrides.amount ?? '1000', + currency: USDC_MINT, + recipient: RECIPIENT, + methodDetails: { + decimals: 6, + network: overrides.network ?? 'devnet', + recentBlockhash: BLOCKHASH, + ...(overrides.splits ? { splits: overrides.splits } : {}), + tokenProgram: TOKEN_PROGRAM, + }, + }; +} + +// §Method Details, splits: "An array of at most 8 additional payment splits." +test('buildChargeTransaction refuses more than 8 splits', async () => { + const signer = await newSigner(); + const splits = Array.from({ length: 9 }, () => ({ amount: '10', recipient: RECIPIENT })); + await expect( + buildChargeTransaction({ request: splRequest({ splits }), rpcUrl: UNREACHABLE_RPC, signer }), + ).rejects.toThrow(/Too many splits: 9 \(maximum 8\)/); +}); + +test('buildChargeTransaction accepts exactly 8 splits', async () => { + const signer = await newSigner(); + const splits = Array.from({ length: 8 }, () => ({ amount: '10', recipient: RECIPIENT })); + await expect( + buildChargeTransaction({ request: splRequest({ splits }), rpcUrl: UNREACHABLE_RPC, signer }), + ).resolves.toBeTruthy(); +}); + +// §Method Details, tokenProgram: "MUST NOT be present when currency is \"sol\"". +test('buildChargeTransaction refuses a SOL charge whose challenge carries tokenProgram', async () => { + const signer = await newSigner(); + await expect( + buildChargeTransaction({ + request: { + amount: '1000', + currency: 'sol', + recipient: RECIPIENT, + methodDetails: { network: 'localnet', recentBlockhash: BLOCKHASH, tokenProgram: TOKEN_PROGRAM }, + }, + rpcUrl: UNREACHABLE_RPC, + signer, + }), + ).rejects.toThrow(/tokenProgram must not be present when currency is "sol"/); +}); + +// §Method Details, network: "MUST be one of \"mainnet\", \"devnet\", or \"localnet\"". +test('buildChargeTransaction refuses an unknown network instead of falling back to mainnet', async () => { + const signer = await newSigner(); + for (const network of ['testnet', 'mainnet-alpha', '']) { + await expect( + buildChargeTransaction({ request: splRequest({ network }), rpcUrl: UNREACHABLE_RPC, signer }), + ).rejects.toThrow(/Unsupported challenge network/); + } +}); + +test('buildChargeTransaction accepts the mainnet-beta alias', async () => { + const signer = await newSigner(); + await expect( + buildChargeTransaction({ + request: { + ...splRequest({ network: 'mainnet-beta' }), + currency: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', + }, + rpcUrl: UNREACHABLE_RPC, + signer, + }), + ).resolves.toBeTruthy(); +}); + +// §Request Schema, amount: "a positive integer that fits in a 64-bit unsigned integer". +test('buildChargeTransaction refuses an amount above u64 with an explicit check', async () => { + const signer = await newSigner(); + await expect( + buildChargeTransaction({ + request: splRequest({ amount: '18446744073709551616' }), + rpcUrl: UNREACHABLE_RPC, + signer, + }), + ).rejects.toThrow(/Invalid amount: amount 18446744073709551616 does not fit in a u64/); +}); + +test('buildChargeTransaction accepts an amount of exactly u64::MAX', async () => { + const signer = await newSigner(); + await expect( + buildChargeTransaction({ + request: splRequest({ amount: '18446744073709551615' }), + rpcUrl: UNREACHABLE_RPC, + signer, + }), + ).resolves.toBeTruthy(); +}); + +test('buildChargeTransaction refuses a zero amount', async () => { + const signer = await newSigner(); + await expect( + buildChargeTransaction({ request: splRequest({ amount: '0' }), rpcUrl: UNREACHABLE_RPC, signer }), + ).rejects.toThrow(/Splits consume the entire amount/); +}); + +test.each(['-1', '1e3', ' 1000', '1000.0', ''])('buildChargeTransaction refuses amount %j', async amount => { + const signer = await newSigner(); + await expect( + buildChargeTransaction({ request: splRequest({ amount }), rpcUrl: UNREACHABLE_RPC, signer }), + ).rejects.toThrow(/Invalid amount/); +}); + +test('buildChargeTransaction refuses a split amount above u64', async () => { + const signer = await newSigner(); + await expect( + buildChargeTransaction({ + request: splRequest({ splits: [{ amount: '18446744073709551616', recipient: RECIPIENT }] }), + rpcUrl: UNREACHABLE_RPC, + signer, + }), + ).rejects.toThrow(/Invalid amount: split amount .* does not fit in a u64/); +}); diff --git a/typescript/packages/mpp/src/__tests__/methods.test.ts b/typescript/packages/mpp/src/__tests__/methods.test.ts index 1ee26f117..711b1910e 100644 --- a/typescript/packages/mpp/src/__tests__/methods.test.ts +++ b/typescript/packages/mpp/src/__tests__/methods.test.ts @@ -33,3 +33,37 @@ describe('session method definition', () => { expect(session.schema.credential.payload).toBeDefined(); }); }); + +// draft-solana-session-00 Action open: "MUST NOT carry an initial voucher". +describe('session open payload', () => { + const open = { + action: 'open', + authorizedSigner: 'Config1111111111111111111111111111111111111', + channelId: 'cGfHiC6Kgg3FpFZvgwGcswsCRtp4aBP2fzuXRQPizuN', + depositAmount: '5000', + gracePeriodSeconds: 900, + mint: '4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU', + openSlot: '250000000', + payee: 'Stake11111111111111111111111111111111111111', + payer: 'Vote111111111111111111111111111111111111111', + salt: '7777', + transaction: 'AQID', + }; + + test('accepts an open payload without a voucher', () => { + expect(session.schema.credential.payload.safeParse(open).success).toBe(true); + }); + + test('rejects an open payload carrying a signed voucher', () => { + const parsed = session.schema.credential.payload.safeParse({ + ...open, + voucher: { + signature: 'sig', + signatureType: 'ed25519', + signer: open.authorizedSigner, + voucher: { channelId: open.channelId, cumulativeAmount: '250', expiresAt: 4102444800 }, + }, + }); + expect(parsed.success).toBe(false); + }); +}); diff --git a/typescript/packages/mpp/src/__tests__/subscription-client.test.ts b/typescript/packages/mpp/src/__tests__/subscription-client.test.ts index 271ddff84..39cb074ab 100644 --- a/typescript/packages/mpp/src/__tests__/subscription-client.test.ts +++ b/typescript/packages/mpp/src/__tests__/subscription-client.test.ts @@ -18,6 +18,7 @@ import { import { getPlanEncoder, getSubscriptionAuthorityEncoder } from '@solana/subscriptions'; import { + ASSOCIATED_TOKEN_PROGRAM, SUBSCRIPTIONS_PROGRAM, SUBSCRIPTIONS_SUBSCRIBE_DISCRIMINATOR, SUBSCRIPTIONS_TRANSFER_DISCRIMINATOR, @@ -57,7 +58,21 @@ function rpcSuccess(result: unknown) { * blockhash for getLatestBlockhash, accept sendTransaction, and report the * signature as confirmed. */ -function defaultMockFetch(opts: { authorityExists?: boolean } = { authorityExists: true }): typeof globalThis.fetch { +const ZERO = '11111111111111111111111111111111'; + +/** Pad a Plan address list to the program's fixed four slots with the zero address. */ +function padded(list: readonly string[]): Address[] { + return [...list, ZERO, ZERO, ZERO, ZERO].slice(0, 4).map(entry => address(entry)); +} + +function defaultMockFetch( + opts: { + authorityExists?: boolean; + planDestinations?: readonly string[]; + planOwner?: string; + planPullers?: readonly string[]; + } = { authorityExists: true }, +): typeof globalThis.fetch { return async (_input: RequestInfo | URL, init?: RequestInit) => { const body = JSON.parse(init?.body as string) as { method?: string; params?: unknown[] }; switch (body.method) { @@ -67,26 +82,16 @@ function defaultMockFetch(opts: { authorityExists?: boolean } = { authorityExist const encoded = getPlanEncoder().encode({ bump: 1, data: { - destinations: [ - address(RECIPIENT), - address('11111111111111111111111111111111'), - address('11111111111111111111111111111111'), - address('11111111111111111111111111111111'), - ], + destinations: padded(opts.planDestinations ?? [RECIPIENT]), endTs: 0n, metadataUri: '', mint: address(MINT), planId: 1n, - pullers: [ - address(PULLER), - address('11111111111111111111111111111111'), - address('11111111111111111111111111111111'), - address('11111111111111111111111111111111'), - ], + pullers: padded(opts.planPullers ?? [PULLER]), terms: { amount: 10_000_000n, createdAt: 1n, periodHours: 720n }, }, discriminator: 1, - owner: address(PULLER), + owner: address(opts.planOwner ?? PULLER), status: 1, }); return rpcSuccess({ @@ -94,7 +99,7 @@ function defaultMockFetch(opts: { authorityExists?: boolean } = { authorityExist value: accountValue(getBase64Codec().decode(encoded)), }); } - if (!opts.authorityExists) return rpcSuccess({ context: { slot: 1 }, value: null }); + if (opts.authorityExists === false) return rpcSuccess({ context: { slot: 1 }, value: null }); const encoded = getSubscriptionAuthorityEncoder().encode({ bump: 1, discriminator: 0, @@ -131,7 +136,7 @@ function accountValue(data: string) { } type CompiledMessage = { - instructions: readonly { data: Uint8Array; programAddressIndex: number }[]; + instructions: readonly { accountIndices?: readonly number[]; data: Uint8Array; programAddressIndex: number }[]; staticAccounts: readonly { toString(): string }[]; }; @@ -351,6 +356,161 @@ describe('buildSubscriptionActivationTransaction', () => { }); }); +// ══════════════════════════════════════════════════════════════════════ +// Challenge and plan checks (draft-solana-subscription-00) +// ══════════════════════════════════════════════════════════════════════ + +/** An RPC that fails the test if the builder asks it anything. */ +const noRpc: typeof globalThis.fetch = () => Promise.reject(new Error('the builder must refuse before any RPC call')); + +describe('buildSubscriptionActivationTransaction challenge checks', () => { + // §Activation: "no instructions other than those above plus optional + // compute-budget and memo instructions" — only the subscriber's own ATA + // (as the Rust kit builds) is created; never the recipient's. + test("creates only the subscriber's ATA, not the recipient's", async () => { + globalThis.fetch = defaultMockFetch(); + const signer = await generateKeyPairSigner(); + const tx = await buildSubscriptionActivationTransaction({ + request: baseRequest(), + rpcUrl: 'https://mock-rpc', + signer, + }); + const message = decodeMessage(tx); + const ataCreations = message.instructions.filter( + ix => message.staticAccounts[ix.programAddressIndex].toString() === ASSOCIATED_TOKEN_PROGRAM, + ); + expect(ataCreations).toHaveLength(1); + const owner = message.staticAccounts[ataCreations[0].accountIndices![2]].toString(); + expect(owner).toBe(signer.address); + }); + + // §Intent Semantics: "clients MUST validate that address before signing". + test('refuses an untrusted subscriptionProgram before any RPC call', async () => { + globalThis.fetch = noRpc; + const signer = await generateKeyPairSigner(); + const request = baseRequest(); + request.methodDetails.subscriptionProgram = 'Vote111111111111111111111111111111111111111'; + await expect( + buildSubscriptionActivationTransaction({ request, rpcUrl: 'https://mock-rpc', signer }), + ).rejects.toThrow(/Untrusted subscription program Vote111111111111111111111111111111111111111/); + }); + + test('trusts the subscriptionProgram named by trustedSubscriptionProgram', async () => { + const other = 'Vote111111111111111111111111111111111111111'; + // The pin passes; the mock plan is owned by the canonical program, so + // the build then stops at the plan-owner check. + globalThis.fetch = defaultMockFetch(); + const signer = await generateKeyPairSigner(); + const request = baseRequest(); + request.methodDetails.subscriptionProgram = other; + await expect( + buildSubscriptionActivationTransaction({ + request, + rpcUrl: 'https://mock-rpc', + signer, + trustedSubscriptionProgram: other, + }), + ).rejects.toThrow(/owner does not match the program/); + }); + + // §Currency Formats: "Implementations MUST treat currency and + // methodDetails.mint as the same value". + test('refuses a challenge whose currency differs from methodDetails.mint', async () => { + globalThis.fetch = noRpc; + const signer = await generateKeyPairSigner(); + const request = { ...baseRequest(), currency: '4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU' }; + await expect( + buildSubscriptionActivationTransaction({ request, rpcUrl: 'https://mock-rpc', signer }), + ).rejects.toThrow(/currency must match methodDetails\.mint/); + }); + + // §Shared Fields: positive base-10 integers, no sign, decimal point, + // exponent, whitespace, or leading zeros. + test.each(['010000000', '0', '+10000000', '1e7', '10000000.0', ' 10000000', '-1', ''])( + 'refuses amount %j', + async amount => { + globalThis.fetch = noRpc; + const signer = await generateKeyPairSigner(); + await expect( + buildSubscriptionActivationTransaction({ + request: { ...baseRequest(), amount }, + rpcUrl: 'https://mock-rpc', + signer, + }), + ).rejects.toThrow(/amount must be a positive base-10 integer/); + }, + ); + + test('refuses an amount above u64', async () => { + globalThis.fetch = noRpc; + const signer = await generateKeyPairSigner(); + await expect( + buildSubscriptionActivationTransaction({ + request: { ...baseRequest(), amount: '18446744073709551616' }, + rpcUrl: 'https://mock-rpc', + signer, + }), + ).rejects.toThrow(/does not fit in a u64/); + }); + + test.each(['030', '+30', '30.0', '3e1', ' 30', '30 ', '0'])('refuses periodCount %j', async periodCount => { + globalThis.fetch = noRpc; + const signer = await generateKeyPairSigner(); + await expect( + buildSubscriptionActivationTransaction({ + request: { ...baseRequest(), periodCount }, + rpcUrl: 'https://mock-rpc', + signer, + }), + ).rejects.toThrow(/periodCount must be a positive base-10 integer/); + }); + + // §Method Details: tokenProgram "MUST be the SPL Token program or the SPL Token-2022 program". + test('refuses a tokenProgram other than SPL Token or Token-2022', async () => { + globalThis.fetch = noRpc; + const signer = await generateKeyPairSigner(); + const request = baseRequest(); + request.methodDetails.tokenProgram = ZERO; + await expect( + buildSubscriptionActivationTransaction({ request, rpcUrl: 'https://mock-rpc', signer }), + ).rejects.toThrow(/tokenProgram must be/); + }); + + // §Method Details: puller "MUST be plan.owner or appear in plan.pullers". + test('refuses a puller that is neither plan.owner nor in plan.pullers', async () => { + const stranger = (await generateKeyPairSigner()).address; + globalThis.fetch = defaultMockFetch({ planOwner: stranger, planPullers: [stranger] }); + const signer = await generateKeyPairSigner(); + await expect( + buildSubscriptionActivationTransaction({ request: baseRequest(), rpcUrl: 'https://mock-rpc', signer }), + ).rejects.toThrow(/neither plan\.owner nor in plan\.pullers/); + }); + + test('accepts a puller listed in plan.pullers that is not plan.owner', async () => { + const merchant = (await generateKeyPairSigner()).address; + globalThis.fetch = defaultMockFetch({ planOwner: merchant, planPullers: [PULLER] }); + const signer = await generateKeyPairSigner(); + await expect( + buildSubscriptionActivationTransaction({ request: baseRequest(), rpcUrl: 'https://mock-rpc', signer }), + ).resolves.toBeTypeOf('string'); + }); + + // §Method Details: "reject request objects referencing a plan with an + // empty destination whitelist, more than one non-zero destination, or a + // destination different from recipient". + test.each([ + ['an empty destination whitelist', []], + ['two non-zero destinations', [RECIPIENT, PULLER]], + ['a destination other than recipient', [PULLER]], + ])('refuses a plan with %s', async (_label, planDestinations) => { + globalThis.fetch = defaultMockFetch({ planDestinations }); + const signer = await generateKeyPairSigner(); + await expect( + buildSubscriptionActivationTransaction({ request: baseRequest(), rpcUrl: 'https://mock-rpc', signer }), + ).rejects.toThrow(/plan\.destinations must be exactly one address equal to recipient/); + }); +}); + // ══════════════════════════════════════════════════════════════════════ // subscription() — Method.toClient wrapper (createCredential) // ══════════════════════════════════════════════════════════════════════ @@ -422,6 +582,24 @@ describe('subscription() client wrapper', () => { expect(calls).toContain('getSignatureStatuses'); }); + test('refuses an untrusted subscriptionProgram before signing the bearer proof', async () => { + globalThis.fetch = noRpc; + const signer = await generateKeyPairSigner(); + let proofs = 0; + const method = subscriptionClient({ + onAuthentication: () => { + proofs += 1; + }, + rpcUrl: 'https://mock-rpc', + signer, + }); + const request = baseRequest(); + request.methodDetails.subscriptionProgram = 'Vote111111111111111111111111111111111111111'; + const challenge = { ...((await buildChallenge()) as object), request } as never; + await expect(method.createCredential!({ challenge })).rejects.toThrow(/Untrusted subscription program/); + expect(proofs).toBe(0); + }); + test('rejects broadcast=true combined with feePayer sponsorship', async () => { globalThis.fetch = defaultMockFetch(); const signer = await generateKeyPairSigner(); diff --git a/typescript/packages/mpp/src/__tests__/subscription-server.test.ts b/typescript/packages/mpp/src/__tests__/subscription-server.test.ts index 0e10a91c2..bb55c42cc 100644 --- a/typescript/packages/mpp/src/__tests__/subscription-server.test.ts +++ b/typescript/packages/mpp/src/__tests__/subscription-server.test.ts @@ -24,11 +24,12 @@ import { setTransactionMessageLifetimeUsingBlockhash, type TransactionSigner, } from '@solana/kit'; -import { findAssociatedTokenPda } from '@solana-program/token'; +import { findAssociatedTokenPda, getCreateAssociatedTokenIdempotentInstruction } from '@solana-program/token'; import { Challenge, Credential } from 'mppx'; import { Mppx, Store } from 'mppx/server'; import { + SUBSCRIPTIONS_INIT_AUTHORITY_DISCRIMINATOR, SUBSCRIPTIONS_PROGRAM, SUBSCRIPTIONS_SUBSCRIBE_DISCRIMINATOR, SUBSCRIPTIONS_TRANSFER_DISCRIMINATOR, @@ -113,9 +114,17 @@ async function buildActivationTransactionBase64( | 'reorder' | 'no-subscribe' | 'no-transfer'; + /** Create an ATA idempotently for this owner before subscribe. */ + ataOwner?: 'recipient' | 'subscriber'; + /** Override the ATA instruction's data (e.g. empty: non-idempotent Create). */ + ataData?: Uint8Array; + /** Prepend an initialize_subscription_authority for this authority. */ + authorityInit?: 'subscriber' | 'unrelated'; feePayerKey?: string; memo?: string; receiver?: string; + /** Plan account named by the subscribe instruction (defaults to PLAN_ID). */ + subscribePlan?: string; version?: 'legacy' | 0; } = {}, ): Promise<{ @@ -124,11 +133,74 @@ async function buildActivationTransactionBase64( transaction: string; }> { const subscriber = await generateKeyPairSigner(); + const subscriptionAuthority = await deriveSubscriptionAuthorityPda({ + mint: address(MINT), + programId: address(SUBSCRIPTIONS_PROGRAM), + subscriber: subscriber.address, + }); + const subscribePlan = address(options.subscribePlan ?? PLAN_ID); + const subscriptionDelegation = await deriveSubscriptionPda({ + planPda: subscribePlan, + programId: address(SUBSCRIPTIONS_PROGRAM), + subscriber: subscriber.address, + }); + // Codama layout: subscriber, merchant, planPda, subscriptionPda, + // subscriptionAuthorityPda, systemProgram, eventAuthority, selfProgram, payer. const subscribeIx: Instruction = { - accounts: [{ address: subscriber.address, role: AccountRole.WRITABLE_SIGNER }], + accounts: [ + { address: subscriber.address, role: AccountRole.WRITABLE_SIGNER }, + { address: address(PULLER), role: AccountRole.READONLY }, + { address: subscribePlan, role: AccountRole.READONLY }, + { address: subscriptionDelegation, role: AccountRole.WRITABLE }, + { address: subscriptionAuthority, role: AccountRole.READONLY }, + { address: address(SYSTEM_PROGRAM), role: AccountRole.READONLY }, + { address: address(RECIPIENT), role: AccountRole.READONLY }, + { address: address(SUBSCRIPTIONS_PROGRAM), role: AccountRole.READONLY }, + { address: subscriber.address, role: AccountRole.WRITABLE_SIGNER }, + ], data: new Uint8Array([SUBSCRIPTIONS_SUBSCRIBE_DISCRIMINATOR]), programAddress: address(SUBSCRIPTIONS_PROGRAM), }; + const [subscriberAta] = await findAssociatedTokenPda({ + mint: address(MINT), + owner: subscriber.address, + tokenProgram: address(TOKEN_PROGRAM), + }); + const unrelated = await generateKeyPairSigner(); + const initAuthorityOwner = options.authorityInit === 'unrelated' ? unrelated.address : subscriber.address; + const initAuthorityIx: Instruction = { + accounts: [ + { address: subscriber.address, role: AccountRole.WRITABLE_SIGNER }, + { + address: await deriveSubscriptionAuthorityPda({ + mint: address(MINT), + programId: address(SUBSCRIPTIONS_PROGRAM), + subscriber: initAuthorityOwner, + }), + role: AccountRole.WRITABLE, + }, + { address: address(MINT), role: AccountRole.READONLY }, + { address: subscriberAta, role: AccountRole.WRITABLE }, + { address: address(SYSTEM_PROGRAM), role: AccountRole.READONLY }, + { address: address(TOKEN_PROGRAM), role: AccountRole.READONLY }, + ], + data: new Uint8Array([SUBSCRIPTIONS_INIT_AUTHORITY_DISCRIMINATOR]), + programAddress: address(SUBSCRIPTIONS_PROGRAM), + }; + const ataOwner = options.ataOwner === 'recipient' ? address(RECIPIENT) : subscriber.address; + const [createdAta] = await findAssociatedTokenPda({ + mint: address(MINT), + owner: ataOwner, + tokenProgram: address(TOKEN_PROGRAM), + }); + const idempotentAtaIx = getCreateAssociatedTokenIdempotentInstruction({ + ata: createdAta, + mint: address(MINT), + owner: ataOwner, + payer: subscriber, + tokenProgram: address(TOKEN_PROGRAM), + }); + const ataIx: Instruction = { ...idempotentAtaIx, data: options.ataData ?? idempotentAtaIx.data }; const [recipientAta] = await findAssociatedTokenPda({ mint: address(MINT), owner: address(options.receiver ?? RECIPIENT), @@ -185,6 +257,8 @@ async function buildActivationTransactionBase64( instructions = [subscribeIx, transferIx]; } if (options.memo !== undefined) instructions.push(memoIx); + if (options.authorityInit !== undefined) instructions.unshift(initAuthorityIx); + if (options.ataOwner !== undefined) instructions.unshift(ataIx); const txMessage = pipe( createTransactionMessage({ version: options.version ?? 0 }), @@ -445,6 +519,7 @@ describe('validateActivationInstructions', () => { amount: '10000000', methodDetails: { mint: MINT, + planAddress: PLAN_ID, subscriptionProgram: SUBSCRIPTIONS_PROGRAM, tokenProgram: TOKEN_PROGRAM, }, @@ -526,6 +601,64 @@ describe('validateActivationInstructions', () => { ).resolves.toBeUndefined(); }); + test("accepts an idempotent creation of the subscriber's own ATA", async () => { + const { subscriberAddress, transaction } = await buildActivationTransactionBase64({ ataOwner: 'subscriber' }); + await expect( + __testing.validateActivationInstructions(transaction, challenge, subscriberAddress), + ).resolves.toBeUndefined(); + }); + + // draft-solana-subscription-00: the activation contains "no instructions + // other than those above plus optional compute-budget and memo + // instructions"; the recipient's ATA is not the server's to create. + test("rejects creation of the recipient's ATA", async () => { + const { subscriberAddress, transaction } = await buildActivationTransactionBase64({ ataOwner: 'recipient' }); + await expect( + __testing.validateActivationInstructions(transaction, challenge, subscriberAddress), + ).rejects.toThrow(/ATA creation owner does not match the activation subscriber/); + }); + + // §Authorization Scope Verification: "uses methodDetails.planAddress as the Plan account". + test('rejects a subscribe instruction naming another Plan account', async () => { + const other = await generateKeyPairSigner(); + const { subscriberAddress, transaction } = await buildActivationTransactionBase64({ + subscribePlan: other.address, + }); + await expect( + __testing.validateActivationInstructions(transaction, challenge, subscriberAddress), + ).rejects.toThrow(/subscribe accounts do not match the challenged activation/); + }); + + test("accepts initialize_subscription_authority for the subscriber's (subscriber, mint) authority", async () => { + const { subscriberAddress, transaction } = await buildActivationTransactionBase64({ + authorityInit: 'subscriber', + }); + await expect( + __testing.validateActivationInstructions(transaction, challenge, subscriberAddress), + ).resolves.toBeUndefined(); + }); + + test('rejects initialize_subscription_authority for an unrelated authority', async () => { + const { subscriberAddress, transaction } = await buildActivationTransactionBase64({ + authorityInit: 'unrelated', + }); + await expect( + __testing.validateActivationInstructions(transaction, challenge, subscriberAddress), + ).rejects.toThrow(/initialize_subscription_authority is not allowed/); + }); + + test('rejects an ATA instruction with empty data instead of crashing', async () => { + // Empty data is the non-idempotent CreateAssociatedTokenAccount; the + // kit decoder omits `data` for it. + const { subscriberAddress, transaction } = await buildActivationTransactionBase64({ + ataData: new Uint8Array(), + ataOwner: 'subscriber', + }); + await expect( + __testing.validateActivationInstructions(transaction, challenge, subscriberAddress), + ).rejects.toThrow(/Only idempotent ATA creation is allowed/); + }); + test('rejects transfer_subscription to an ATA owned by another recipient', async () => { const { subscriberAddress, transaction } = await buildActivationTransactionBase64({ receiver: '11111111111111111111111111111111', @@ -689,7 +822,7 @@ describe('encoding helpers', () => { // verify() — end-to-end push-mode happy path // ══════════════════════════════════════════════════════════════════════ -describe('subscription().verify() (push mode)', () => { +describe('subscription().verify()', () => { test('rejects activation when first-period charge did not execute', async () => { const { subscriber, transaction, subscriberAddress } = await buildActivationTransactionBase64(); const authentication = await buildAuthentication('test-challenge', subscriber); @@ -774,7 +907,7 @@ describe('subscription().verify() (push mode)', () => { ).rejects.toThrow(/first-period charge/); }); - test('rejects type="signature" with feePayer=true', async () => { + test('rejects type="signature" with feePayer=true as push mode', async () => { globalThis.fetch = async () => rpcSuccess({}); const method = subscription({ decimals: 6, @@ -810,7 +943,7 @@ describe('subscription().verify() (push mode)', () => { } as never, request: {} as never, }), - ).rejects.toThrow(/fee sponsorship/); + ).rejects.toThrow(/Push-mode/); }); test('rejects an unknown payload type', async () => { @@ -1413,11 +1546,17 @@ describe('subscription().verify() (push mode)', () => { ).rejects.toThrow(/RPC error/); }); - test('rejects when push-mode signature is replayed (consumed)', async () => { - const store = Store.memory(); - const sig = 'replayedSig0000000000000000000000000000000000'; - await store.put(`solana-subscription:consumed:${sig}`, true); - globalThis.fetch = async () => rpcSuccess({}); + // draft-solana-subscription-00 §Payload: "Solana subscription activation + // uses type=\"transaction\"". A client-broadcast signature is refused as an + // invalid payload before the server reads anything from the RPC. + test('rejects a push-mode (type="signature") activation without touching the RPC', async () => { + const { subscriber } = await buildActivationTransactionBase64(); + const authentication = await buildAuthentication('push-challenge', subscriber); + let rpcCalls = 0; + globalThis.fetch = async () => { + rpcCalls += 1; + return rpcSuccess({}); + }; const method = subscription({ decimals: 6, mint: MINT, @@ -1428,13 +1567,13 @@ describe('subscription().verify() (push mode)', () => { puller: PULLER, recipient: RECIPIENT, rpcUrl: 'https://mock-rpc', - store, tokenProgram: TOKEN_PROGRAM, }); await expect( method.verify!({ credential: { challenge: { + id: 'push-challenge', request: { amount: '10000000', currency: MINT, @@ -1451,36 +1590,30 @@ describe('subscription().verify() (push mode)', () => { recipient: RECIPIENT, }, }, - payload: { signature: sig, type: 'signature' }, + payload: { authentication, signature: 'activation-signature', type: 'signature' }, } as never, request: {} as never, }), - ).rejects.toThrow(/already consumed/); + ).rejects.toThrow(/Push-mode \(type="signature"\) subscription activation is not supported/); + expect(rpcCalls).toBe(0); }); - test('concurrent push-mode activation returns exactly one receipt', async () => { - const { subscriber, transaction, subscriberAddress } = await buildActivationTransactionBase64(); - const authentication = await buildAuthentication('concurrent-challenge', subscriber); - const accountB64 = Buffer.from(buildDelegationData(subscriberAddress, PLAN_ID, 10_000_000n)).toString('base64'); - globalThis.fetch = async (_input, init) => { - const body = JSON.parse(init?.body as string) as { method?: string }; - if (body.method === 'getTransaction') { - await Promise.resolve(); - return rpcSuccess({ meta: { err: null }, transaction: [transaction, 'base64'], version: 0 }); - } - if (body.method === 'getAccountInfo') { - return rpcSuccess({ - value: { - data: [accountB64, 'base64'], - executable: false, - lamports: 0, - owner: SUBSCRIPTIONS_PROGRAM, - rentEpoch: 0, - }, - }); - } - return rpcSuccess({}); - }; + function writeU64Le(buf: Uint8Array, offset: number, value: bigint) { + for (let i = 0; i < 8; i += 1) { + buf[offset + i] = Number((value >> BigInt(i * 8)) & 0xffn); + } + } +}); + +// draft-solana-subscription-00 §Source Verification: "If source is present, +// servers MUST verify that it uses the did:pkh:solana: method and that its +// address matches the subscriber signer extracted from the activation +// transaction." +describe('subscription().verify() credential source', () => { + async function verifyWithSource(source: (subscriber: string) => string | undefined) { + const { subscriber, subscriberAddress, transaction } = await buildActivationTransactionBase64(); + const authentication = await buildAuthentication('source-challenge', subscriber); + globalThis.fetch = () => Promise.reject(new Error('RPC reached')); const method = subscription({ decimals: 6, mint: MINT, @@ -1494,65 +1627,21 @@ describe('subscription().verify() (push mode)', () => { store: Store.memory(), tokenProgram: TOKEN_PROGRAM, }); - const credential = { - challenge: { - id: 'concurrent-challenge', - request: { - amount: '10000000', - currency: MINT, - methodDetails: { - decimals: 6, - mint: MINT, - planAddress: PLAN_ID, - subscriptionProgram: SUBSCRIPTIONS_PROGRAM, - puller: PULLER, - tokenProgram: TOKEN_PROGRAM, - }, - periodCount: '30', - periodUnit: 'day', - recipient: RECIPIENT, - }, - }, - payload: { authentication, signature: 'same-activation-signature', type: 'signature' }, - } as never; - - const results = await Promise.allSettled( - Array.from({ length: 16 }, () => method.verify!({ credential, request: {} as never })), - ); - expect(results.filter(result => result.status === 'fulfilled')).toHaveLength(1); - expect(results.filter(result => result.status === 'rejected')).toHaveLength(15); - }); - - describe('push-mode reported transaction version', () => { - function pushModeMethod(store = Store.memory()) { - return subscription({ - decimals: 6, - mint: MINT, - network: 'devnet', - periodCount: 30, - periodUnit: 'day', - planId: PLAN_ID, - puller: PULLER, - recipient: RECIPIENT, - rpcUrl: 'https://mock-rpc', - store, - tokenProgram: TOKEN_PROGRAM, - }); - } - - function pushModeCredential(challengeId: string, authentication: unknown, signature: string) { - return { + const value = source(subscriberAddress); + return method.verify!({ + credential: { challenge: { - id: challengeId, + id: 'source-challenge', request: { amount: '10000000', currency: MINT, methodDetails: { decimals: 6, mint: MINT, + network: 'devnet', planAddress: PLAN_ID, - subscriptionProgram: SUBSCRIPTIONS_PROGRAM, puller: PULLER, + subscriptionProgram: SUBSCRIPTIONS_PROGRAM, tokenProgram: TOKEN_PROGRAM, }, periodCount: '30', @@ -1560,126 +1649,33 @@ describe('subscription().verify() (push mode)', () => { recipient: RECIPIENT, }, }, - payload: { authentication, signature, type: 'signature' }, - } as never; - } - - function mockPushModeFetch(transaction: string, subscriberAddress: string, version: unknown) { - const accountB64 = Buffer.from(buildDelegationData(subscriberAddress, PLAN_ID, 10_000_000n)).toString( - 'base64', - ); - globalThis.fetch = async (_input, init) => { - const body = JSON.parse(init?.body as string) as { method?: string }; - if (body.method === 'getTransaction') { - return rpcSuccess({ - meta: { err: null }, - transaction: [transaction, 'base64'], - ...(version === undefined ? {} : { version }), - }); - } - if (body.method === 'getAccountInfo') { - return rpcSuccess({ - value: { - data: [accountB64, 'base64'], - executable: false, - lamports: 0, - owner: SUBSCRIPTIONS_PROGRAM, - rentEpoch: 0, - }, - }); - } - return rpcSuccess({}); - }; - } - - test('settles a legacy activation reported by the RPC like a version-0 one', async () => { - const { subscriber, transaction, subscriberAddress } = await buildActivationTransactionBase64({ - version: 'legacy', - }); - const authentication = await buildAuthentication('version-challenge', subscriber); - const store = Store.memory(); - const method = pushModeMethod(store); - const credential = pushModeCredential('version-challenge', authentication, 'legacy-activation-signature'); - - mockPushModeFetch(transaction, subscriberAddress, 'legacy'); - const receipt = await method.verify!({ credential, request: {} as never }); - expect(receipt.status).toBe('success'); - expect(await store.get('solana-subscription:consumed:legacy-activation-signature')).not.toBeNull(); - }); - - test('rejects when the RPC does not report the activation transaction version', async () => { - const { subscriber, transaction, subscriberAddress } = await buildActivationTransactionBase64(); - const authentication = await buildAuthentication('no-version-challenge', subscriber); - mockPushModeFetch(transaction, subscriberAddress, undefined); - await expect( - pushModeMethod().verify!({ - credential: pushModeCredential('no-version-challenge', authentication, 'no-version-signature'), - request: {} as never, - }), - ).rejects.toThrow('RPC did not report the transaction version'); + payload: { authentication, transaction, type: 'transaction' }, + ...(value === undefined ? {} : { source: value }), + } as never, + request: {} as never, }); + } - test('accepts a version 0 activation reported by the RPC', async () => { - const { subscriber, transaction, subscriberAddress } = await buildActivationTransactionBase64(); - const authentication = await buildAuthentication('v0-challenge', subscriber); - mockPushModeFetch(transaction, subscriberAddress, 0); - const receipt = await pushModeMethod().verify!({ - credential: pushModeCredential('v0-challenge', authentication, 'v0-activation-signature'), - request: {} as never, - }); - expect(receipt.status).toBe('success'); - expect(receipt.reference).toBe('v0-activation-signature'); - }); + test('rejects a source naming another address', async () => { + const other = (await generateKeyPairSigner()).address; + await expect(verifyWithSource(() => `did:pkh:solana:devnet:${other}`)).rejects.toThrow( + /Credential source does not match the activation subscriber/, + ); }); - test('rejects when push-mode getTransaction returns null', async () => { - globalThis.fetch = async (_input, init) => { - const body = JSON.parse(init?.body as string) as { method?: string }; - if (body.method === 'getTransaction') return rpcSuccess(null); - return rpcSuccess({}); - }; - const method = subscription({ - decimals: 6, - mint: MINT, - network: 'devnet', - periodCount: 30, - periodUnit: 'day', - planId: PLAN_ID, - puller: PULLER, - recipient: RECIPIENT, - rpcUrl: 'https://mock-rpc', - tokenProgram: TOKEN_PROGRAM, - }); - await expect( - method.verify!({ - credential: { - challenge: { - request: { - amount: '10000000', - currency: MINT, - methodDetails: { - decimals: 6, - mint: MINT, - planAddress: PLAN_ID, - subscriptionProgram: SUBSCRIPTIONS_PROGRAM, - puller: PULLER, - tokenProgram: TOKEN_PROGRAM, - }, - periodCount: '30', - periodUnit: 'day', - recipient: RECIPIENT, - }, - }, - payload: { signature: 'newsig', type: 'signature' }, - } as never, - request: {} as never, - }), - ).rejects.toThrow(/not found/); + test('rejects a source using another DID method', async () => { + await expect(verifyWithSource(subscriber => `did:pkh:eip155:1:${subscriber}`)).rejects.toThrow( + /Credential source must be a did:pkh:solana DID/, + ); + await expect(verifyWithSource(subscriber => `did:pkh:solana:${subscriber}`)).rejects.toThrow( + /Credential source must be a did:pkh:solana DID/, + ); }); - function writeU64Le(buf: Uint8Array, offset: number, value: bigint) { - for (let i = 0; i < 8; i += 1) { - buf[offset + i] = Number((value >> BigInt(i * 8)) & 0xffn); - } - } + test('accepts a source matching the subscriber and an absent source', async () => { + await expect(verifyWithSource(subscriber => `did:pkh:solana:devnet:${subscriber}`)).rejects.toThrow( + /RPC reached/, + ); + await expect(verifyWithSource(() => undefined)).rejects.toThrow(/RPC reached/); + }); }); diff --git a/typescript/packages/mpp/src/__tests__/subscription.test.ts b/typescript/packages/mpp/src/__tests__/subscription.test.ts index 87c01f8af..b78542b65 100644 --- a/typescript/packages/mpp/src/__tests__/subscription.test.ts +++ b/typescript/packages/mpp/src/__tests__/subscription.test.ts @@ -256,3 +256,73 @@ describe('Instruction discriminators', () => { expect(SUBSCRIPTIONS_TRANSFER_DISCRIMINATOR).toBe(10); }); }); + +// draft-solana-subscription-00 §Shared Fields: amount and periodCount "MUST be +// a string representation of a positive integer in base 10 with no sign, +// decimal point, exponent, or surrounding whitespace. Leading zeros MUST NOT +// be used." §Method Details: tokenProgram "MUST be the SPL Token program or the +// SPL Token-2022 program". +describe('Methods.subscription request format', () => { + function request(overrides: { amount?: string; periodCount?: string; tokenProgram?: string } = {}) { + return { + amount: overrides.amount ?? '10000000', + currency: MINT, + methodDetails: { + decimals: 6, + mint: MINT, + planAddress: PLAN_ID, + puller: PULLER, + subscriptionProgram: SUBSCRIPTIONS_PROGRAM, + tokenProgram: overrides.tokenProgram ?? TOKEN_PROGRAM, + }, + periodCount: overrides.periodCount ?? '30', + periodUnit: 'day', + recipient: RECIPIENT, + }; + } + + test.each(['010000000', '0', '+10000000', '-1', '1e7', '10000000.0', ' 10000000', '10000000 ', ''])( + 'rejects amount %j', + amount => { + expect(subscriptionMethod.schema.request.safeParse(request({ amount })).success).toBe(false); + }, + ); + + test('rejects an amount above u64', () => { + expect(subscriptionMethod.schema.request.safeParse(request({ amount: '18446744073709551616' })).success).toBe( + false, + ); + expect(subscriptionMethod.schema.request.safeParse(request({ amount: '18446744073709551615' })).success).toBe( + true, + ); + }); + + test.each(['030', '0', '+30', '30.0', '3e1', ' 30', '30\n'])('rejects periodCount %j', periodCount => { + expect(subscriptionMethod.schema.request.safeParse(request({ periodCount })).success).toBe(false); + }); + + test('rejects a tokenProgram that is neither SPL Token nor Token-2022', () => { + expect( + subscriptionMethod.schema.request.safeParse(request({ tokenProgram: '11111111111111111111111111111111' })) + .success, + ).toBe(false); + expect( + subscriptionMethod.schema.request.safeParse( + request({ tokenProgram: 'TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb' }), + ).success, + ).toBe(true); + }); +}); + +describe('mapSubscriptionPeriodToHours with the wire periodCount', () => { + test('maps a canonical decimal string', () => { + expect(mapSubscriptionPeriodToHours('day', '30')).toBe(720); + expect(mapSubscriptionPeriodToHours('week', '2')).toBe(336); + }); + + test.each(['030', '+30', '30.0', '3e1', ' 30', '0'])('rejects %j', periodCount => { + expect(() => mapSubscriptionPeriodToHours('day', periodCount)).toThrow( + /periodCount must be a positive base-10 integer/, + ); + }); +}); diff --git a/typescript/packages/mpp/src/client/Charge.ts b/typescript/packages/mpp/src/client/Charge.ts index 346f6f51a..105e53420 100644 --- a/typescript/packages/mpp/src/client/Charge.ts +++ b/typescript/packages/mpp/src/client/Charge.ts @@ -30,6 +30,7 @@ import { Credential, Method } from 'mppx'; import { ASSOCIATED_TOKEN_PROGRAM, + CANONICAL_NETWORKS, DEFAULT_RPC_URLS, MEMO_PROGRAM, normalizeNetwork, @@ -180,8 +181,26 @@ export async function buildChargeTransaction( splits, } = methodDetails; + // Challenge checks that need no RPC: refuse an out-of-spec challenge before + // anything is fetched or signed. + assertSupportedChallengeNetwork(network); + // A zero amount is refused below: no split arithmetic leaves the primary + // recipient a positive amount. + const totalAmount = parseU64Amount(amount, 'amount'); + if (splits !== undefined && splits.length > MAX_SPLITS) { + throw new Error(`Too many splits: ${splits.length} (maximum ${MAX_SPLITS})`); + } + for (const split of splits ?? []) { + parseU64Amount(split.amount, 'split amount'); + } + // currency is "sol" for native, or the mint address for SPL tokens. const mint = resolveStablecoinMint(currency, network); + // draft-solana-charge-00 §Method Details, tokenProgram: "MUST NOT be + // present when `currency` is \"sol\"". + if (!mint && tokenProgramAddr !== undefined) { + throw new Error('methodDetails.tokenProgram must not be present when currency is "sol"'); + } const rpcUrl = parameters.rpcUrl ?? DEFAULT_RPC_URLS[normalizeNetwork(network || 'mainnet')] ?? DEFAULT_RPC_URLS.mainnet; @@ -211,7 +230,7 @@ export async function buildChargeTransaction( // Compute primary amount (total minus splits). const splitsTotal = (splits ?? []).reduce((sum, s) => sum + BigInt(s.amount), 0n); - const primaryAmount = BigInt(amount) - splitsTotal; + const primaryAmount = totalAmount - splitsTotal; if (primaryAmount <= 0n) { throw new Error('Splits consume the entire amount; primary recipient must receive a positive amount'); } @@ -402,6 +421,40 @@ export async function buildChargeTransaction( // ── Helpers ── +/** draft-solana-charge-00 §Method Details: "An array of at most 8 additional payment splits." */ +const MAX_SPLITS = 8; +const U64_MAX = (1n << 64n) - 1n; + +/** + * draft-solana-charge-00 §Method Details, network: "MUST be one of + * \"mainnet\", \"devnet\", or \"localnet\"" (the legacy `mainnet-beta` spelling + * is accepted as an alias). An unknown cluster is refused rather than paid + * through the mainnet RPC. + */ +function assertSupportedChallengeNetwork(network: string | undefined): void { + if (network === undefined) return; + if (!(CANONICAL_NETWORKS as readonly string[]).includes(normalizeNetwork(network))) { + throw new Error(`Unsupported challenge network "${network}" (allowed: ${CANONICAL_NETWORKS.join(', ')})`); + } +} + +/** + * draft-solana-charge-00 §Request Schema, amount: "The value MUST be a + * positive integer that fits in a 64-bit unsigned integer". Checked + * explicitly so the refusal names the amount instead of surfacing a codec + * error from instruction encoding. + */ +function parseU64Amount(value: string, label: string): bigint { + if (!/^[0-9]+$/.test(value)) { + throw new Error(`Invalid amount: ${label} "${value}" is not a base-10 integer`); + } + const parsed = BigInt(value); + if (parsed > U64_MAX) { + throw new Error(`Invalid amount: ${label} ${value} does not fit in a u64`); + } + return parsed; +} + /** * Always-on expiry refusal for the client (audit #10): refuse to sign a * challenge whose `expires` timestamp is in the past or malformed. A challenge diff --git a/typescript/packages/mpp/src/client/Subscription.ts b/typescript/packages/mpp/src/client/Subscription.ts index 5c436ab0e..bb3a507ca 100644 --- a/typescript/packages/mpp/src/client/Subscription.ts +++ b/typescript/packages/mpp/src/client/Subscription.ts @@ -36,13 +36,22 @@ import { findAssociatedTokenPda, getCreateAssociatedTokenIdempotentInstruction } import type { Challenge as MppxChallenge } from 'mppx'; import { Credential, Method } from 'mppx'; -import { DEFAULT_RPC_URLS, MEMO_PROGRAM, normalizeNetwork, SYSTEM_PROGRAM } from '../constants.js'; +import { + DEFAULT_RPC_URLS, + MEMO_PROGRAM, + normalizeNetwork, + SUBSCRIPTIONS_PROGRAM, + SYSTEM_PROGRAM, + TOKEN_2022_PROGRAM, + TOKEN_PROGRAM, +} from '../constants.js'; import * as Methods from '../Methods.js'; import { assertPeriodHoursInRange, deriveSubscriptionAuthorityPda, deriveSubscriptionPda, mapSubscriptionPeriodToHours, + parseSubscriptionInteger, } from '../shared/subscription.js'; /** Domain separator for reusable subscription authentication proofs. */ @@ -166,6 +175,9 @@ export function subscription(parameters: subscription.Parameters) { if (serverPaysFees && broadcast) { throw new Error('broadcast=true cannot be used with fee sponsorship (feePayer: true)'); } + // Refuse an out-of-spec challenge (untrusted program, currency/mint + // mismatch, malformed amount) before signing the bearer proof. + assertSubscriptionChallengeRequest(challenge.request, parameters.trustedSubscriptionProgram); const subscriptionDelegation = await deriveSubscriptionPda({ planPda: address(challenge.request.methodDetails.planAddress), @@ -212,6 +224,7 @@ export function subscription(parameters: subscription.Parameters) { rpcUrl, signer, subscriptionAuthorityInitId, + trustedSubscriptionProgram: parameters.trustedSubscriptionProgram, }); const rpc = createSolanaRpc(rpcUrl); @@ -270,7 +283,8 @@ export async function buildSubscriptionActivationTransaction( recentBlockhash: serverBlockhash, } = methodDetails; - const periodHours = mapSubscriptionPeriodToHours(periodUnit, Number(periodCount)); + assertSubscriptionChallengeRequest(parameters.request, parameters.trustedSubscriptionProgram); + const periodHours = mapSubscriptionPeriodToHours(periodUnit, periodCount); assertPeriodHoursInRange(periodHours); const rpcUrl = @@ -314,6 +328,10 @@ export async function buildSubscriptionActivationTransaction( owner: subscriberAddress, tokenProgram: tokenProgramAddress, }); + // The receiver ATA is only referenced by transfer_subscription. The + // activation does not create it: draft-solana-subscription-00 lists the + // activation's instructions and allows nothing else beyond compute-budget + // and memo instructions; the recipient's ATA must already exist. const [recipientAta] = await findAssociatedTokenPda({ mint: mintAddress, owner: recipientAddress, @@ -333,6 +351,7 @@ export async function buildSubscriptionActivationTransaction( if (plan.data.terms.periodHours !== BigInt(periodHours)) { throw new Error('Subscription plan period does not match the challenge'); } + assertPlanPullerAndDestinations(plan, address(methodDetails.puller), recipientAddress); const payerAddress = useServerFeePayer ? address(feePayerKey!) : subscriberAddress; const payerSigner = payerAddress === subscriberAddress ? signer : remoteSigner(payerAddress); @@ -350,21 +369,14 @@ export async function buildSubscriptionActivationTransaction( }), payerAddress, ); - const recipientAtaIx = stripRemoteSigner( - getCreateAssociatedTokenIdempotentInstruction({ - ata: recipientAta, - mint: mintAddress, - owner: recipientAddress, - payer: payerSigner, - tokenProgram: tokenProgramAddress, - }), - payerAddress, - ); const generatedSubscribe = await getSubscribeInstructionAsync( { eventAuthority, merchant: plan.owner, - payer: payerSigner, + // The optional payer account names a sponsor; without one the + // subscriber pays and the account is omitted (the Rust kit's + // eight-account layout). + ...(useServerFeePayer ? { payer: payerSigner } : {}), planPda, selfProgram: programAddress, subscribeData: { @@ -404,7 +416,7 @@ export async function buildSubscriptionActivationTransaction( pullerAddress, ); - const instructions: Instruction[] = [subscriberAtaIx, recipientAtaIx, subscribeIx, transferIx]; + const instructions: Instruction[] = [subscriberAtaIx, subscribeIx, transferIx]; if (externalId) { instructions.push(buildMemoInstruction(externalId)); @@ -507,6 +519,75 @@ async function readSubscriptionAuthorityInitId(parameters: { return await fetchAuthorityInitId(rpc, authority, programAddress); } +const U64_MAX = (1n << 64n) - 1n; +/** Base58 of the all-zero address: an unused slot in a Plan's fixed-size lists. */ +const ZERO_ADDRESS = SYSTEM_PROGRAM; + +/** + * Challenge checks that need no RPC (draft-solana-subscription-00): + * + * - §Intent Semantics: "clients MUST validate that address + * [methodDetails.subscriptionProgram] before signing" — pinned to + * `trustedProgram` (default: the canonical deployment). + * - §Currency Formats: "Implementations MUST treat `currency` and + * `methodDetails.mint` as the same value". + * - §Shared Fields: `amount` and `periodCount` are positive base-10 integers + * without sign, decimal point, exponent, whitespace, or leading zeros. + * - §Method Details: tokenProgram "MUST be the SPL Token program or the SPL + * Token-2022 program". + */ +function assertSubscriptionChallengeRequest( + request: buildSubscriptionActivationTransaction.Parameters['request'], + trustedProgram: string = SUBSCRIPTIONS_PROGRAM, +): void { + const { methodDetails } = request; + if (methodDetails.subscriptionProgram !== trustedProgram) { + throw new Error( + `Untrusted subscription program ${methodDetails.subscriptionProgram} (expected ${trustedProgram})`, + ); + } + if (request.currency !== methodDetails.mint) { + throw new Error( + `currency must match methodDetails.mint (currency ${request.currency}, mint ${methodDetails.mint})`, + ); + } + if (parseSubscriptionInteger(request.amount, 'amount') > U64_MAX) { + throw new Error(`Invalid amount: ${request.amount} does not fit in a u64`); + } + parseSubscriptionInteger(request.periodCount, 'periodCount'); + if (methodDetails.tokenProgram !== TOKEN_PROGRAM && methodDetails.tokenProgram !== TOKEN_2022_PROGRAM) { + throw new Error( + `methodDetails.tokenProgram must be ${TOKEN_PROGRAM} or ${TOKEN_2022_PROGRAM}, got ${methodDetails.tokenProgram}`, + ); + } +} + +/** + * draft-solana-subscription-00 §Method Details: `methodDetails.puller` "MUST + * be `plan.owner` or appear in `plan.pullers`", and "Servers and clients MUST + * reject request objects referencing a plan with an empty destination + * whitelist, more than one non-zero destination, or a destination different + * from `recipient`." + */ +function assertPlanPullerAndDestinations( + plan: ReturnType['decode']>, + puller: Address, + recipient: Address, +): void { + const pullers = plan.data.pullers.filter(entry => entry !== ZERO_ADDRESS); + if (puller !== plan.owner && !pullers.includes(puller)) { + throw new Error( + 'The on-chain Plan does not match the challenge: methodDetails.puller is neither plan.owner nor in plan.pullers', + ); + } + const destinations = plan.data.destinations.filter(entry => entry !== ZERO_ADDRESS); + if (destinations.length !== 1 || destinations[0] !== recipient) { + throw new Error( + 'The on-chain Plan does not match the challenge: plan.destinations must be exactly one address equal to recipient', + ); + } +} + function remoteSigner(remoteAddress: Address): TransactionSigner { return { address: remoteAddress, @@ -602,6 +683,12 @@ export declare namespace subscription { rpcUrl?: string; /** Solana transaction signer. The subscriber's funding key. */ signer: SubscriptionSigner; + /** + * Subscriptions program deployment the client trusts. A challenge whose + * `methodDetails.subscriptionProgram` names any other program is refused + * before anything is signed. Defaults to {@link SUBSCRIPTIONS_PROGRAM}. + */ + trustedSubscriptionProgram?: string; }; type ProgressEvent = @@ -668,5 +755,10 @@ export declare namespace buildSubscriptionActivationTransaction { signer: SubscriptionSigner; /** Live init id returned by the separately initialized SubscriptionAuthority. */ subscriptionAuthorityInitId?: bigint; + /** + * Subscriptions program deployment the client trusts. Defaults to + * {@link SUBSCRIPTIONS_PROGRAM}; any other `subscriptionProgram` is refused. + */ + trustedSubscriptionProgram?: string; }; } diff --git a/typescript/packages/mpp/src/server/Charge.ts b/typescript/packages/mpp/src/server/Charge.ts index 7e3166559..750fc3ae6 100644 --- a/typescript/packages/mpp/src/server/Charge.ts +++ b/typescript/packages/mpp/src/server/Charge.ts @@ -369,6 +369,35 @@ type CompiledInstruction = { programAddressIndex: number; }; +/** Solana's maximum serialized transaction size (the 1232-byte packet payload). */ +const MAX_TRANSACTION_SIZE_BYTES = 1232; + +/** + * The kit decoder omits `accountIndices` and `data` when an instruction has + * none. Fill them with empty values so policy checks reject such instructions + * instead of crashing on `undefined`. + */ +function normalizeCompiledMessage( + decoded: ReturnType['decode']>, +) { + const message = decoded as unknown as Omit & { + instructions?: readonly Partial[]; + }; + const { instructions } = message; + if (instructions === undefined) { + // Not a legacy or version-0 message layout. + throw new Error(`unsupported message version ${String((decoded as { version?: unknown }).version)}`); + } + return { + ...message, + instructions: instructions.map(ix => ({ + accountIndices: ix.accountIndices ?? [], + data: ix.data ?? new Uint8Array(), + programAddressIndex: ix.programAddressIndex ?? -1, + })), + } as CompiledMessage; +} + /** * RPC-free pre-broadcast verification of a base64-encoded charge transaction * against the challenge it answers: split-count, address-lookup-table, @@ -395,11 +424,24 @@ export async function verifyChargeTransaction(clientTxBase64: string, challenge: } async function verifyChargeTransactionShape(clientTxBase64: string, challenge: ChallengeRequest) { + let txBytes: Uint8Array; + try { + txBytes = new Uint8Array(getBase64Codec().encode(clientTxBase64)); + } catch (e) { + throw new Error(`Invalid transaction: ${e instanceof Error ? e.message : String(e)}`); + } + // draft-solana-charge-00 §Transaction payload: "The transaction MUST be a + // valid Solana versioned transaction that does not exceed the 1232-byte + // transaction size limit." + if (txBytes.byteLength > MAX_TRANSACTION_SIZE_BYTES) { + throw new Error( + `Transaction is ${txBytes.byteLength} bytes, over the ${MAX_TRANSACTION_SIZE_BYTES}-byte limit`, + ); + } let message: CompiledMessage; try { - const txBytes = getBase64Codec().encode(clientTxBase64); const decoded = getTransactionDecoder().decode(txBytes); - message = getCompiledTransactionMessageDecoder().decode(decoded.messageBytes) as unknown as CompiledMessage; + message = normalizeCompiledMessage(getCompiledTransactionMessageDecoder().decode(decoded.messageBytes)); } catch (e) { throw new Error(`Invalid transaction: ${e instanceof Error ? e.message : String(e)}`); } diff --git a/typescript/packages/mpp/src/server/Subscription.ts b/typescript/packages/mpp/src/server/Subscription.ts index 179fd5ce9..7c3f6b2db 100644 --- a/typescript/packages/mpp/src/server/Subscription.ts +++ b/typescript/packages/mpp/src/server/Subscription.ts @@ -37,12 +37,8 @@ import { deriveSubscriptionPda, mapSubscriptionPeriodToHours, } from '../shared/subscription.js'; -import { - assertReportedTransactionVersion, - coSignBase64Transaction, - transactionSignatureFromBase64, -} from '../utils/transactions.js'; -import { claimReplayKey, confirmReplayKey, inspectReplayKey, reserveReplayKey } from './replay.js'; +import { coSignBase64Transaction, transactionSignatureFromBase64 } from '../utils/transactions.js'; +import { claimReplayKey, confirmReplayKey, inspectReplayKey } from './replay.js'; /** * Creates a Solana `subscription` method for usage on the server. @@ -236,14 +232,20 @@ export function subscription(parameters: subscription.Parameters) { return await verifySubscriptionAccess(cred, challenge, rpcUrl, store); } + // draft-solana-subscription-00 §Payload: "Solana subscription + // activation uses type=\"transaction\"". The profile defines no + // push mode, so a client-broadcast signature is refused before any + // RPC lookup. + if (payloadType === 'signature') { + throw new Error( + 'Push-mode (type="signature") subscription activation is not supported: the Solana profile activates with type="transaction" only', + ); + } + assertActivationChallengeNotExpired(cred.challenge.expires); assertSubscriptionNotExpired(challenge.subscriptionExpires); - if (payloadType === 'signature' && challenge.methodDetails.feePayer) { - throw new Error('type="signature" credentials cannot be used with fee sponsorship (feePayer: true)'); - } - - const settlement = await settleActivation(cred, challenge, rpcUrl, store, signer, payloadType); + const settlement = await settleActivation(cred, challenge, rpcUrl, store, signer); const subscriberAddress = settlement.subscriberAddress; const subscriptionPda = await deriveSubscriptionPda({ @@ -252,10 +254,7 @@ export function subscription(parameters: subscription.Parameters) { subscriber: address(subscriberAddress), }); - const expectedPeriodHours = mapSubscriptionPeriodToHours( - challenge.periodUnit, - Number(challenge.periodCount), - ); + const expectedPeriodHours = mapSubscriptionPeriodToHours(challenge.periodUnit, challenge.periodCount); const delegation = await fetchSubscriptionDelegation( rpcUrl, @@ -403,98 +402,96 @@ async function settleActivation( rpcUrl: string, store: Store.Store, signer: TransactionPartialSigner | undefined, - payloadType: 'signature' | 'transaction', ): Promise<{ activationSignature: string; replay?: { binding: string; key: string }; subscriberAddress: string; }> { - if (payloadType === 'transaction') { - const { transaction: clientTxBase64 } = credential.payload; - if (!clientTxBase64) { - throw new Error('Missing transaction data in credential payload'); - } + const { transaction: clientTxBase64 } = credential.payload; + if (!clientTxBase64) { + throw new Error('Missing transaction data in credential payload'); + } - const subscriber = extractSubscriberFromTransaction(clientTxBase64, challenge); - await verifyActivationAuthentication(credential, challenge, subscriber); - await validateActivationInstructions(clientTxBase64, challenge, subscriber); + const subscriber = extractSubscriberFromTransaction(clientTxBase64, challenge); + verifyCredentialSource(credential.source, subscriber); + await verifyActivationAuthentication(credential, challenge, subscriber); + await validateActivationInstructions(clientTxBase64, challenge, subscriber); - let txToSend = clientTxBase64; - if (signer) { - if (challenge.methodDetails.feePayerKey !== signer.address) { - throw new Error('Configured fee-payer signer does not match challenge feePayerKey'); - } - txToSend = await coSignBase64Transaction(signer, clientTxBase64); + let txToSend = clientTxBase64; + if (signer) { + if (challenge.methodDetails.feePayerKey !== signer.address) { + throw new Error('Configured fee-payer signer does not match challenge feePayerKey'); } + txToSend = await coSignBase64Transaction(signer, clientTxBase64); + } + + const signature = transactionSignatureFromBase64(txToSend); + const key = `solana-subscription:consumed:${signature}`; + const binding = JSON.stringify({ challengeId: credential.challenge.id ?? null, request: challenge }); + const replayStatus = await inspectReplayKey(store, key, binding); + if (replayStatus === 'conflict') { + throw new Error('Activation signature already consumed'); + } + if (replayStatus === 'pending') { + throw new Error('Activation settlement is already in progress; retry shortly'); + } - const signature = transactionSignatureFromBase64(txToSend); - const key = `solana-subscription:consumed:${signature}`; - const binding = JSON.stringify({ challengeId: credential.challenge.id ?? null, request: challenge }); - const replayStatus = await inspectReplayKey(store, key, binding); - if (replayStatus === 'conflict') { - throw new Error('Activation signature already consumed'); + let needsConfirmation = replayStatus !== 'retry'; + if (replayStatus === 'expired') { + const recoveryClaim = await claimReplayKey(store, key, binding); + if (recoveryClaim === 'conflict') throw new Error('Activation signature already consumed'); + if (recoveryClaim === 'pending') { + throw new Error('Activation settlement is already in progress; retry shortly'); } - if (replayStatus === 'pending') { + needsConfirmation = recoveryClaim !== 'retry'; + } else if (replayStatus === 'available') { + const replayClaim = await claimReplayKey(store, key, binding); + if (replayClaim === 'conflict') throw new Error('Activation signature already consumed'); + if (replayClaim === 'pending') { throw new Error('Activation settlement is already in progress; retry shortly'); } - - let needsConfirmation = replayStatus !== 'retry'; - if (replayStatus === 'expired') { - const recoveryClaim = await claimReplayKey(store, key, binding); - if (recoveryClaim === 'conflict') throw new Error('Activation signature already consumed'); - if (recoveryClaim === 'pending') { - throw new Error('Activation settlement is already in progress; retry shortly'); - } - needsConfirmation = recoveryClaim !== 'retry'; - } else if (replayStatus === 'available') { - const replayClaim = await claimReplayKey(store, key, binding); - if (replayClaim === 'conflict') throw new Error('Activation signature already consumed'); - if (replayClaim === 'pending') { - throw new Error('Activation settlement is already in progress; retry shortly'); - } - needsConfirmation = replayClaim !== 'retry'; - if (replayClaim === 'reserved') { - try { - await simulateTransaction(rpcUrl, txToSend); - } catch (error) { - // No transaction was submitted, so releasing this reservation - // is safe and lets the client correct and retry the activation. - await store.delete(key); - throw error; - } - // Keep the reservation on an ambiguous send failure: the RPC may - // have accepted the transaction even if the response was lost. - await broadcastTransaction(rpcUrl, txToSend); + needsConfirmation = replayClaim !== 'retry'; + if (replayClaim === 'reserved') { + try { + await simulateTransaction(rpcUrl, txToSend); + } catch (error) { + // No transaction was submitted, so releasing this reservation + // is safe and lets the client correct and retry the activation. + await store.delete(key); + throw error; } + // Keep the reservation on an ambiguous send failure: the RPC may + // have accepted the transaction even if the response was lost. + await broadcastTransaction(rpcUrl, txToSend); } - if (needsConfirmation) { - await waitForConfirmation(rpcUrl, signature); - } - return { activationSignature: signature, replay: { binding, key }, subscriberAddress: subscriber }; } + if (needsConfirmation) { + await waitForConfirmation(rpcUrl, signature); + } + return { activationSignature: signature, replay: { binding, key }, subscriberAddress: subscriber }; +} - // ── Push mode (type="signature") ── - const { signature } = credential.payload; - if (!signature) { - throw new Error('Missing signature in credential payload'); +/** + * draft-solana-subscription-00 §Source Verification: "If `source` is present, + * servers MUST verify that it uses the `did:pkh:solana:` method and that its + * address matches the subscriber signer extracted from the activation + * transaction." Mirrors the Rust kit's `verify_credential_source`. + */ +function verifyCredentialSource(source: string | undefined, subscriber: string): void { + if (source === undefined) return; + const prefix = 'did:pkh:solana:'; + if (!source.startsWith(prefix)) { + throw new Error('Credential source must be a did:pkh:solana DID'); } - const consumedKey = `solana-subscription:consumed:${signature}`; - if ((await store.get(consumedKey)) !== null) { - throw new Error('Activation signature already consumed'); + const rest = source.slice(prefix.length); + const separator = rest.indexOf(':'); + if (separator <= 0) { + throw new Error('Credential source must be a did:pkh:solana DID'); } - const tx = await fetchTransactionRaw(rpcUrl, signature); - if (!tx) throw new Error('Transaction not found or not yet confirmed'); - assertReportedTransactionVersion(tx.version); - if (tx.meta?.err) throw new Error('Transaction failed on-chain'); - const [transactionBase64] = tx.transaction; - const subscriber = extractSubscriberFromTransaction(transactionBase64, challenge); - await verifyActivationAuthentication(credential, challenge, subscriber); - await validateActivationInstructions(transactionBase64, challenge, subscriber); - - if (!(await reserveReplayKey(store, consumedKey))) { - throw new Error('Activation signature already consumed'); + const sourceAddress = rest.slice(separator + 1); + if (sourceAddress !== subscriber) { + throw new Error('Credential source does not match the activation subscriber'); } - return { activationSignature: signature, subscriberAddress: subscriber }; } async function verifyActivationAuthentication( @@ -569,7 +566,7 @@ async function verifySubscriptionAccess( throw new Error('Subscription authority has been invalidated'); } - const expectedPeriodHours = mapSubscriptionPeriodToHours(challenge.periodUnit, Number(challenge.periodCount)); + const expectedPeriodHours = mapSubscriptionPeriodToHours(challenge.periodUnit, challenge.periodCount); if ( delegation.amountPerPeriod !== challenge.amount || delegation.periodHours !== expectedPeriodHours || @@ -674,9 +671,19 @@ function decodeCompiledMessage(clientTxBase64: string): CompiledMessage { // and v0 messages both decode to this shape. const message = getCompiledTransactionMessageDecoder().decode(decoded.messageBytes) as unknown as Omit< CompiledMessage, - 'signerAccounts' - >; - return { ...message, signerAccounts: Object.keys(decoded.signatures) }; + 'instructions' | 'signerAccounts' + > & { instructions: readonly Partial[] }; + // The decoder omits `accountIndices` / `data` when an instruction has + // none; normalize so the policy checks reject rather than crash. + return { + ...message, + instructions: message.instructions.map(ix => ({ + accountIndices: ix.accountIndices ?? [], + data: ix.data ?? new Uint8Array(), + programAddressIndex: ix.programAddressIndex ?? -1, + })), + signerAccounts: Object.keys(decoded.signatures), + }; } catch (e) { throw new Error(`Invalid transaction: ${e instanceof Error ? e.message : String(e)}`); } @@ -728,6 +735,20 @@ async function validateActivationInstructions( let sawMemo = false; let sawComputeUnitLimit = false; let sawComputeUnitPrice = false; + let sawAtaCreation = false; + + // §Authorization Scope Verification: the activation "uses + // methodDetails.planAddress as the Plan account", and a + // subscription-authority initialization is allowed "only if the + // (subscriber, mint) authority does not yet exist". Pin the accounts the + // subscribe and initialize_subscription_authority instructions name. + const expectedAuthority = (subscriberAddress: string) => + deriveSubscriptionAuthorityPda({ + mint: address(challenge.methodDetails.mint), + programId: address(programId), + subscriber: address(subscriberAddress), + }); + const txFeePayer = message.staticAccounts[0]; for (const [index, ix] of message.instructions.entries()) { const program = message.staticAccounts[ix.programAddressIndex]; @@ -765,10 +786,16 @@ async function validateActivationInstructions( if (!subscriber || ix.accountIndices.length !== 6) { throw new Error('Invalid ATA creation instruction in activation transaction'); } + if (sawAtaCreation) { + throw new Error('Only one idempotent subscriber ATA creation is allowed in activation transaction'); + } const account = (position: number) => message.staticAccounts[ix.accountIndices[position]]; const ataOwner = account(2); - if (ataOwner !== subscriber && ataOwner !== challenge.recipient) { - throw new Error('ATA creation owner does not match the activation subscriber or recipient'); + // Only the subscriber's own ATA (the funding source) may be created, + // as in the Rust kit; the spec's activation instruction list allows + // no recipient ATA creation. + if (ataOwner !== subscriber) { + throw new Error('ATA creation owner does not match the activation subscriber'); } const [expectedAta] = await findAssociatedTokenPda({ mint: address(challenge.methodDetails.mint), @@ -783,6 +810,7 @@ async function validateActivationInstructions( ) { throw new Error('ATA creation does not match the activation subscriber and mint'); } + sawAtaCreation = true; continue; } @@ -790,12 +818,65 @@ async function validateActivationInstructions( throw new Error(`Unsupported program ${program ?? ''} in activation transaction`); } if (ix.data.length === 0) throw new Error('Empty subscriptions-program instruction'); + const account = (position: number): string | undefined => { + const accountIndex = ix.accountIndices[position]; + return accountIndex === undefined ? undefined : message.staticAccounts[accountIndex]; + }; if (ix.data[0] === SUBSCRIPTIONS_INIT_AUTHORITY_DISCRIMINATOR) { if (sawInitializeAuthority) throw new Error('Multiple initialize_subscription_authority instructions found'); + // Accounts: owner, subscriptionAuthority, tokenMint, userAta, + // systemProgram, tokenProgram[, payer]. + const payerOk = + ix.accountIndices.length === 6 || (ix.accountIndices.length === 7 && account(6) === txFeePayer); + const subscriberAta = subscriber + ? ( + await findAssociatedTokenPda({ + mint: address(challenge.methodDetails.mint), + owner: address(subscriber), + tokenProgram: address(challenge.methodDetails.tokenProgram), + }) + )[0] + : undefined; + if ( + !subscriber || + !payerOk || + account(0) !== subscriber || + account(1) !== (await expectedAuthority(subscriber)) || + account(2) !== challenge.methodDetails.mint || + account(3) !== subscriberAta || + account(4) !== SYSTEM_PROGRAM || + account(5) !== challenge.methodDetails.tokenProgram + ) { + throw new Error( + "initialize_subscription_authority is not allowed for any authority other than the subscriber's (subscriber, mint) authority", + ); + } sawInitializeAuthority = true; } else if (ix.data[0] === SUBSCRIPTIONS_SUBSCRIBE_DISCRIMINATOR) { if (sawSubscribe) throw new Error('Multiple subscribe instructions found'); + // Accounts: subscriber, merchant, planPda, subscriptionPda, + // subscriptionAuthorityPda, systemProgram, eventAuthority, + // selfProgram[, payer]. The optional payer is the fee payer. + const payerOk = + ix.accountIndices.length === 8 || (ix.accountIndices.length === 9 && account(8) === txFeePayer); + if ( + !subscriber || + !payerOk || + account(0) !== subscriber || + account(2) !== challenge.methodDetails.planAddress || + account(3) !== + (await deriveSubscriptionPda({ + planPda: address(challenge.methodDetails.planAddress), + programId: address(programId), + subscriber: address(subscriber), + })) || + account(4) !== (await expectedAuthority(subscriber)) || + account(5) !== SYSTEM_PROGRAM || + account(7) !== programId + ) { + throw new Error('subscribe accounts do not match the challenged activation'); + } sawSubscribe = true; subscribeIndex = index; } else if (ix.data[0] === SUBSCRIPTIONS_TRANSFER_DISCRIMINATOR) { @@ -993,28 +1074,6 @@ function base64UrlEncodeNoPadding(bytes: Uint8Array): string { // ── RPC helpers ── -type RawTransaction = { - meta: { err: unknown } | null; - transaction: [string, 'base64']; - version?: unknown; -}; - -async function fetchTransactionRaw(rpcUrl: string, signature: string): Promise { - const response = await fetch(rpcUrl, { - body: JSON.stringify({ - id: 1, - jsonrpc: '2.0', - method: 'getTransaction', - params: [signature, { commitment: 'confirmed', encoding: 'base64', maxSupportedTransactionVersion: 1 }], - }), - headers: { 'Content-Type': 'application/json' }, - method: 'POST', - }); - const data = (await response.json()) as { error?: { message: string }; result?: RawTransaction | null }; - if (data.error) throw new Error(`RPC error: ${data.error.message}`); - return data.result ?? null; -} - async function simulateTransaction(rpcUrl: string, base64Tx: string): Promise { const response = await fetch(rpcUrl, { body: JSON.stringify({ @@ -1098,6 +1157,8 @@ type CredentialPayload = { transaction?: string; type?: string; }; + /** Optional payer identifier (e.g. `did:pkh:solana:...`); verified when present. */ + source?: string; }; type SubscriptionBinding = { diff --git a/typescript/packages/mpp/src/shared/subscription.ts b/typescript/packages/mpp/src/shared/subscription.ts index e4443c670..467fb7a15 100644 --- a/typescript/packages/mpp/src/shared/subscription.ts +++ b/typescript/packages/mpp/src/shared/subscription.ts @@ -3,15 +3,45 @@ import { type Address, getAddressEncoder, getProgramDerivedAddress } from '@sola /** Maximum `period_hours` supported by the subscriptions program. */ const MAX_PERIOD_HOURS = 8760; +/** + * draft-solana-subscription-00 §Shared Fields: `amount` and `periodCount` are + * positive base-10 integers "with no sign, decimal point, exponent, or + * surrounding whitespace. Leading zeros MUST NOT be used." + */ +const POSITIVE_DECIMAL_INTEGER = /^[1-9][0-9]*$/; + +/** + * Parse a wire `amount` or `periodCount` under the profile's strict integer + * format, refusing what `Number()` or `BigInt()` would silently accept + * (`"030"`, `"+30"`, `"30.0"`, `"3e1"`, `" 30"`). + * + * @throws If `value` is not a positive base-10 integer without leading zeros. + */ +export function parseSubscriptionInteger(value: string, field: 'amount' | 'periodCount'): bigint { + if (typeof value !== 'string' || !POSITIVE_DECIMAL_INTEGER.test(value)) { + throw new Error( + `${field} must be a positive base-10 integer with no sign, decimal point, exponent, whitespace, or leading zeros, got ${JSON.stringify(value)}`, + ); + } + return BigInt(value); +} + /** * Map the shared subscription period to the subscriptions program's * `period_hours` value. The Solana profile only supports `day` and `week`; * `month` cannot be represented exactly because the on-chain program uses * fixed elapsed seconds. * + * `periodCount` may be the wire string, which is held to the profile's strict + * integer format, or a number (server configuration). + * * @throws If the inputs cannot be represented on-chain. */ -export function mapSubscriptionPeriodToHours(periodUnit: 'day' | 'week', periodCount: number): number { +export function mapSubscriptionPeriodToHours(periodUnit: 'day' | 'week', periodCountInput: number | string): number { + const periodCount = + typeof periodCountInput === 'string' + ? Number(parseSubscriptionInteger(periodCountInput, 'periodCount')) + : periodCountInput; if (!Number.isInteger(periodCount) || periodCount <= 0) { throw new Error(`periodCount must be a positive integer, got ${periodCount}`); } diff --git a/typescript/packages/pay-kit/package.json b/typescript/packages/pay-kit/package.json index 57ff0bfd7..53e1fea21 100644 --- a/typescript/packages/pay-kit/package.json +++ b/typescript/packages/pay-kit/package.json @@ -1,6 +1,6 @@ { "name": "@solana/pay-kit", - "version": "0.13.1", + "version": "0.14.0", "description": "Building blocks for Agentic payments (x402, MPP, AP2)", "repository": { "type": "git", @@ -28,18 +28,18 @@ "prepack": "node -e \"require('node:fs').copyFileSync('../../README.md', 'README.md')\"" }, "dependencies": { - "@solana-program/compute-budget": "^0.15.0", - "@solana-program/token": "^0.13.0", - "@solana-program/token-2022": "^0.11.0", + "@solana-program/compute-budget": "^0.20.0", + "@solana-program/token": "^0.18.0", + "@solana-program/token-2022": "^0.20.0", "@solana/keychain-memory": "^1.3.0", - "@solana/kit": ">=6.5.0", + "@solana/kit": "^8.5.0", "mppx": ">=0.8.15" }, "devDependencies": { "@solana/mpp": "workspace:^", "@types/node": "^25.5.0", - "@x402/core": "file:../../.x402-vendor/x402-core-2.26.0.tgz", - "@x402/svm": "file:../../.x402-vendor/x402-svm-2.26.0.tgz", + "@x402/core": "file:../../.x402-vendor/x402-core-2.28.0.tgz", + "@x402/svm": "file:../../.x402-vendor/x402-svm-2.28.0.tgz", "tsup": "^8.5.0" } } diff --git a/typescript/packages/pay-kit/src/__tests__/client.test.ts b/typescript/packages/pay-kit/src/__tests__/client.test.ts index 4ea1b6101..071472802 100644 --- a/typescript/packages/pay-kit/src/__tests__/client.test.ts +++ b/typescript/packages/pay-kit/src/__tests__/client.test.ts @@ -154,7 +154,10 @@ describe('createPayKitClient', () => { * Serve the 402 (with `extensions`), the mint and blockhash RPC calls, * and capture the payment envelope the client retries with. */ - async function payWithExtensions(extensions: Record): Promise> { + async function payWithExtensions( + extensions: Record, + options: { extra?: Record; maxTransactionVersion?: 0 | 1 } = {}, + ): Promise> { const feePayer = await generateKeyPairSigner(); const paymentRequired = btoa( JSON.stringify({ @@ -162,7 +165,7 @@ describe('createPayKitClient', () => { { amount: '1000', asset: MINT, - extra: { feePayer: feePayer.address }, + extra: { feePayer: feePayer.address, ...options.extra }, maxTimeoutSeconds: 300, network: DEVNET, payTo: feePayer.address, @@ -206,7 +209,13 @@ describe('createPayKitClient', () => { return Promise.resolve(response(402, { 'payment-required': paymentRequired })); }); - const client = await createPayKitClient({ accept: ['x402'], permissions: false, rpcUrl: RPC_URL, signer }); + const client = await createPayKitClient({ + accept: ['x402'], + maxTransactionVersion: options.maxTransactionVersion, + permissions: false, + rpcUrl: RPC_URL, + signer, + }); const result = await client.fetch('https://api.test/paid'); expect(result.status).toBe(200); @@ -230,6 +239,33 @@ describe('createPayKitClient', () => { expect(identifier.info.id).toMatch(/^pay_[0-9a-f]{32}$/); }); + /** First byte of the message: 0x81 for version 1, 0x80 for version 0. */ + function messageVersionByte(envelope: Record): number { + const transaction = (envelope.payload as { transaction: string }).transaction; + const bytes = Buffer.from(transaction, 'base64'); + // Version 1 puts the message first; version 0 after the signatures. + return bytes[0]! & 0x80 ? bytes[0]! : bytes[1 + 64 * bytes[0]!]!; + } + + it('builds version 1 when the server advertises it', async () => { + const envelope = await payWithExtensions({}, { extra: { transactionVersions: [0, 1] } }); + expect(messageVersionByte(envelope)).toBe(0x81); + }); + + it('builds version 0 for a signer limited to version 0', async () => { + const envelope = await payWithExtensions( + {}, + { extra: { transactionVersions: [0, 1] }, maxTransactionVersion: 0 }, + ); + expect(messageVersionByte(envelope)).toBe(0x80); + }); + + it('rejects a maxTransactionVersion other than 0 or 1', () => { + expect(() => + createPayKitClient({ accept: ['x402'], maxTransactionVersion: 2 as never, rpcUrl: RPC_URL, signer }), + ).toThrow(ConfigurationError); + }); + it('adds no id when the server does not require one', async () => { const envelope = await payWithExtensions({ 'payment-identifier': { info: { required: false } } }); diff --git a/typescript/packages/pay-kit/src/__tests__/x402.test.ts b/typescript/packages/pay-kit/src/__tests__/x402.test.ts index fda7c89c5..d6e10033d 100644 --- a/typescript/packages/pay-kit/src/__tests__/x402.test.ts +++ b/typescript/packages/pay-kit/src/__tests__/x402.test.ts @@ -1,4 +1,5 @@ import type { ExactSvmSchemeOptions } from '@x402/svm'; +import type { UptoSvmFacilitatorConfig } from '@x402/svm/upto/facilitator'; import { beforeEach, describe, expect, expectTypeOf, it, vi } from 'vitest'; import type { X402Options } from '../config.js'; @@ -6,10 +7,13 @@ import type { X402Options } from '../config.js'; // Compile-time drift guard: X402Options must equal the full vendored // @x402/svm option surface modulo readonly (our config is frozen). Key drift // in either direction — including upstream adding an option we don't expose — -// optionality drift, and per-key widening/narrowing all fail typecheck. +// optionality drift, and per-key widening/narrowing all fail typecheck. The +// upto facilitator's treasury owner is the one upto-only option on top. type ImmutableValue = V extends readonly (infer E)[] ? readonly E[] : V; type Immutable = { readonly [K in keyof T]: ImmutableValue }; -expectTypeOf>().toEqualTypeOf(); +expectTypeOf< + Immutable> +>().toEqualTypeOf(); // The upto challenge requires a server-fetched recentBlockhash + recentSlot // (one getLatestBlockhash call); stub the RPC so the enriched requirement is @@ -133,6 +137,8 @@ describe('x402 exact adapter', () => { expect(typeof entry.network).toBe('string'); expect(typeof entry.asset).toBe('string'); expect((entry.extra as { feePayer?: string }).feePayer).toBe(config.operator.signer.pubkey); + // Copied from the facilitator's /supported extra (scheme_exact_svm.md §1.5). + expect((entry.extra as { transactionVersions?: unknown }).transactionVersions).toEqual([0, 1]); }); it('detects the x402 payment header', async () => { @@ -404,6 +410,18 @@ describe('x402 smart-wallet options', () => { expect(uptoCtorCalls.at(-1)?.[1]).toEqual({}); }); + it('forwards a configured treasury owner to the upto facilitator only when set', async () => { + const owner = 'Cs2zdfUNonRdRGsiZUQQLdTxzxVvJZmgiX2mpLYKuEqP'; + const config = await configure({ + mpp: { challengeBindingSecret: 'x402-test-secret' }, + network: 'solana_devnet', + x402: { paymentChannelsTreasuryOwner: owner }, + }); + uptoCtorCalls.length = 0; + new X402Upto(config); + expect(uptoCtorCalls.at(-1)?.[1]).toEqual({ paymentChannelsTreasuryOwner: owner }); + }); + it('copies the allowlist so callers cannot mutate verification policy', async () => { const allowed = ['SQDS4ep65T869zMMBKyuUq6aD6EgTu8psMjkvj52pCf']; const config = await configure({ @@ -429,6 +447,7 @@ describe('x402 upto engine', () => { expect((entry.extra as { feePayer?: string }).feePayer).toBe(config.operator.signer.pubkey); expect((entry.extra as { receiverAuthorizer?: string }).receiverAuthorizer).toBe(config.operator.signer.pubkey); expect((entry.extra as { withdrawDelay?: number }).withdrawDelay).toBe(900); + expect((entry.extra as { transactionVersions?: unknown }).transactionVersions).toEqual([0, 1]); expect((entry.extra as { tokenProgram?: string }).tokenProgram).toEqual(expect.any(String)); expect((entry.extra as { assetTransferMethod?: string }).assetTransferMethod).toBeUndefined(); expect((entry.extra as { facilitatorAddress?: string }).facilitatorAddress).toBeUndefined(); diff --git a/typescript/packages/pay-kit/src/adapters/x402-upto.ts b/typescript/packages/pay-kit/src/adapters/x402-upto.ts index 21eac6cf6..6e3f82844 100644 --- a/typescript/packages/pay-kit/src/adapters/x402-upto.ts +++ b/typescript/packages/pay-kit/src/adapters/x402-upto.ts @@ -83,6 +83,8 @@ export type UptoSettlement = { */ export class X402Upto { readonly #facilitator: x402Facilitator; + /** The facilitator's `extra.transactionVersions`, copied into every challenge. */ + readonly #transactionVersions: unknown; readonly #network: Network; readonly #feePayer: string; readonly #receiverAuthorizer: string; @@ -102,22 +104,26 @@ export class X402Upto { this.#recipient = config.operator.recipient; this.#rpcUrl = config.rpcUrl; this.#stablecoins = config.stablecoins; - this.#facilitator = new x402Facilitator().register( - this.#network, - // The facilitator reads and broadcasts through the signer's RPC - // (`defaultRpcUrl`); upstream dropped the separate `rpcUrl` option. - // A configured pending-settlement store is shared with the exact - // adapter so a settle retry on another replica reconciles for - // both schemes. - new UptoSvmFacilitator( - toFacilitatorSvmSigner(config.operator.signer.signer, { defaultRpcUrl: config.rpcUrl }), - { - ...(config.x402.pendingSettlementStore && { - pendingSettlementStore: config.x402.pendingSettlementStore, - }), - }, - ), + // The facilitator reads and broadcasts through the signer's RPC + // (`defaultRpcUrl`); upstream dropped the separate `rpcUrl` option. + // A configured pending-settlement store is shared with the exact + // adapter so a settle retry on another replica reconciles for + // both schemes. + const scheme = new UptoSvmFacilitator( + toFacilitatorSvmSigner(config.operator.signer.signer, { defaultRpcUrl: config.rpcUrl }), + { + ...(config.x402.pendingSettlementStore && { + pendingSettlementStore: config.x402.pendingSettlementStore, + }), + ...(config.x402.paymentChannelsTreasuryOwner && { + paymentChannelsTreasuryOwner: config.x402.paymentChannelsTreasuryOwner, + }), + }, ); + this.#facilitator = new x402Facilitator().register(this.#network, scheme); + // scheme_upto_svm.md: the server copies the facilitator's + // `transactionVersions` into the requirements. + this.#transactionVersions = scheme.getExtra(this.#network)?.transactionVersions; } /** Whether `request` carries an x402 payment credential. */ @@ -313,6 +319,7 @@ export class X402Upto { receiverAuthorizer: this.#receiverAuthorizer, ...(recentSlot !== undefined && { recentSlot: recentSlot.toString() }), tokenProgram: getStablecoinTokenProgram(mint, this.#network), + ...(this.#transactionVersions !== undefined && { transactionVersions: this.#transactionVersions }), withdrawDelay: DEFAULT_WITHDRAW_DELAY_SECONDS, }, maxTimeoutSeconds: MAX_TIMEOUT_SECONDS, diff --git a/typescript/packages/pay-kit/src/adapters/x402.ts b/typescript/packages/pay-kit/src/adapters/x402.ts index 8e203f6a3..2cce9b92c 100644 --- a/typescript/packages/pay-kit/src/adapters/x402.ts +++ b/typescript/packages/pay-kit/src/adapters/x402.ts @@ -51,14 +51,16 @@ export function createX402ExactAdapter(config: PayKitConfig): ProtocolAdapter { }; // In-process facilitator: the operator both fee-pays and signs settlement. - const facilitator = new x402Facilitator().register( - network, - new ExactSvmFacilitator( - toFacilitatorSvmSigner(config.operator.signer.signer, { defaultRpcUrl: config.rpcUrl }), - undefined, - schemeOptions, - ), + const scheme = new ExactSvmFacilitator( + toFacilitatorSvmSigner(config.operator.signer.signer, { defaultRpcUrl: config.rpcUrl }), + undefined, + schemeOptions, ); + const facilitator = new x402Facilitator().register(network, scheme); + // scheme_exact_svm.md §1.5: the server MUST copy the facilitator's + // `extra.transactionVersions` into the requirements, so clients build a + // version the facilitator accepts (version 1 when it accepts it). + const transactionVersions = scheme.getExtra(network)?.transactionVersions; function mintFor(gate: Gate): string { const coin = resolveCoin(gate.amount, config.stablecoins); @@ -70,7 +72,10 @@ export function createX402ExactAdapter(config: PayKitConfig): ProtocolAdapter { return { amount: gate.total().baseUnits().toString(), asset: mintFor(gate), - extra: { feePayer: operator }, + extra: { + feePayer: operator, + ...(transactionVersions !== undefined && { transactionVersions }), + }, maxTimeoutSeconds: MAX_TIMEOUT_SECONDS, network, payTo: gate.payTo, diff --git a/typescript/packages/pay-kit/src/client/index.ts b/typescript/packages/pay-kit/src/client/index.ts index ffb2fd557..44c655687 100644 --- a/typescript/packages/pay-kit/src/client/index.ts +++ b/typescript/packages/pay-kit/src/client/index.ts @@ -45,6 +45,13 @@ const nativeFetch: typeof fetch = globalThis.fetch.bind(globalThis); export type PayKitClientOptions = { /** Protocols the client will pay with. Defaults to `['x402', 'mpp']`. */ readonly accept?: readonly Protocol[]; + /** + * Highest Solana transaction message version the signer can sign. x402 + * payments build the highest version the server advertises up to this one; + * set `0` for a signer (such as a wallet) that cannot sign version 1. + * Defaults to `1`. Applies to x402 `exact` and `upto`. + */ + readonly maxTransactionVersion?: 0 | 1; /** Solana cluster used to pin default permissions. Defaults to `mainnet`. */ readonly network?: SolanaNetwork; /** Progress callback, forwarded to the MPP charge/subscription methods. */ @@ -76,6 +83,7 @@ export class PayKitClientBuilder { #permissions: ClientPermissions | false | undefined; #rpcUrl: string | undefined; #signer: KeyPairSigner | undefined; + #maxTransactionVersion: 0 | 1 | undefined; /** Set the payer signer. */ signer(signer: KeyPairSigner): this { @@ -107,6 +115,12 @@ export class PayKitClientBuilder { return this; } + /** Set the highest transaction version the signer can sign; see {@link PayKitClientOptions.maxTransactionVersion}. */ + maxTransactionVersion(version: 0 | 1): this { + this.#maxTransactionVersion = version; + return this; + } + /** Set a payment progress callback. */ onProgress(callback: (event: unknown) => void): this { this.#onProgress = callback; @@ -119,6 +133,7 @@ export class PayKitClientBuilder { if (!this.#rpcUrl) throw new ConfigurationError('PayKitClient requires an RPC URL'); return createPayKitClient({ accept: this.#accept, + maxTransactionVersion: this.#maxTransactionVersion, network: this.#network, onProgress: this.#onProgress, permissions: this.#permissions, @@ -177,7 +192,14 @@ export function createPayKitClient(options: PayKitClientOptions): Promise=2.0.10' '@humanfs/node': 0.16.8 baseline-browser-mapping: 2.11.0 @@ -16,12 +16,14 @@ overrides: brace-expansion@5.0.4: 5.0.12 brace-expansion@5.0.6: 5.0.12 linkify-it: 5.0.2 - markdown-it: 14.3.1 + markdown-it: '>=14.3.3 <15' nanoid@3.3.11: 3.3.18 picomatch@2.3.1: 2.3.2 postcss: 8.5.23 source-map-js: 1.2.2 - vite: 8.0.16 + vite: '>=8.1.6 <9' + esbuild: '>=0.28.1 <0.29' + '@babel/core': '>=7.29.6 <8' '@modelcontextprotocol/sdk': '>=1.31.0' fast-uri: '>=4.1.5' hono: '>=4.13.11' @@ -30,7 +32,8 @@ overrides: path-to-regexp: '>=8.4.0' qs: '>=6.16.0' yaml: '>=2.8.3' - body-parser: '>=2.3.0' + body-parser: '>=2.4.0' + zod: '>=4.6.6 <5' proxy-addr: '>=2.0.8' '@toon-format/toon': 2.3.1 @@ -51,8 +54,8 @@ importers: specifier: ^8.57.1 version: 8.57.1(eslint@9.39.4)(typescript@5.9.3) '@vitest/coverage-v8': - specifier: 4.1.11 - version: 4.1.11(vitest@4.1.11) + specifier: 4.1.12 + version: 4.1.12(vitest@4.1.12) eslint: specifier: ^9.39.4 version: 9.39.4 @@ -69,8 +72,8 @@ importers: specifier: ^5.7.0 version: 5.9.3 vitest: - specifier: 4.1.11 - version: 4.1.11(@types/node@25.5.0)(@vitest/coverage-v8@4.1.11)(vite@8.0.16(@types/node@25.5.0)(esbuild@0.27.4)(tsx@4.21.0)(yaml@2.9.0)) + specifier: 4.1.12 + version: 4.1.12(@types/node@25.5.0)(@vitest/coverage-v8@4.1.12)(vite@8.3.5(@types/node@25.5.0)(esbuild@0.28.2)(tsx@4.21.0)(yaml@2.9.0)) packages/mpp: dependencies: @@ -93,8 +96,8 @@ importers: specifier: ^0.5.0 version: 0.5.0(@solana/kit@6.10.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6))(@solana/sysvars@7.1.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: '>=4.6.6 <5' + version: 4.6.7 devDependencies: '@solana/kit': specifier: ^6.10.0 @@ -107,7 +110,7 @@ importers: version: 25.5.0 mppx: specifier: ^0.8.15 - version: 0.8.15(express@5.2.1)(typescript@5.9.3)(viem@2.55.10(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.4.3)) + version: 0.8.15(express@5.2.1)(typescript@5.9.3)(viem@2.55.10(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.6.7)) surfpool-sdk: specifier: ^1.2.0 version: 1.2.0 @@ -118,23 +121,23 @@ importers: packages/pay-kit: dependencies: '@solana-program/compute-budget': - specifier: ^0.15.0 - version: 0.15.0(@solana/kit@6.10.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6)) + specifier: ^0.20.0 + version: 0.20.0(@solana/kit@8.5.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6)) '@solana-program/token': - specifier: ^0.13.0 - version: 0.13.0(@solana/kit@6.10.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6)) + specifier: ^0.18.0 + version: 0.18.0(@solana/kit@8.5.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6)) '@solana-program/token-2022': - specifier: ^0.11.0 - version: 0.11.0(@solana/kit@6.10.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6))(@solana/sysvars@5.5.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)) + specifier: ^0.20.0 + version: 0.20.0(@solana/kit@8.5.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6))(@solana/sysvars@8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)) '@solana/keychain-memory': specifier: ^1.3.0 - version: 1.3.0(@solana/addresses@7.1.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))(@solana/codecs-core@7.1.1(typescript@5.9.3))(@solana/codecs-strings@7.1.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))(@solana/keys@7.1.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))(@solana/signers@7.1.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))(@solana/transactions@7.1.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)) + version: 1.3.0(@solana/addresses@8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))(@solana/codecs-core@8.5.0(typescript@5.9.3))(@solana/codecs-strings@8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))(@solana/keys@8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))(@solana/signers@8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))(@solana/transactions@8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)) '@solana/kit': - specifier: '>=6.5.0' - version: 6.10.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6) + specifier: ^8.5.0 + version: 8.5.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6) mppx: specifier: '>=0.8.15' - version: 0.8.15(express@5.2.1)(typescript@5.9.3)(viem@2.55.10(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.4.3)) + version: 0.8.15(express@5.2.1)(typescript@5.9.3)(viem@2.55.10(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.6.7)) devDependencies: '@solana/mpp': specifier: workspace:^ @@ -143,11 +146,11 @@ importers: specifier: ^25.5.0 version: 25.5.0 '@x402/core': - specifier: file:../../.x402-vendor/x402-core-2.26.0.tgz - version: file:.x402-vendor/x402-core-2.26.0.tgz + specifier: file:../../.x402-vendor/x402-core-2.28.0.tgz + version: file:.x402-vendor/x402-core-2.28.0.tgz '@x402/svm': - specifier: file:../../.x402-vendor/x402-svm-2.26.0.tgz - version: file:.x402-vendor/x402-svm-2.26.0.tgz(@solana/kit@6.10.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6))(@solana/sysvars@5.5.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + specifier: file:../../.x402-vendor/x402-svm-2.28.0.tgz + version: file:.x402-vendor/x402-svm-2.28.0.tgz(@solana/kit@8.5.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6))(@solana/sysvars@8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) tsup: specifier: ^8.5.0 version: 8.5.1(postcss@8.5.23)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.9.0) @@ -157,39 +160,39 @@ packages: '@adraffy/ens-normalize@1.11.1': resolution: {integrity: sha512-nhCBV3quEgesuf7c7KYfperqSS14T8bYuvJ8PcLJp6znkZpFc0AuW4qBtr8eKVyPPe/8RSr7sglCWPU5eaxwKQ==} - '@babel/code-frame@7.29.0': - resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} + '@babel/code-frame@7.29.7': + resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==} engines: {node: '>=6.9.0'} - '@babel/compat-data@7.29.0': - resolution: {integrity: sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==} + '@babel/compat-data@7.29.7': + resolution: {integrity: sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==} engines: {node: '>=6.9.0'} - '@babel/core@7.29.0': - resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==} + '@babel/core@7.29.7': + resolution: {integrity: sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==} engines: {node: '>=6.9.0'} - '@babel/generator@7.29.1': - resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} + '@babel/generator@7.29.8': + resolution: {integrity: sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==} engines: {node: '>=6.9.0'} - '@babel/helper-compilation-targets@7.28.6': - resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==} + '@babel/helper-compilation-targets@7.29.7': + resolution: {integrity: sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==} engines: {node: '>=6.9.0'} - '@babel/helper-globals@7.28.0': - resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} + '@babel/helper-globals@7.29.7': + resolution: {integrity: sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==} engines: {node: '>=6.9.0'} - '@babel/helper-module-imports@7.28.6': - resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==} + '@babel/helper-module-imports@7.29.7': + resolution: {integrity: sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==} engines: {node: '>=6.9.0'} - '@babel/helper-module-transforms@7.28.6': - resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==} + '@babel/helper-module-transforms@7.29.7': + resolution: {integrity: sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==} engines: {node: '>=6.9.0'} peerDependencies: - '@babel/core': ^7.0.0 + '@babel/core': '>=7.29.6 <8' '@babel/helper-plugin-utils@7.28.6': resolution: {integrity: sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==} @@ -199,18 +202,31 @@ packages: resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} engines: {node: '>=6.9.0'} + '@babel/helper-string-parser@7.29.11': + resolution: {integrity: sha512-snZbO7MEDOof+hvNa97EjEY7qD7h2kwvQr5AJC3ZhQudKW5dnej6k3kP9NQV88hJwaS8vDqRLFo9rivLEhle2g==} + engines: {node: '>=6.9.0'} + '@babel/helper-validator-identifier@7.28.5': resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-option@7.27.1': - resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} + '@babel/helper-validator-identifier@7.29.7': + resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} engines: {node: '>=6.9.0'} - '@babel/helpers@7.29.2': - resolution: {integrity: sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==} + '@babel/helper-validator-option@7.29.7': + resolution: {integrity: sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==} engines: {node: '>=6.9.0'} + '@babel/helpers@7.29.10': + resolution: {integrity: sha512-EMCx3AGZ3WfAl6ht7AyQoPm2Lh+BGYEMdc4Q6Hf7uSCDOZFuLq44qNwL+iaim8VlyYhRAo4X43+weadK8ZB4Yg==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.29.11': + resolution: {integrity: sha512-OZ6+oaK7GMyg3IfCpj8JOmn8n+w2rJbDT0LLfVDTLb1ZFeKDh3AiNELgCMUw175IJHSkLl74hG0M0VLsvx+gag==} + engines: {node: '>=6.0.0'} + hasBin: true + '@babel/parser@7.29.2': resolution: {integrity: sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==} engines: {node: '>=6.0.0'} @@ -219,106 +235,110 @@ packages: '@babel/plugin-syntax-async-generators@7.8.4': resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/core': '>=7.29.6 <8' '@babel/plugin-syntax-bigint@7.8.3': resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/core': '>=7.29.6 <8' '@babel/plugin-syntax-class-properties@7.12.13': resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/core': '>=7.29.6 <8' '@babel/plugin-syntax-class-static-block@7.14.5': resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==} engines: {node: '>=6.9.0'} peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/core': '>=7.29.6 <8' '@babel/plugin-syntax-import-attributes@7.28.6': resolution: {integrity: sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==} engines: {node: '>=6.9.0'} peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/core': '>=7.29.6 <8' '@babel/plugin-syntax-import-meta@7.10.4': resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/core': '>=7.29.6 <8' '@babel/plugin-syntax-json-strings@7.8.3': resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/core': '>=7.29.6 <8' '@babel/plugin-syntax-jsx@7.28.6': resolution: {integrity: sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==} engines: {node: '>=6.9.0'} peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/core': '>=7.29.6 <8' '@babel/plugin-syntax-logical-assignment-operators@7.10.4': resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/core': '>=7.29.6 <8' '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3': resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/core': '>=7.29.6 <8' '@babel/plugin-syntax-numeric-separator@7.10.4': resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/core': '>=7.29.6 <8' '@babel/plugin-syntax-object-rest-spread@7.8.3': resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/core': '>=7.29.6 <8' '@babel/plugin-syntax-optional-catch-binding@7.8.3': resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/core': '>=7.29.6 <8' '@babel/plugin-syntax-optional-chaining@7.8.3': resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/core': '>=7.29.6 <8' '@babel/plugin-syntax-private-property-in-object@7.14.5': resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==} engines: {node: '>=6.9.0'} peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/core': '>=7.29.6 <8' '@babel/plugin-syntax-top-level-await@7.14.5': resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} engines: {node: '>=6.9.0'} peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/core': '>=7.29.6 <8' '@babel/plugin-syntax-typescript@7.28.6': resolution: {integrity: sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==} engines: {node: '>=6.9.0'} peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/core': '>=7.29.6 <8' - '@babel/template@7.28.6': - resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} + '@babel/template@7.29.7': + resolution: {integrity: sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==} engines: {node: '>=6.9.0'} - '@babel/traverse@7.29.0': - resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} + '@babel/traverse@7.29.10': + resolution: {integrity: sha512-B3lYAs2nkKskbgQ1nfy8Ma9ao9Q1rntTAQHrzzyDuj+TSO+X3le6PfWwqDvodsb+OumE10eMFfuMCTQSQ5iuIQ==} engines: {node: '>=6.9.0'} '@babel/types@7.29.0': resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} engines: {node: '>=6.9.0'} + '@babel/types@7.29.11': + resolution: {integrity: sha512-WCsemW40Cpc6gouC1SrY6PBaZ+oLRlEVY9XBvZBI7il/HyUrb2nJ505wE1MHEFyDZNnrWDEuy4jL50WVHfTTSQ==} + engines: {node: '>=6.9.0'} + '@bcoe/v8-coverage@0.2.3': resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} @@ -338,158 +358,158 @@ packages: '@emnapi/wasi-threads@1.2.1': resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} - '@esbuild/aix-ppc64@0.27.4': - resolution: {integrity: sha512-cQPwL2mp2nSmHHJlCyoXgHGhbEPMrEEU5xhkcy3Hs/O7nGZqEpZ2sUtLaL9MORLtDfRvVl2/3PAuEkYZH0Ty8Q==} + '@esbuild/aix-ppc64@0.28.2': + resolution: {integrity: sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.27.4': - resolution: {integrity: sha512-gdLscB7v75wRfu7QSm/zg6Rx29VLdy9eTr2t44sfTW7CxwAtQghZ4ZnqHk3/ogz7xao0QAgrkradbBzcqFPasw==} + '@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.4': - resolution: {integrity: sha512-X9bUgvxiC8CHAGKYufLIHGXPJWnr0OCdR0anD2e21vdvgCI8lIfqFbnoeOz7lBjdrAGUhqLZLcQo6MLhTO2DKQ==} + '@esbuild/android-arm@0.28.2': + resolution: {integrity: sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==} engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-x64@0.27.4': - resolution: {integrity: sha512-PzPFnBNVF292sfpfhiyiXCGSn9HZg5BcAz+ivBuSsl6Rk4ga1oEXAamhOXRFyMcjwr2DVtm40G65N3GLeH1Lvw==} + '@esbuild/android-x64@0.28.2': + resolution: {integrity: sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==} engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.27.4': - resolution: {integrity: sha512-b7xaGIwdJlht8ZFCvMkpDN6uiSmnxxK56N2GDTMYPr2/gzvfdQN8rTfBsvVKmIVY/X7EM+/hJKEIbbHs9oA4tQ==} + '@esbuild/darwin-arm64@0.28.2': + resolution: {integrity: sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.27.4': - resolution: {integrity: sha512-sR+OiKLwd15nmCdqpXMnuJ9W2kpy0KigzqScqHI3Hqwr7IXxBp3Yva+yJwoqh7rE8V77tdoheRYataNKL4QrPw==} + '@esbuild/darwin-x64@0.28.2': + resolution: {integrity: sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==} engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.27.4': - resolution: {integrity: sha512-jnfpKe+p79tCnm4GVav68A7tUFeKQwQyLgESwEAUzyxk/TJr4QdGog9sqWNcUbr/bZt/O/HXouspuQDd9JxFSw==} + '@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.4': - resolution: {integrity: sha512-2kb4ceA/CpfUrIcTUl1wrP/9ad9Atrp5J94Lq69w7UwOMolPIGrfLSvAKJp0RTvkPPyn6CIWrNy13kyLikZRZQ==} + '@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.4': - resolution: {integrity: sha512-7nQOttdzVGth1iz57kxg9uCz57dxQLHWxopL6mYuYthohPKEK0vU0C3O21CcBK6KDlkYVcnDXY099HcCDXd9dA==} + '@esbuild/linux-arm64@0.28.2': + resolution: {integrity: sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==} engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.27.4': - resolution: {integrity: sha512-aBYgcIxX/wd5n2ys0yESGeYMGF+pv6g0DhZr3G1ZG4jMfruU9Tl1i2Z+Wnj9/KjGz1lTLCcorqE2viePZqj4Eg==} + '@esbuild/linux-arm@0.28.2': + resolution: {integrity: sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==} engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.27.4': - resolution: {integrity: sha512-oPtixtAIzgvzYcKBQM/qZ3R+9TEUd1aNJQu0HhGyqtx6oS7qTpvjheIWBbes4+qu1bNlo2V4cbkISr8q6gRBFA==} + '@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.4': - resolution: {integrity: sha512-8mL/vh8qeCoRcFH2nM8wm5uJP+ZcVYGGayMavi8GmRJjuI3g1v6Z7Ni0JJKAJW+m0EtUuARb6Lmp4hMjzCBWzA==} + '@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.4': - resolution: {integrity: sha512-1RdrWFFiiLIW7LQq9Q2NES+HiD4NyT8Itj9AUeCl0IVCA459WnPhREKgwrpaIfTOe+/2rdntisegiPWn/r/aAw==} + '@esbuild/linux-mips64el@0.28.2': + resolution: {integrity: sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.27.4': - resolution: {integrity: sha512-tLCwNG47l3sd9lpfyx9LAGEGItCUeRCWeAx6x2Jmbav65nAwoPXfewtAdtbtit/pJFLUWOhpv0FpS6GQAmPrHA==} + '@esbuild/linux-ppc64@0.28.2': + resolution: {integrity: sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.27.4': - resolution: {integrity: sha512-BnASypppbUWyqjd1KIpU4AUBiIhVr6YlHx/cnPgqEkNoVOhHg+YiSVxM1RLfiy4t9cAulbRGTNCKOcqHrEQLIw==} + '@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.4': - resolution: {integrity: sha512-+eUqgb/Z7vxVLezG8bVB9SfBie89gMueS+I0xYh2tJdw3vqA/0ImZJ2ROeWwVJN59ihBeZ7Tu92dF/5dy5FttA==} + '@esbuild/linux-s390x@0.28.2': + resolution: {integrity: sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==} engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.27.4': - resolution: {integrity: sha512-S5qOXrKV8BQEzJPVxAwnryi2+Iq5pB40gTEIT69BQONqR7JH1EPIcQ/Uiv9mCnn05jff9umq/5nqzxlqTOg9NA==} + '@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.4': - resolution: {integrity: sha512-xHT8X4sb0GS8qTqiwzHqpY00C95DPAq7nAwX35Ie/s+LO9830hrMd3oX0ZMKLvy7vsonee73x0lmcdOVXFzd6Q==} + '@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.4': - resolution: {integrity: sha512-RugOvOdXfdyi5Tyv40kgQnI0byv66BFgAqjdgtAKqHoZTbTF2QqfQrFwa7cHEORJf6X2ht+l9ABLMP0dnKYsgg==} + '@esbuild/netbsd-x64@0.28.2': + resolution: {integrity: sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.27.4': - resolution: {integrity: sha512-2MyL3IAaTX+1/qP0O1SwskwcwCoOI4kV2IBX1xYnDDqthmq5ArrW94qSIKCAuRraMgPOmG0RDTA74mzYNQA9ow==} + '@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.4': - resolution: {integrity: sha512-u8fg/jQ5aQDfsnIV6+KwLOf1CmJnfu1ShpwqdwC0uA7ZPwFws55Ngc12vBdeUdnuWoQYx/SOQLGDcdlfXhYmXQ==} + '@esbuild/openbsd-x64@0.28.2': + resolution: {integrity: sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/openharmony-arm64@0.27.4': - resolution: {integrity: sha512-JkTZrl6VbyO8lDQO3yv26nNr2RM2yZzNrNHEsj9bm6dOwwu9OYN28CjzZkH57bh4w0I2F7IodpQvUAEd1mbWXg==} + '@esbuild/openharmony-arm64@0.28.2': + resolution: {integrity: sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] - '@esbuild/sunos-x64@0.27.4': - resolution: {integrity: sha512-/gOzgaewZJfeJTlsWhvUEmUG4tWEY2Spp5M20INYRg2ZKl9QPO3QEEgPeRtLjEWSW8FilRNacPOg8R1uaYkA6g==} + '@esbuild/sunos-x64@0.28.2': + resolution: {integrity: sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==} engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.27.4': - resolution: {integrity: sha512-Z9SExBg2y32smoDQdf1HRwHRt6vAHLXcxD2uGgO/v2jK7Y718Ix4ndsbNMU/+1Qiem9OiOdaqitioZwxivhXYg==} + '@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.4': - resolution: {integrity: sha512-DAyGLS0Jz5G5iixEbMHi5KdiApqHBWMGzTtMiJ72ZOLhbu/bzxgAe8Ue8CTS3n3HbIUHQz/L51yMdGMeoxXNJw==} + '@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.4': - resolution: {integrity: sha512-+knoa0BDoeXgkNvvV1vvbZX4+hizelrkwmGJBdT17t8FNPwG2lKemmuMZlmaNQ3ws3DKKCxpb4zRZEIp3UxFCg==} + '@esbuild/win32-x64@0.28.2': + resolution: {integrity: sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==} engines: {node: '>=18'} cpu: [x64] os: [win32] @@ -675,13 +695,6 @@ packages: '@napi-rs/wasm-runtime@0.2.12': resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} - '@napi-rs/wasm-runtime@1.2.4': - resolution: {integrity: sha512-AJxoUD2/15ESHbvpcyjU274nsAPLuOtPHCk0vKJM5pj//Fg/B1FXNWjPnXTT9PymCYYiHo4zPj0ZomXBKhoy7g==} - engines: {node: ^20.19.0 || ^22.13.0 || >=23.5.0} - peerDependencies: - '@emnapi/core': ^1.7.1 || ^2.0.0-alpha.4 - '@emnapi/runtime': ^1.7.1 || ^2.0.0-alpha.4 - '@noble/ciphers@1.3.0': resolution: {integrity: sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==} engines: {node: ^14.21.3 || >=16} @@ -710,8 +723,8 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} - '@oxc-project/types@0.133.0': - resolution: {integrity: sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==} + '@oxc-project/types@0.155.0': + resolution: {integrity: sha512-SeE8JPwW1xs1tHeNycjUtUBdhorRa8o4jlvjwk49R7/Z291i+4DQa7JJIgOm/TaYQZx+QrPQbVJ/9c8dMIZN8Q==} '@pkgjs/parseargs@0.11.0': resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} @@ -721,97 +734,98 @@ packages: resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} - '@rolldown/binding-android-arm64@1.0.3': - resolution: {integrity: sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==} + '@rolldown/binding-android-arm-eabi@1.2.15': + resolution: {integrity: sha512-aLcgK9gIJ3YRvrrtfSBbRa27F5WrpiTaPulnFpsHPxpUHgFlSgnU4854MHwoRGEBhfRJDWCS2WQ7lIjskE9Olw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [android] + + '@rolldown/binding-android-arm64@1.2.15': + resolution: {integrity: sha512-xD7DdZCrbThKuxNg7ooQmvp07ys4J/pnSEMTG3/OdOWl6daC67m/Q4fL78sRHMxTH/N4fGUbYhcPM0MF5WFHkg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@rolldown/binding-darwin-arm64@1.0.3': - resolution: {integrity: sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA==} + '@rolldown/binding-darwin-arm64@1.2.15': + resolution: {integrity: sha512-m2WuQ6r0B4OTYxyPpNLtXaMRbRDUbG8YQV2Q3KTdSSK8Th6KHCnC8jVCJt8bvYeSB5WivkkNbc85mKadaSdOxA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@rolldown/binding-darwin-x64@1.0.3': - resolution: {integrity: sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg==} + '@rolldown/binding-darwin-x64@1.2.15': + resolution: {integrity: sha512-5RtnsHM36nodM9WbMy+zip0LGS/G+y5wro5RHrpOlr4ac24+1zSi9kiV2MP1myZeZ/ifEHfulQcWjnAXzc2C2A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@rolldown/binding-freebsd-x64@1.0.3': - resolution: {integrity: sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g==} + '@rolldown/binding-freebsd-x64@1.2.15': + resolution: {integrity: sha512-g3l09pyFqhu+135JKkbkwiKGQmwU5hUMUPJ4VdBADvuqR8d33L6H578rh8m7rtxbdp+VmX/+nzI7nvhSZlzpUQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@rolldown/binding-linux-arm-gnueabihf@1.0.3': - resolution: {integrity: sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw==} + '@rolldown/binding-linux-arm-gnueabihf@1.2.15': + resolution: {integrity: sha512-nIe3VugI97nGQtspPxDqA4sXMUpeiocKIP/CqpY/u/vgbT+alX+cVxu1C/oVBPKg4feNTmYovE91v4DgXvXNwQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@rolldown/binding-linux-arm64-gnu@1.0.3': - resolution: {integrity: sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw==} + '@rolldown/binding-linux-arm64-gnu@1.2.15': + resolution: {integrity: sha512-iTBjXx+B5QSvgI89lJfmqh4wTh8NabR1YZIIN3hNx4zSG0EVfVqkOvLulNpG4251pbd6/IAmZ/LefVk1Y4rPhw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-arm64-musl@1.0.3': - resolution: {integrity: sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==} + '@rolldown/binding-linux-arm64-musl@1.2.15': + resolution: {integrity: sha512-uN26XOnVR7rqQupG3V9oAG2EGGatWjcJHOeDOHUFCh4TBWmP2tHTFoVN13aYbwfm0aHqJAEmcwhAu6sooIjfqQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] - '@rolldown/binding-linux-ppc64-gnu@1.0.3': - resolution: {integrity: sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==} + '@rolldown/binding-linux-ppc64-gnu@1.2.15': + resolution: {integrity: sha512-9nWkcdd+H+XhaA3fQIwpHnKIrfx/PQ6rO0pivr78Og07tXlUlctBBJoEYLPfhTmCR/QxEVdn6uPjHV5SymPhdw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-s390x-gnu@1.0.3': - resolution: {integrity: sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==} + '@rolldown/binding-linux-s390x-gnu@1.2.15': + resolution: {integrity: sha512-Ggh0ciFjLwIusLSLz7LZYEaGdxOAUJXI+Qu5JCbhPJJHEt8vP+IjRATTJheiJsdzzTYgUiHUiw3X1Ea3ZpMBdA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] libc: [glibc] - '@rolldown/binding-linux-x64-gnu@1.0.3': - resolution: {integrity: sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==} + '@rolldown/binding-linux-x64-gnu@1.2.15': + resolution: {integrity: sha512-FHg60rS6DBePAYZ9X9F67x+JObFdmgn6tupA1C/a3B+CufFmTD4mX+e8M75tCiAO3foR/6xwVBI0KQiI7sn/rw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-x64-musl@1.0.3': - resolution: {integrity: sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==} + '@rolldown/binding-linux-x64-musl@1.2.15': + resolution: {integrity: sha512-/cvV/7v5VGz/moiz0XKRj2dE8DzsKyhIu1KpOvJGPjRywg3yscON889UGvAe8zfiJLHup7VLjBduoGWi3HusWQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [musl] - '@rolldown/binding-openharmony-arm64@1.0.3': - resolution: {integrity: sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==} + '@rolldown/binding-openharmony-arm64@1.2.15': + resolution: {integrity: sha512-MyzC5Hrv/sm+Z7TSGKP/j8001RO2xQm1zOpCNVL4j0cY/VhBZviludA2YFQ7i4lH6ZAXxQm0lcMdBzM+99mE7w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@rolldown/binding-wasm32-wasi@1.0.3': - resolution: {integrity: sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [wasm32] - - '@rolldown/binding-win32-arm64-msvc@1.0.3': - resolution: {integrity: sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g==} + '@rolldown/binding-win32-arm64-msvc@1.2.15': + resolution: {integrity: sha512-+PgYiS+AH5omy6L45ZLxybasauJaj3M8buoT83D+nzPmCayXlxUV9hydhciCKVyIg0B/v0BtXPDE1uGqNwCPpg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@rolldown/binding-win32-x64-msvc@1.0.3': - resolution: {integrity: sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA==} + '@rolldown/binding-win32-x64-msvc@1.2.15': + resolution: {integrity: sha512-HFZd2QNQYn1JbIi+Hpd7H+r/lkWxcfIu28nirZ6eCn2LafuvmExMlb/P96Sfx5tf7pPArw39IdhmCF8vmV+NhQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] @@ -994,46 +1008,56 @@ packages: '@sinonjs/fake-timers@15.1.1': resolution: {integrity: sha512-cO5W33JgAPbOh07tvZjUOJ7oWhtaqGHiZw+11DPbyqh2kHTBc3eF/CjJDeQ4205RLQsX6rxCuYOroFQwl7JDRw==} - '@solana-program/compute-budget@0.11.0': - resolution: {integrity: sha512-7f1ePqB/eURkTwTOO9TNIdUXZcyrZoX3Uy2hNo7cXMfNhPFWp9AVgIyRNBc2jf15sdUa9gNpW+PfP2iV8AYAaw==} - peerDependencies: - '@solana/kit': ^5.0 - '@solana-program/compute-budget@0.15.0': resolution: {integrity: sha512-toejNdIkzpUTqLSIzP0Nofr/EFel8QpPWuTtIKzfCcjn+mXpkThHxPJaNesk251rSTiWaxDZ3WxG7RxYwTWTqA==} peerDependencies: '@solana/kit': ^6.3.0 + '@solana-program/compute-budget@0.18.1': + resolution: {integrity: sha512-ZVWknu3XvF6NI3zAuT6TXV19lQ7iDPzToM9gwI6KnUlnzHHP3u7IAIzDM7hLueQ6T7vLGjIUjYFCVg4mLHRZcg==} + peerDependencies: + '@solana/kit': ^8.0.0 + + '@solana-program/compute-budget@0.20.0': + resolution: {integrity: sha512-7SrwpFVNX6R5sjmPnqHUohCwZ3167TsWtE1Htg5wVrnsSoKfS8o1JxH033S/mYE56jGLwusYgNAwJn+Md1JmTQ==} + peerDependencies: + '@solana/kit': ^8.5.0 + '@solana-program/record@0.3.0': resolution: {integrity: sha512-q8z86INfXRQ5357qgVBrw05vC+u3xg8Vb4E1gEwnYUvAkL3cbJSjWVfTlGRiGWYmPNq/FYIWbsFrhsxXyhaJ+w==} engines: {node: '>=24.0.0'} peerDependencies: '@solana/kit': ^7.0.0 + '@solana-program/record@0.4.1': + resolution: {integrity: sha512-3iurtMAc3POMKVSZBqpNZQeoxAYVIxi0VZNOjkdaZqxr5glCxkWWruT8JekDwNFM0FnXxvtdu7tFFn3j6Kpegg==} + peerDependencies: + '@solana/kit': ^8.0.0 + + '@solana-program/record@0.6.0': + resolution: {integrity: sha512-8NeDjYA8OVWiL7sZqURsYFPXoT/i1c2A1Wt4k5MOMEItehX8fUOj7uCspU85lC+so+tsEmJ09qO0t8vN8kk/ZQ==} + peerDependencies: + '@solana/kit': ^8.5.0 + '@solana-program/system@0.12.0': resolution: {integrity: sha512-ZnAAWeGVMWNtJhw3GdifI2HnhZ0A0H0qs8tBkcFvxp/8wIavvO+GOM4Jd0N22u2+Lni2zcwvcrxrsxj6Mjphng==} peerDependencies: '@solana/kit': ^6.1.0 - '@solana-program/system@0.12.2': - resolution: {integrity: sha512-MaBeOxlvTruQhA7UYkOb3hVTEHPPagOtd+PvTm6a8rGgvEAP0kD4BbC37NceOaR4ABNqdaCmD5OMVRKgrE6KAg==} - peerDependencies: - '@solana/kit': ^6.4.0 - '@solana-program/system@0.13.0': resolution: {integrity: sha512-Id6QQxCG7ByImXPD5X/c3Ag2kySD+49aJ9waIkfxyUFyokhMQgxYQAx2rKuaygaBlaBQY6VVfBS46pqxZV+99A==} peerDependencies: '@solana/kit': ^7.0.0 - '@solana-program/token-2022@0.11.0': - resolution: {integrity: sha512-4yhSajmlZdMl98vJvt63kW6L0ERtV7UFcfZGJFyUVfTMxTrgghp8BNyhh5S1Ho3p4yHqfgL4N9VgVQ9GCnqqbg==} + '@solana-program/system@0.14.1': + resolution: {integrity: sha512-K6ZiIrAKoJAfcwfUdsoFvfSAxeRJaRrV7BPFTJvUVRS4m3zszN+nLcdaNMMe2F1/zTriZqC+xh+Kgw6ziGUqpQ==} peerDependencies: - '@solana/kit': ^6.0.0 - '@solana/sysvars': ^5.0 - '@solana/zk-sdk': ^0.4.2 - peerDependenciesMeta: - '@solana/zk-sdk': - optional: true + '@solana/kit': ^8.0.0 + + '@solana-program/system@0.16.0': + resolution: {integrity: sha512-/RG6q2E2vG/XpdOt8Jj/kbQktPlL5JyJuNGAeN9wDcxKDKQtrGTJpDrJgQUxiEy23fsPNXQbLN8XeCtYoMof3Q==} + peerDependencies: + '@solana/kit': ^8.5.0 '@solana-program/token-2022@0.14.1': resolution: {integrity: sha512-8yDF8xgEYU3HyfT4o7nLKHKMWQr3r2+1zBFojWYMkRyVh6YjuPO6Sxzf+p9trvL9Ddwp0d8SvqmMdYeErBZROA==} @@ -1046,51 +1070,61 @@ packages: '@solana/zk-sdk': optional: true - '@solana-program/token-2022@0.6.1': - resolution: {integrity: sha512-Ex02cruDMGfBMvZZCrggVR45vdQQSI/unHVpt/7HPt/IwFYB4eTlXtO8otYZyqV/ce5GqZ8S6uwyRf0zy6fdbA==} + '@solana-program/token-2022@0.16.1': + resolution: {integrity: sha512-VEQHBcFFGErW+gDGQAjuLRjAbg2x7uJqoWV9EgwG82exPpqHP2VGcV0sb7DXc8uXP+IvkmZeVH81gtuKyMxpZw==} peerDependencies: - '@solana/kit': ^5.0 - '@solana/sysvars': ^5.0 + '@solana/kit': ^8.0.0 + '@solana/sysvars': ^8.0.0 + '@solana/zk-sdk': ^0.5.1 + peerDependenciesMeta: + '@solana/zk-sdk': + optional: true + + '@solana-program/token-2022@0.20.0': + resolution: {integrity: sha512-MMi+1szfgSHUdtk1drBbQsMVdTOOdGjzgH9i3IN42EZC07x5ZrXcgraZanrFSoS+DnSlTF+vFVOvmFE38rQBXA==} + peerDependencies: + '@solana/kit': ^8.5.0 + '@solana/sysvars': ^8.0.0 + '@solana/zk-sdk': ^0.5.4 + peerDependenciesMeta: + '@solana/zk-sdk': + optional: true '@solana-program/token@0.11.0': resolution: {integrity: sha512-/lB72Pcmkn5kjUfP1Vd8F86HBlhN9RN4hJYgUG5csc23w9LCdYom2CiRdGsK25KkR9UFf6ndCCAMh83hMo+ftw==} peerDependencies: '@solana/kit': ^6.1.0 - '@solana-program/token@0.13.0': - resolution: {integrity: sha512-/Apjrd5lwOJGrPB0J5Rv7EBeclvyEBQPAGA85Scm7wBH+GpkbdLDM9uK3TNg8jjFKyWQYai/JtPHbrx7VgFLSg==} - peerDependencies: - '@solana/kit': ^6.5.0 - '@solana-program/token@0.15.0': resolution: {integrity: sha512-SeLm08EYIfT453I6lo7wTGgfMbz1s7bJ1jSHFHBFebSJHD3xF46zRgMxq3YKRlr/RM8jN0cG8SjZVu+IDvMxEA==} engines: {node: '>=24.0.0'} peerDependencies: '@solana/kit': ^7.0.0 - '@solana-program/token@0.9.0': - resolution: {integrity: sha512-vnZxndd4ED4Fc56sw93cWZ2djEeeOFxtaPS8SPf5+a+JZjKA/EnKqzbE1y04FuMhIVrLERQ8uR8H2h72eZzlsA==} + '@solana-program/token@0.16.1': + resolution: {integrity: sha512-X9dsvbh+VDq4SuCfvxn95P1DCvtBYHJOBiVmgBJMfW8l/lp8uSwEhy9IurpcdltnGi5kNIkCm4sk4YOXKAMiCw==} peerDependencies: - '@solana/kit': ^5.0 + '@solana/kit': ^8.0.0 - '@solana-program/zk-elgamal-proof@0.1.0': - resolution: {integrity: sha512-MKyeapz8P7SqkkC7h53ARFLoanb59ylVzokSMyINDH7hxY3JyiZs92/VfPa/qedhLAEHLd8jcc8sQ3pr3GyXtw==} + '@solana-program/token@0.18.0': + resolution: {integrity: sha512-YNN13I4BxBnGPGk0NzP/LLQMCmJVdunbtgqjl7/Gfp1fDXQrKXh9df8xu+2ayNdvjGJYC4c9D5vZpVetHdyJaQ==} peerDependencies: - '@solana/kit': ^5.0 + '@solana/kit': ^8.5.0 '@solana-program/zk-elgamal-proof@0.3.2': resolution: {integrity: sha512-bCiRVKtqYZpajgC2RVypZL4A0xHjQYVEsVSNMTtPJ1jjE5KOUvsXhnngGMYShK6BHv+fQP4F8QKvEVW/HOSFAg==} peerDependencies: '@solana/kit': ^7.0.0 - '@solana/accounts@5.5.1': - resolution: {integrity: sha512-TfOY9xixg5rizABuLVuZ9XI2x2tmWUC/OoN556xwfDlhBHBjKfszicYYOyD6nbFmwTGYarCmyGIdteXxTXIdhQ==} - engines: {node: '>=20.18.0'} + '@solana-program/zk-elgamal-proof@0.4.0': + resolution: {integrity: sha512-bf2Q3f25xcCNaLm/MR4lwoAguJzEW2eeLdrJb6rUjMcA63qcgyJOWl6To7Bn4e+0OyWBa+J7YP2BUhi//VPz3g==} peerDependencies: - typescript: ^5.0.0 - peerDependenciesMeta: - typescript: - optional: true + '@solana/kit': ^8.0.0 + + '@solana-program/zk-elgamal-proof@0.5.0': + resolution: {integrity: sha512-2shlu/0a/WFjERyFyhZevXG7WXRUz0kmy5DPEse3TOjH0s4fTU+Uk9kE5ijPhF85Fh662m4xT1ZZm+KBGq5y1g==} + peerDependencies: + '@solana/kit': ^8.5.0 '@solana/accounts@6.10.0': resolution: {integrity: sha512-+FxfDOrnifoPlBkF+fr8eeQdgM6xtIgAg9xKMu3WnIz60oZd4Xnry6+ff6t+ePPoZZp397FSg9ZJet68VCWm5Q==} @@ -1110,11 +1144,11 @@ packages: typescript: optional: true - '@solana/addresses@5.5.1': - resolution: {integrity: sha512-5xoah3Q9G30HQghu/9BiHLb5pzlPKRC3zydQDmE3O9H//WfayxTFppsUDCL6FjYUHqj/wzK6CWHySglc2RkpdA==} + '@solana/accounts@8.5.0': + resolution: {integrity: sha512-vwwXYCobg1oG4kFeUEsGiNORjPujI2ff3yKLp6lCa7QBIlKaD7kZ2QRI3PZFYcNrMJ6HYNwNeZXR7ixg02pWdA==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: ^5.0.0 + typescript: '>=5.4.0' peerDependenciesMeta: typescript: optional: true @@ -1137,11 +1171,11 @@ packages: typescript: optional: true - '@solana/assertions@5.5.1': - resolution: {integrity: sha512-YTCSWAlGwSlVPnWtWLm3ukz81wH4j2YaCveK+TjpvUU88hTy6fmUqxi0+hvAMAe4zKXpJyj3Az7BrLJRxbIm4Q==} + '@solana/addresses@8.5.0': + resolution: {integrity: sha512-LwTrDbDSJBng9y0vwiKqb/kSS9daspTGrSYoZPafeMWpAlpmutdD1KXPDHVTa4Xz00hcAfOJXYxRXX5VAoiOag==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: ^5.0.0 + typescript: '>=5.4.0' peerDependenciesMeta: typescript: optional: true @@ -1164,11 +1198,11 @@ packages: typescript: optional: true - '@solana/codecs-core@5.5.1': - resolution: {integrity: sha512-TgBt//bbKBct0t6/MpA8ElaOA3sa8eYVvR7LGslCZ84WiAwwjCY0lW/lOYsFHJQzwREMdUyuEyy5YWBKtdh8Rw==} + '@solana/assertions@8.5.0': + resolution: {integrity: sha512-EZDY5rJIV8Mv9xYJ7P+jvE5pihG7pmKZ6pTqbunba/4uZSQN4Klw0FX54LDDklfDvhzmAdXN0nYAnjovTGAPEg==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: ^5.0.0 + typescript: '>=5.4.0' peerDependenciesMeta: typescript: optional: true @@ -1191,11 +1225,11 @@ packages: typescript: optional: true - '@solana/codecs-data-structures@5.5.1': - resolution: {integrity: sha512-97bJWGyUY9WvBz3mX1UV3YPWGDTez6btCfD0ip3UVEXJbItVuUiOkzcO5iFDUtQT5riKT6xC+Mzl+0nO76gd0w==} + '@solana/codecs-core@8.5.0': + resolution: {integrity: sha512-ou38qNrf9XOzCWsu/I4sTzRmnrKqhblwMVvpXwXPKAAUZwkSAKQXonwgZFY68I5HK6nkfq1NLWfZFmTEIZYLiw==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: ^5.0.0 + typescript: '>=5.4.0' peerDependenciesMeta: typescript: optional: true @@ -1218,11 +1252,11 @@ packages: typescript: optional: true - '@solana/codecs-numbers@5.5.1': - resolution: {integrity: sha512-rllMIZAHqmtvC0HO/dc/21wDuWaD0B8Ryv8o+YtsICQBuiL/0U4AGwH7Pi5GNFySYk0/crSuwfIqQFtmxNSPFw==} + '@solana/codecs-data-structures@8.5.0': + resolution: {integrity: sha512-CnnNriyltkgxZAKgAJoVRsRnrtdW4KCX37BUoIsquCM+AgSvhSbxaZNz0iaHjGOX7o1Z4s6+j7nAUgad0N/w5A==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: ^5.0.0 + typescript: '>=5.4.0' peerDependenciesMeta: typescript: optional: true @@ -1245,15 +1279,12 @@ packages: typescript: optional: true - '@solana/codecs-strings@5.5.1': - resolution: {integrity: sha512-7klX4AhfHYA+uKKC/nxRGP2MntbYQCR3N6+v7bk1W/rSxYuhNmt+FN8aoThSZtWIKwN6BEyR1167ka8Co1+E7A==} + '@solana/codecs-numbers@8.5.0': + resolution: {integrity: sha512-6Vtf52rHzjf98ykejn9bNGMaQ2k1f4UMIa+BGMbBy4mIRQ5ggdI5oCAb3sZPfJcel2JQHwDlsLHCYdpqC+n6Mg==} engines: {node: '>=20.18.0'} peerDependencies: - fastestsmallesttextencoderdecoder: ^1.0.22 - typescript: ^5.0.0 + typescript: '>=5.4.0' peerDependenciesMeta: - fastestsmallesttextencoderdecoder: - optional: true typescript: optional: true @@ -1281,12 +1312,15 @@ packages: typescript: optional: true - '@solana/codecs@5.5.1': - resolution: {integrity: sha512-Vea29nJub/bXjfzEV7ZZQ/PWr1pYLZo3z0qW0LQL37uKKVzVFRQlwetd7INk3YtTD3xm9WUYr7bCvYUk3uKy2g==} + '@solana/codecs-strings@8.5.0': + resolution: {integrity: sha512-9lCSCUVkbPLb1o9PLDsaOatdVgrUqqWMrAqJvZPyyuvrC5++wPuKRIGq+5iU3lICY+AwWxrzVyiwdu4xaZVCiw==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: ^5.0.0 + fastestsmallesttextencoderdecoder: ^1.0.22 + typescript: '>=5.4.0' peerDependenciesMeta: + fastestsmallesttextencoderdecoder: + optional: true typescript: optional: true @@ -1299,12 +1333,11 @@ packages: typescript: optional: true - '@solana/errors@5.5.1': - resolution: {integrity: sha512-vFO3p+S7HoyyrcAectnXbdsMfwUzY2zYFUc2DEe5BwpiE9J1IAxPBGjOWO6hL1bbYdBrlmjNx8DXCslqS+Kcmg==} + '@solana/codecs@8.5.0': + resolution: {integrity: sha512-wALOoEuL7HAaahZnrhxCwYz10p23hku/LPNfXjlvwgjVYJL08PH3uyWDFO8e9zhcNLOaR13IREE9z8zPUhJjDQ==} engines: {node: '>=20.18.0'} - hasBin: true peerDependencies: - typescript: ^5.0.0 + typescript: '>=5.4.0' peerDependenciesMeta: typescript: optional: true @@ -1329,6 +1362,16 @@ packages: typescript: optional: true + '@solana/errors@8.5.0': + resolution: {integrity: sha512-y/XTiwAZsm2kHoEDJ3ac3NUq/0E4uCbOnBe2m5mmBXF3TGmF562tDKgN5pQ+thiRABvi7b2LqwTBCg4kAdtgRg==} + engines: {node: '>=20.18.0'} + hasBin: true + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + '@solana/eslint-config-solana@6.0.0': resolution: {integrity: sha512-tl3C2ZK8buItUQNVCwnveR2iiLALr5XZ8cevswbTDQN1SA29xQWPFRYR/JPyXLd7iOGNAo4HwvIoxNmkLjdZsQ==} deprecated: It has been replaced by @solana-config/eslint, part of the js-configs monorepo (https://github.com/solana-foundation/js-configs). Please migrate to the new package; this one will no longer receive updates. @@ -1356,6 +1399,15 @@ packages: typescript: optional: true + '@solana/fast-stable-stringify@8.5.0': + resolution: {integrity: sha512-CTIoOwJ0NScrB8KTzr/V4PJrNHrBAz1zvamM0opgDPQZGzLrBhca1e4eQcGmF6o7Dv3Ve0HdvDJx0B2uG6YxVA==} + 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'} @@ -1374,6 +1426,15 @@ packages: typescript: optional: true + '@solana/fixed-points@8.5.0': + resolution: {integrity: sha512-hkB7dUAD/oxXeNOvdMXVqfKZAvOJ1o50gBwzh8yLP1ihdSxVgssb36Vg7806C5HzmIxmTKZclJJokG0cRUXVSw==} + 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'} @@ -1392,6 +1453,15 @@ packages: typescript: optional: true + '@solana/functional@8.5.0': + resolution: {integrity: sha512-+8pgF1rVW78FfT0d+ceADFLKpSh/8/o9Ldx5tEkI6paiv0QeClL1rlU5nFs5tjoFkf+92x8PpiLEEGkm0CifOQ==} + 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'} @@ -1410,6 +1480,15 @@ packages: typescript: optional: true + '@solana/instruction-plans@8.5.0': + resolution: {integrity: sha512-cES8TzRGuJ5cdVn3hr6GskwwG68rLd8R0FqmzB9NeU/nzPnW/50nRrg36DYX1Nh+OwuU/ehg6zkNNu1Vo72lKQ==} + 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'} @@ -1428,6 +1507,15 @@ packages: typescript: optional: true + '@solana/instructions@8.5.0': + resolution: {integrity: sha512-LSMOQRicz8OalMM2DT60PtAaPjvkHPhIvmPEI8KpyWOuNRwABJBRAfn5ypcdSa69VVj4IdOY10tDWZzjN4dviA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + '@solana/keychain-core@1.3.0': resolution: {integrity: sha512-iIH3GRQdNPiLZVDU7MxiDzIQ8Fd8GKw4LxaeuifBjqWHFbAlOFSjgvvtNix1VFHy1quvCFSJZt+/0l0MRX0aoQ==} peerDependencies: @@ -1465,6 +1553,15 @@ packages: typescript: optional: true + '@solana/keys@8.5.0': + resolution: {integrity: sha512-mq6amguPYLklpAOC9A+boXQhpcHGjcn4QN40J0l1TvUkfWyFJ4HBbNb35fyWldqqDUV5ujOpaPZmmVvWJBK2Kw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + '@solana/kit-client-rpc@0.8.0': resolution: {integrity: sha512-YD9x3hZ9TKR8r5evmkfURI1e2BtIudnd6zUWXEakMLi0FhvUfdtPrWjQsHw5ngWUv9Ns9yYlI+h3DEY0xmweUg==} deprecated: 'Deprecated: use createClient from @solana/kit with payer() from @solana/kit-plugin-signer and solanaRpc() from @solana/kit-plugin-rpc instead. See the README for migration.' @@ -1511,11 +1608,11 @@ packages: typescript: optional: true - '@solana/nominal-types@5.5.1': - resolution: {integrity: sha512-I1ImR+kfrLFxN5z22UDiTWLdRZeKtU0J/pkWkO8qm/8WxveiwdIv4hooi8pb6JnlR4mSrWhq0pCIOxDYrL9GIQ==} + '@solana/kit@8.5.0': + resolution: {integrity: sha512-bMnXXADeyZFe3XyqzPhlQAIsmPYRiojaRO4JQxwGOmMwiQ5f13ZQodmsOqnt8W/n40P7r/+/pDqWuqG0TUv+yA==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: ^5.0.0 + typescript: '>=5.4.0' peerDependenciesMeta: typescript: optional: true @@ -1538,6 +1635,15 @@ packages: typescript: optional: true + '@solana/nominal-types@8.5.0': + resolution: {integrity: sha512-OfTZ+w/C59Zkp51RJ3dzn2GXUojf9p/PMmSrOpxrj+hci3bdh4e6XDGY+mvP8HGPH+m0nfKWTBCygEslfoX6bg==} + 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'} @@ -1556,11 +1662,11 @@ packages: typescript: optional: true - '@solana/options@5.5.1': - resolution: {integrity: sha512-eo971c9iLNLmk+yOFyo7yKIJzJ/zou6uKpy6mBuyb/thKtS/haiKIc3VLhyTXty3OH2PW8yOlORJnv4DexJB8A==} + '@solana/offchain-messages@8.5.0': + resolution: {integrity: sha512-C7qBBD1Gfbdv99uoQnuc8XZYwttTQJOYEG2v6z7q3mAL03PN7zdItAlBa+M2tpeRKjTJObRYnUUJDfiIyyGD/Q==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: ^5.0.0 + typescript: '>=5.4.0' peerDependenciesMeta: typescript: optional: true @@ -1574,6 +1680,15 @@ packages: typescript: optional: true + '@solana/options@8.5.0': + resolution: {integrity: sha512-Ron9FrWDkwxlmuI6D+NmrZZRngC1MUncglgyN77ThAoxDE1gGMOB88mQvEILeeqONeTA1rDg1uBvbewQcILp+w==} + 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'} @@ -1583,6 +1698,15 @@ packages: typescript: optional: true + '@solana/plugin-core@8.5.0': + resolution: {integrity: sha512-1zmh+UC47yxsZHleDpH4AEVkm9yXIATkWm8v33DJuXaqX3TQXMXuxP39cXAyObIQEpCG8DK8lyAeFTUrIFcDmA==} + 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'} @@ -1601,6 +1725,15 @@ packages: typescript: optional: true + '@solana/plugin-interfaces@8.5.0': + resolution: {integrity: sha512-+s/+cCuzk23/a1ViTIugvXFYHN0txxmvqfuL4qx81NlmGawqEYws6xD+L02wNzJ5rbJeAaBhw2pUFStMfG4vYg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + '@solana/prettier-config-solana@0.0.6': resolution: {integrity: sha512-/s55hDoAyh5QyltQh/jjNK3AgACEq885+DnC6lYhrmYZiV6I0iHITWYnKd8d23KRKs/RBjlaQH54MiafeoI9hw==} deprecated: This package is deprecated. It has been replaced by @solana-config/prettier, part of the @solana-foundation/js-configs monorepo (https://github.com/solana-foundation/js-configs). Please migrate to the new package; this one will no longer receive updates. @@ -1625,6 +1758,15 @@ packages: typescript: optional: true + '@solana/program-client-core@8.5.0': + resolution: {integrity: sha512-HJcnbuvQRcWOV3nTUjzgmQRIs0Of1973UU8uOvSEEW7rxycQwNxJ7fVgxQ5sYOCbT+7rlqqTkDeczvB7I4OwoA==} + 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'} @@ -1634,6 +1776,15 @@ packages: typescript: optional: true + '@solana/programs@8.5.0': + resolution: {integrity: sha512-8PC2E/d5rwCRw1tFwQlpG65YDN56bYmPiBl99QqCP2RzhNdFJ/52xgFumL2G0uLfD3xsuFaWuOIGNxkyfXYm/Q==} + 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'} @@ -1652,6 +1803,15 @@ packages: typescript: optional: true + '@solana/promises@8.5.0': + resolution: {integrity: sha512-qWJbU6RGuZVrtvsGZ+2F46jccaIZDX4czYRRhS3m38cCdE+wKMbqGvWND50xP7D9egOxYKHMqJAJbLQH4gspvQ==} + 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'} @@ -1670,6 +1830,15 @@ packages: typescript: optional: true + '@solana/rpc-api@8.5.0': + resolution: {integrity: sha512-qlRZ2yC8WEWNg3VX8UEqlZOitKZaeE6KWbn3A/ybtJAYz+mvr3RMDhnQ89RDqIuxPuAFZNV21BRJv3yB9xR44Q==} + 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'} @@ -1688,11 +1857,11 @@ packages: typescript: optional: true - '@solana/rpc-spec-types@5.5.1': - resolution: {integrity: sha512-6OFKtRpIEJQs8Jb2C4OO8KyP2h2Hy1MFhatMAoXA+0Ik8S3H+CicIuMZvGZ91mIu/tXicuOOsNNLu3HAkrakrw==} + '@solana/rpc-parsed-types@8.5.0': + resolution: {integrity: sha512-ktygZ019trgAyjr8y1GN1x4x6wJYw2Ola6UogAfJT5LoNs6kV3k84yCNAlGv34xRPqCVxlWo4nsIWJf8yWQQ2w==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: ^5.0.0 + typescript: '>=5.4.0' peerDependenciesMeta: typescript: optional: true @@ -1715,11 +1884,11 @@ packages: typescript: optional: true - '@solana/rpc-spec@5.5.1': - resolution: {integrity: sha512-m3LX2bChm3E3by4mQrH4YwCAFY57QBzuUSWqlUw7ChuZ+oLLOq7b2czi4i6L4Vna67j3eCmB3e+4tqy1j5wy7Q==} + '@solana/rpc-spec-types@8.5.0': + resolution: {integrity: sha512-YUTMKWWlHCGBmA1wxhIilbxJlad5vEsvc8dDO9VWr7GVkQUlipEU79iGaKk4xQ6Oo1mZWxpGz5mAJUqGraTK4A==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: ^5.0.0 + typescript: '>=5.4.0' peerDependenciesMeta: typescript: optional: true @@ -1742,6 +1911,15 @@ packages: typescript: optional: true + '@solana/rpc-spec@8.5.0': + resolution: {integrity: sha512-0oET5yc880zFGqBMJE2UB7sxW8sIs4hmsP4bmkR2y4ipm1aScC5U+Rd8GaIrupBOVOFj+RXIorC7kQycN/9nhw==} + 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'} @@ -1751,6 +1929,15 @@ packages: typescript: optional: true + '@solana/rpc-subscriptions-api@8.5.0': + resolution: {integrity: sha512-PJaAyqZkpG8vuzdxmdWMwp1JS5pyZ6PuL8OMhx6nCt3phkseqIs1NmAf8pQc/RZjIV3hJMMVCwSDG1DE8DY64w==} + 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'} @@ -1760,6 +1947,15 @@ packages: typescript: optional: true + '@solana/rpc-subscriptions-channel-websocket@8.5.0': + resolution: {integrity: sha512-sRYYwBFg31z77zfKpJBcAO9MaUWa+bO1PlBcDiToa4luXGuR3dC8TSpi1Yip4T4NCONNzK3yhyeI6sHhGHc8Qw==} + 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'} @@ -1778,6 +1974,15 @@ packages: typescript: optional: true + '@solana/rpc-subscriptions-spec@8.5.0': + resolution: {integrity: sha512-YdCPLHOcQWz8JhMaT/E+YC56nFDJ6D+XOTr6qRWHGe/1PIYGQDVvaFzI7+tF0b6tuv49GoMbpGdkiTX2v6KeUw==} + 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'} @@ -1787,6 +1992,15 @@ packages: typescript: optional: true + '@solana/rpc-subscriptions@8.5.0': + resolution: {integrity: sha512-8hdWSDKKtMK3kRrR8TExwFo/bWHxVTu4zJ/JkePTQgNtm95kX25/hy+9JHKRtSsNUfXXYM60sQVE18cGgMU7dA==} + 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'} @@ -1805,6 +2019,15 @@ packages: typescript: optional: true + '@solana/rpc-transformers@8.5.0': + resolution: {integrity: sha512-JYq+EyfzJ1ksZubU9VHynQY1Z3k1tosdxG6KE4Cua/rFuXPosSn7o5h9FLLbSB5cTVcnj0lGNrBaVYW4AVK4iA==} + 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'} @@ -1814,11 +2037,11 @@ packages: typescript: optional: true - '@solana/rpc-types@5.5.1': - resolution: {integrity: sha512-bibTFQ7PbHJJjGJPmfYC2I+/5CRFS4O2p9WwbFraX1Keeel+nRrt/NBXIy8veP5AEn2sVJIyJPpWBRpCx1oATA==} + '@solana/rpc-transport-http@8.5.0': + resolution: {integrity: sha512-xfIFZa+oxXLgA6BXaE2bXjiy2yZM1qO1URzzF0lmTekJM/okS8EZAQwEicWpYkvfdHJZ2x/oagD3AOSBBCWrsw==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: ^5.0.0 + typescript: '>=5.4.0' peerDependenciesMeta: typescript: optional: true @@ -1841,6 +2064,15 @@ packages: typescript: optional: true + '@solana/rpc-types@8.5.0': + resolution: {integrity: sha512-L050pZqQ8gaFABF26NAYoatyZZeJo52AKvQQ3i58LRtUc6wcrpCF+4x4U/EDER2YVAc6Qx1xWvGnAomGhI6vzw==} + 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'} @@ -1850,6 +2082,15 @@ packages: typescript: optional: true + '@solana/rpc@8.5.0': + resolution: {integrity: sha512-7CQFNOMhXrY/LT0qdsi3h0chy4A/Ao93pyBLqFQqxzlub0st8dC5wl+MDXhkxaBos/DZOu1V4EleWv6qbLMlow==} + 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'} @@ -1868,6 +2109,15 @@ packages: typescript: optional: true + '@solana/signers@8.5.0': + resolution: {integrity: sha512-F9VvFsG9Av+Sbs4mQpuVlszb6msujxnqKQqa4TsRT24GOqKOFr4Xvs7HqgVJV/BPIDnz7u0omUhUILesHJDfkQ==} + 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'} @@ -1886,22 +2136,31 @@ packages: typescript: optional: true + '@solana/subscribable@8.5.0': + resolution: {integrity: sha512-v1/hL/l4kubwYVuaMNmtQcmTgDuKG6e9Hjv9fCxkYCdDIUERgmm9DX/So1386+6rkQBVRC7wTSH86Jq+RIqNGQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + '@solana/subscriptions@0.5.0': resolution: {integrity: sha512-N7mA5U3rqak9sSbAfB/iYGlgbuIjwGUHfNDlQRGqgXIACnxPcvA3e6f6cHkD0GITstRNxX+rg9uyE1FGGlw/Jw==} peerDependencies: '@solana/kit': ^7.0.0 - '@solana/sysvars@5.5.1': - resolution: {integrity: sha512-k3Quq87Mm+geGUu1GWv6knPk0ALsfY6EKSJGw9xUJDHzY/RkYSBnh0RiOrUhtFm2TDNjOailg8/m0VHmi3reFA==} + '@solana/sysvars@6.10.0': + resolution: {integrity: sha512-cG13p1+onxz+20iWjwWQr1Z1jQwPm0fnjoW75fqZq7p4rVCie3L2sXvaJsYPjWKrUvpOzOIEHnqZGkG05rCpjg==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: ^5.0.0 + typescript: '>=5.4.0' peerDependenciesMeta: typescript: optional: true - '@solana/sysvars@6.10.0': - resolution: {integrity: sha512-cG13p1+onxz+20iWjwWQr1Z1jQwPm0fnjoW75fqZq7p4rVCie3L2sXvaJsYPjWKrUvpOzOIEHnqZGkG05rCpjg==} + '@solana/sysvars@7.1.1': + resolution: {integrity: sha512-EscE/HKbBRKedG6AtQ0t9LOX87bw409viferac5YSuvuDxtZvbMpCCJs89uEQPVpgvHtjMJhfsjEwMK97uG9pA==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1909,8 +2168,8 @@ packages: typescript: optional: true - '@solana/sysvars@7.1.1': - resolution: {integrity: sha512-EscE/HKbBRKedG6AtQ0t9LOX87bw409viferac5YSuvuDxtZvbMpCCJs89uEQPVpgvHtjMJhfsjEwMK97uG9pA==} + '@solana/sysvars@8.5.0': + resolution: {integrity: sha512-vidKFEOAujEVizDUHFCmmIpHsS3Zu/fXJKcDUtbUn+bwD9Z1fRiper8rZW3Qdtgu1GmrH3O8MoyL2Nrp7k6QNw==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.4.0' @@ -1927,6 +2186,24 @@ packages: typescript: optional: true + '@solana/transaction-confirmation@8.5.0': + resolution: {integrity: sha512-dUVHhyaJ9tt535ZJfgPAdKo6zycCAn1mqKKP/FYvCz/4FiAKnyvqj8rxd66yvvuJVhkpjbcPDDagm/P8JEYUug==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/transaction-introspection@8.5.0': + resolution: {integrity: sha512-VPYVLcpieu5YwwC1wmh3zZ/KHWmqJWPS7iMPVpf90L79/1Dvkg+YYQHnVeN4VQdb7VFnfpTqUnSQpfERDk0Sag==} + 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'} @@ -1945,6 +2222,15 @@ packages: typescript: optional: true + '@solana/transaction-messages@8.5.0': + resolution: {integrity: sha512-8SHxirU5K0kFmOwwD6XTGI5LWP/bLvLBDbemT4xDOaL+6xkLzlTMtzlgKb/Td5UtqyYOoew0FBVLJzJx/QApOw==} + 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'} @@ -1963,6 +2249,15 @@ packages: typescript: optional: true + '@solana/transactions@8.5.0': + resolution: {integrity: sha512-IGRWI38rq5b94gy93wn/gVSQBuwNPSUv3GnWkd6R6Tc7jLbfRlYbYHJNHH5o28Fmlr+nlEn4bgu3BiqMWxuLmg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + '@standard-schema/spec@1.1.0': resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} @@ -2239,59 +2534,59 @@ packages: cpu: [x64] os: [win32] - '@vitest/coverage-v8@4.1.11': - resolution: {integrity: sha512-8MVGEFnJIcdGjcbfKmeq8z0pZHH0JlVtoVZH9Q/qwUp6wyFnEJUBMrw9DCaj+ra3vShGmhavjalMIhPNxZAUcw==} + '@vitest/coverage-v8@4.1.12': + resolution: {integrity: sha512-6S7/iVknKglLAxMFxQGNppBI0iqJS2NgM6FBxavitj7KaDq/vywOWGf6dGu7F2L1Qy0G6S3uTp7aGshHrzK8JA==} peerDependencies: - '@vitest/browser': 4.1.11 - vitest: 4.1.11 + '@vitest/browser': 4.1.12 + vitest: 4.1.12 peerDependenciesMeta: '@vitest/browser': optional: true - '@vitest/expect@4.1.11': - resolution: {integrity: sha512-VX2x5vNJXET47KAFzwERI+KRMtTTCSWTfSMKsW7JsUsXV4psq++e3DvZpuTDOpHcxytiDs6p2nhVb2tVDiiUYw==} + '@vitest/expect@4.1.12': + resolution: {integrity: sha512-vFlTt+YEu9WBpNjdGayNmlMVzrWPi1+sv853/7t2FU7hpO5gAFBKHzQmkCq5Xjpr+evegF2994LQT3hF3mRlqQ==} - '@vitest/mocker@4.1.11': - resolution: {integrity: sha512-2XJVD55d1o5AZous5CCGKS74g/riOj9odEt2bQpCVZeblHyHdnMeFl4jl0XjU21stf4mbjUkew2eXQZt65g5CQ==} + '@vitest/mocker@4.1.12': + resolution: {integrity: sha512-fKShNpKZzupWZuY0z7egydvL0sqW4INEZBEExMBMAa6izlENEVHwoXgdaTCaBZ5fwlr4xf2o1wXC83n9RpO+NA==} peerDependencies: msw: ^2.4.9 - vite: 8.0.16 + vite: '>=8.1.6 <9' peerDependenciesMeta: msw: optional: true vite: optional: true - '@vitest/pretty-format@4.1.11': - resolution: {integrity: sha512-yiZzPbGTS9Sr/JpFl8zHrcIkAofNbFV6k21vIgQN/cY/oxZeXhJv5sc/MBJ5jFKWmWs+oJHw0UXLZjmf931+Vw==} + '@vitest/pretty-format@4.1.12': + resolution: {integrity: sha512-XW9O8+Mxx4VpCtkYdMJLZQQwsVryP9wk7cPKDxtXFfwSak6yRh5+2fep/Y0XF/ElBvJHq8bcYdi6aeuai0opZA==} - '@vitest/runner@4.1.11': - resolution: {integrity: sha512-LztvUgdwMNJMIkj3hQnnxiC2Xy1zNxq928W/xhjCLaNCzqTZOudjwbQf6v9IntZGPw132i2Lq2rgTRZHD3JHNw==} + '@vitest/runner@4.1.12': + resolution: {integrity: sha512-NKlVKCr5QnCe8jijdMnmkpHHU+WTqiLFR6G0pHji9uRjXK9xJl1k1nTw6F3pOOj2PDcsDt2GKQMI7wIsaT491w==} - '@vitest/snapshot@4.1.11': - resolution: {integrity: sha512-pN7ikn1ON7h8ee4gIAp4AzyK+zBtJPzVbqOgu5LCEh4VaJVbPQcgYQYJIMGQPXVeJJq1fnfazis7a5pFNPahog==} + '@vitest/snapshot@4.1.12': + resolution: {integrity: sha512-ko1y1Qgb/slzQ9mr+b89Cuqud8WG1TKtsPD8r7ZUBdvVOGt85Af2HwCqHujrhwJq95hs/9RM7fcAPg57o1vlzw==} - '@vitest/spy@4.1.11': - resolution: {integrity: sha512-apNa/prQy2qCeywhnixOHPRCgGNhvg7T4Dapfl1GahLp/R+uhBm5cPyFoNVyqsNd2h1nJxL6BqqdIjiABL60YA==} + '@vitest/spy@4.1.12': + resolution: {integrity: sha512-RGq9x4JNGNTZHEJxvN0oSiJjeSCExm0n2gZKKJZHY9cX5AVA6M7VJILBT3ZJ/tJ/0J9uWT7fETV9/btoi//vSg==} - '@vitest/utils@4.1.11': - resolution: {integrity: sha512-zTCVGpyFsGWBhllOyKlTw/vnr6D9qxsfSDyfbyZmTyjHw5N/VuvzHpHoQjm2ZJzn4RJgx5w4r7V0er69CmLgPQ==} + '@vitest/utils@4.1.12': + resolution: {integrity: sha512-Q3awXrwOfEV+qc3WmO5ONyE0yO7Q1gQ9/oyHxGLZ/pl7N3NO/ZztqQwKLuwMkV+CA1JYSIeO3gkHnRDIo4AVaA==} - '@x402/core@file:.x402-vendor/x402-core-2.26.0.tgz': - resolution: {integrity: sha512-ZbdBfsnze0M4GOx1vnNsPp37qz6UtzLtLVEmEmlJJeiUueVPnm5nCiGd8j8pJWP+UH004IpMmHo/j63YKKlYuQ==, tarball: file:.x402-vendor/x402-core-2.26.0.tgz} - version: 2.26.0 + '@x402/core@file:.x402-vendor/x402-core-2.28.0.tgz': + resolution: {integrity: sha512-JTAUxpX4/tP+RisHPqUgAAPcCK+Jbz5unISBD7XJhR060b0kF9HWhpk0Da0341SztzX5x6lMpqMwkjvsnQEg5A==, tarball: file:.x402-vendor/x402-core-2.28.0.tgz} + version: 2.28.0 - '@x402/svm@file:.x402-vendor/x402-svm-2.26.0.tgz': - resolution: {integrity: sha512-xpe8i2/uwF51kT0DHJZfnZVNZ1+G3wDuYXTaCJkvLUBnlQ52k7hBSHFGN/HEgXG0jWesnxaWPPgjwFuGPUc4+A==, tarball: file:.x402-vendor/x402-svm-2.26.0.tgz} - version: 2.26.0 + '@x402/svm@file:.x402-vendor/x402-svm-2.28.0.tgz': + resolution: {integrity: sha512-cuY8ppSxs5aWYO1SqsHT7P6/zfZoR/MT70tTYADGsBppG3Vn/aT4e18lkcqoGdB5y2Rg/iUQrX+CiMyhzSRyJg==, tarball: file:.x402-vendor/x402-svm-2.28.0.tgz} + version: 2.28.0 peerDependencies: - '@solana/kit': '>=5.1.0' + '@solana/kit': '>=8.0.0' abitype@1.2.3: resolution: {integrity: sha512-Ofer5QUnuUdTFsBRwARMoWKOH1ND5ehwYhJ3OJ/BQO+StkwQjHw0XyVh4vDttzHB7QOFhPHa/o413PJ82gU/Tg==} peerDependencies: typescript: '>=5.0.4' - zod: ^3.22.0 || ^4.0.0 + zod: '>=4.6.6 <5' peerDependenciesMeta: typescript: optional: true @@ -2369,7 +2664,7 @@ packages: resolution: {integrity: sha512-gRpauEU2KRrCox5Z296aeVHR4jQ98BCnu0IO332D/xpHNOsIH/bgSRk9k6GbKIbBw8vFeN6ctuu6tV8WOyVfYQ==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} peerDependencies: - '@babel/core': ^7.11.0 || ^8.0.0-0 + '@babel/core': '>=7.29.6 <8' babel-plugin-istanbul@7.0.1: resolution: {integrity: sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA==} @@ -2382,13 +2677,13 @@ packages: babel-preset-current-node-syntax@1.2.0: resolution: {integrity: sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==} peerDependencies: - '@babel/core': ^7.0.0 || ^8.0.0-0 + '@babel/core': '>=7.29.6 <8' babel-preset-jest@30.3.0: resolution: {integrity: sha512-6ZcUbWHC+dMz2vfzdNwi87Z1gQsLNK2uLuK1Q89R11xdvejcivlYYwDlEv0FHX3VwEXpbBQ9uufB/MUNpZGfhQ==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} peerDependencies: - '@babel/core': ^7.11.0 || ^8.0.0-beta.1 + '@babel/core': '>=7.29.6 <8' balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -2402,8 +2697,8 @@ packages: engines: {node: '>=6.0.0'} hasBin: true - body-parser@2.3.0: - resolution: {integrity: sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==} + body-parser@2.4.0: + resolution: {integrity: sha512-Ifk1KcLrxaGt1occQagQNFNNOqRt1LFuehEnHHzB8Z6cRgIxRU1TBaiIsUiCdA+gy5PL7Y1IX31DNKkRmxtXjQ==} engines: {node: '>=18'} brace-expansion@1.1.21: @@ -2439,7 +2734,7 @@ packages: resolution: {integrity: sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} peerDependencies: - esbuild: '>=0.18' + esbuild: '>=0.28.1 <0.29' bytes@3.1.2: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} @@ -2517,10 +2812,6 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - commander@14.0.2: - resolution: {integrity: sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==} - engines: {node: '>=20'} - commander@15.0.0: resolution: {integrity: sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==} engines: {node: '>=22.12.0'} @@ -2547,8 +2838,8 @@ packages: resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} engines: {node: '>= 0.6'} - content-type@2.0.0: - resolution: {integrity: sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==} + content-type@2.1.0: + resolution: {integrity: sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==} engines: {node: '>=18'} convert-source-map@2.0.0: @@ -2655,8 +2946,8 @@ packages: resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} engines: {node: '>= 0.4'} - esbuild@0.27.4: - resolution: {integrity: sha512-Rq4vbHnYkK5fws5NF7MYTU68FPRE1ajX7heQ/8QXXWqNgqqJ/GkmmyxIzUnf2Sr/bakf8l54716CcMGHYhMrrQ==} + esbuild@0.28.2: + resolution: {integrity: sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==} engines: {node: '>=18'} hasBin: true @@ -2987,8 +3278,8 @@ packages: resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} engines: {node: '>=10.17.0'} - iconv-lite@0.7.2: - resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} + iconv-lite@0.7.3: + resolution: {integrity: sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==} engines: {node: '>=0.10.0'} ignore@5.3.2: @@ -3267,78 +3558,78 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} - lightningcss-android-arm64@1.32.0: - resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} + lightningcss-android-arm64@1.33.0: + resolution: {integrity: sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [android] - lightningcss-darwin-arm64@1.32.0: - resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} + lightningcss-darwin-arm64@1.33.0: + resolution: {integrity: sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [darwin] - lightningcss-darwin-x64@1.32.0: - resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} + lightningcss-darwin-x64@1.33.0: + resolution: {integrity: sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [darwin] - lightningcss-freebsd-x64@1.32.0: - resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} + lightningcss-freebsd-x64@1.33.0: + resolution: {integrity: sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [freebsd] - lightningcss-linux-arm-gnueabihf@1.32.0: - resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} + lightningcss-linux-arm-gnueabihf@1.33.0: + resolution: {integrity: sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==} engines: {node: '>= 12.0.0'} cpu: [arm] os: [linux] - lightningcss-linux-arm64-gnu@1.32.0: - resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} + lightningcss-linux-arm64-gnu@1.33.0: + resolution: {integrity: sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] libc: [glibc] - lightningcss-linux-arm64-musl@1.32.0: - resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} + lightningcss-linux-arm64-musl@1.33.0: + resolution: {integrity: sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] libc: [musl] - lightningcss-linux-x64-gnu@1.32.0: - resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} + lightningcss-linux-x64-gnu@1.33.0: + resolution: {integrity: sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] libc: [glibc] - lightningcss-linux-x64-musl@1.32.0: - resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} + lightningcss-linux-x64-musl@1.33.0: + resolution: {integrity: sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] libc: [musl] - lightningcss-win32-arm64-msvc@1.32.0: - resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} + lightningcss-win32-arm64-msvc@1.33.0: + resolution: {integrity: sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [win32] - lightningcss-win32-x64-msvc@1.32.0: - resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} + lightningcss-win32-x64-msvc@1.33.0: + resolution: {integrity: sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [win32] - lightningcss@1.32.0: - resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} + lightningcss@1.33.0: + resolution: {integrity: sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==} engines: {node: '>= 12.0.0'} lilconfig@3.1.3: @@ -3388,8 +3679,8 @@ packages: makeerror@1.0.12: resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} - markdown-it@14.3.1: - resolution: {integrity: sha512-4Ej49aYTDFIQ+uBkfX8GBvJGccoARxxPep+7aWTs55ozbjQJpW9M26Fe53vnGgvLeVzva/amzjQQaQu9w0vMhA==} + markdown-it@14.3.3: + resolution: {integrity: sha512-L//tDAkjTjJCU6pBUSBTgs3Kg4InVaZuUZog/b6V12UKhcDQ7S78877ibbCanRExwPuYP1CZD7Gd2dxSy1GXRg==} hasBin: true math-intrinsics@1.1.0: @@ -3733,8 +4024,8 @@ packages: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - rolldown@1.0.3: - resolution: {integrity: sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==} + rolldown@1.2.15: + resolution: {integrity: sha512-6odND+fel5zVw3I4Yc2e69gvguDnX0CAAGiNDZSq4ik5WUcaLrkD2GLuog0XcODbor31hZ5ayEMgVDno+KPV5g==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true @@ -4058,6 +4349,9 @@ packages: undici-types@7.18.2: resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} + undici-types@8.12.3: + resolution: {integrity: sha512-EXE4ydL3S76dFb27UFjNVZHTyv/TLdATj/KUe29ptdcg6qXL48J2tZ3126E5kICj5jn781OR+XlVH1N6Mz8jbA==} + undici-types@8.5.0: resolution: {integrity: sha512-+FxhD+5RUdCZHlVPt+pd0DaYYHBPsgoHovxhMnFq9R1SOejHGE4ma0swzuRoKhOisEzsjFWdFedyD0JQmftrHg==} @@ -4097,14 +4391,14 @@ packages: typescript: optional: true - vite@8.0.16: - resolution: {integrity: sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==} + vite@8.3.5: + resolution: {integrity: sha512-z1YpjieJ9g0ebTmQpLBv/oq9E3F9EIlOe+7LahW8SrE3LTiG3udBRUXQOlYXP9b+IC2q2phHeVxj9xGlw34OEQ==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: '@types/node': ^20.19.0 || >=22.12.0 - '@vitejs/devtools': ^0.1.18 - esbuild: ^0.27.0 || ^0.28.0 + '@vitejs/devtools': ^0.7.1 || ^0.8.0 + esbuild: '>=0.28.1 <0.29' jiti: '>=1.21.0' less: ^4.0.0 sass: ^1.70.0 @@ -4140,23 +4434,23 @@ packages: yaml: optional: true - vitest@4.1.11: - resolution: {integrity: sha512-fhACrNXUidIbGSBr5FlbuBkO7VWC1ZyLl0DO4CU2DrQoAPxX84Ysxs+HeGQpii5lZWV1Q4gBZTTu49mF+A6Edw==} + vitest@4.1.12: + resolution: {integrity: sha512-5eWdz2yb3ajxWF3C8C4TjkXl7FGm3n2E/VlazALrQHzK7nYMSGFnCZto0bbPNl77AwkOZVLk0YnBAejUu0NiWA==} engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@opentelemetry/api': ^1.9.0 '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/browser-playwright': 4.1.11 - '@vitest/browser-preview': 4.1.11 - '@vitest/browser-webdriverio': 4.1.11 - '@vitest/coverage-istanbul': 4.1.11 - '@vitest/coverage-v8': 4.1.11 - '@vitest/ui': 4.1.11 + '@vitest/browser-playwright': 4.1.12 + '@vitest/browser-preview': 4.1.12 + '@vitest/browser-webdriverio': ^4.1.11 + '@vitest/coverage-istanbul': 4.1.12 + '@vitest/coverage-v8': 4.1.12 + '@vitest/ui': 4.1.12 happy-dom: '*' jsdom: '*' - vite: 8.0.16 + vite: '>=8.1.6 <9' peerDependenciesMeta: '@edge-runtime/vm': optional: true @@ -4253,37 +4547,34 @@ packages: resolution: {integrity: sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==} engines: {node: '>=18.0.0'} peerDependencies: - zod: ^3.25.0 || ^4.0.0 - - zod@3.25.76: - resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + zod: '>=4.6.6 <5' - zod@4.4.3: - resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} + zod@4.6.7: + resolution: {integrity: sha512-g8W2D2kU6a8untc053fX1uVBKzM7yqAxW/3zwk83+6RyF2+SKOuV+c0wBDhUwzV1PaGapmZH+rmcUzPf+3CGwg==} snapshots: '@adraffy/ens-normalize@1.11.1': {} - '@babel/code-frame@7.29.0': + '@babel/code-frame@7.29.7': dependencies: - '@babel/helper-validator-identifier': 7.28.5 + '@babel/helper-validator-identifier': 7.29.7 js-tokens: 4.0.0 picocolors: 1.1.1 - '@babel/compat-data@7.29.0': {} + '@babel/compat-data@7.29.7': {} - '@babel/core@7.29.0': + '@babel/core@7.29.7': dependencies: - '@babel/code-frame': 7.29.0 - '@babel/generator': 7.29.1 - '@babel/helper-compilation-targets': 7.28.6 - '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) - '@babel/helpers': 7.29.2 - '@babel/parser': 7.29.2 - '@babel/template': 7.28.6 - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.8 + '@babel/helper-compilation-targets': 7.29.7 + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) + '@babel/helpers': 7.29.10 + '@babel/parser': 7.29.11 + '@babel/template': 7.29.7 + '@babel/traverse': 7.29.10 + '@babel/types': 7.29.11 '@jridgewell/remapping': 2.3.5 convert-source-map: 2.0.0 debug: 4.4.3 @@ -4293,37 +4584,37 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/generator@7.29.1': + '@babel/generator@7.29.8': dependencies: - '@babel/parser': 7.29.2 - '@babel/types': 7.29.0 + '@babel/parser': 7.29.11 + '@babel/types': 7.29.11 '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 jsesc: 3.1.0 - '@babel/helper-compilation-targets@7.28.6': + '@babel/helper-compilation-targets@7.29.7': dependencies: - '@babel/compat-data': 7.29.0 - '@babel/helper-validator-option': 7.27.1 + '@babel/compat-data': 7.29.7 + '@babel/helper-validator-option': 7.29.7 browserslist: 4.28.7 lru-cache: 5.1.1 semver: 6.3.1 - '@babel/helper-globals@7.28.0': {} + '@babel/helper-globals@7.29.7': {} - '@babel/helper-module-imports@7.28.6': + '@babel/helper-module-imports@7.29.7': dependencies: - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 + '@babel/traverse': 7.29.10 + '@babel/types': 7.29.11 transitivePeerDependencies: - supports-color - '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)': + '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-module-imports': 7.28.6 - '@babel/helper-validator-identifier': 7.28.5 - '@babel/traverse': 7.29.0 + '@babel/core': 7.29.7 + '@babel/helper-module-imports': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + '@babel/traverse': 7.29.10 transitivePeerDependencies: - supports-color @@ -4331,118 +4622,126 @@ snapshots: '@babel/helper-string-parser@7.27.1': {} + '@babel/helper-string-parser@7.29.11': {} + '@babel/helper-validator-identifier@7.28.5': {} - '@babel/helper-validator-option@7.27.1': {} + '@babel/helper-validator-identifier@7.29.7': {} - '@babel/helpers@7.29.2': + '@babel/helper-validator-option@7.29.7': {} + + '@babel/helpers@7.29.10': dependencies: - '@babel/template': 7.28.6 - '@babel/types': 7.29.0 + '@babel/template': 7.29.7 + '@babel/types': 7.29.11 + + '@babel/parser@7.29.11': + dependencies: + '@babel/types': 7.29.11 '@babel/parser@7.29.2': dependencies: '@babel/types': 7.29.0 - '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.29.0)': + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.29.0)': + '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.29.0)': + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.29.0)': + '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-import-attributes@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-syntax-import-attributes@7.28.6(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.29.0)': + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.29.0)': + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.29.0)': + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.29.0)': + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.29.0)': + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.29.0)': + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.29.0)': + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.29.0)': + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.29.0)': + '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.29.0)': + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-typescript@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-syntax-typescript@7.28.6(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.28.6 - '@babel/template@7.28.6': + '@babel/template@7.29.7': dependencies: - '@babel/code-frame': 7.29.0 - '@babel/parser': 7.29.2 - '@babel/types': 7.29.0 + '@babel/code-frame': 7.29.7 + '@babel/parser': 7.29.11 + '@babel/types': 7.29.11 - '@babel/traverse@7.29.0': + '@babel/traverse@7.29.10': dependencies: - '@babel/code-frame': 7.29.0 - '@babel/generator': 7.29.1 - '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.29.2 - '@babel/template': 7.28.6 - '@babel/types': 7.29.0 + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.8 + '@babel/helper-globals': 7.29.7 + '@babel/parser': 7.29.11 + '@babel/template': 7.29.7 + '@babel/types': 7.29.11 debug: 4.4.3 transitivePeerDependencies: - supports-color @@ -4452,6 +4751,11 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 + '@babel/types@7.29.11': + dependencies: + '@babel/helper-string-parser': 7.29.11 + '@babel/helper-validator-identifier': 7.29.7 + '@bcoe/v8-coverage@0.2.3': {} '@bcoe/v8-coverage@1.0.2': {} @@ -4474,82 +4778,82 @@ snapshots: tslib: 2.8.1 optional: true - '@esbuild/aix-ppc64@0.27.4': + '@esbuild/aix-ppc64@0.28.2': optional: true - '@esbuild/android-arm64@0.27.4': + '@esbuild/android-arm64@0.28.2': optional: true - '@esbuild/android-arm@0.27.4': + '@esbuild/android-arm@0.28.2': optional: true - '@esbuild/android-x64@0.27.4': + '@esbuild/android-x64@0.28.2': optional: true - '@esbuild/darwin-arm64@0.27.4': + '@esbuild/darwin-arm64@0.28.2': optional: true - '@esbuild/darwin-x64@0.27.4': + '@esbuild/darwin-x64@0.28.2': optional: true - '@esbuild/freebsd-arm64@0.27.4': + '@esbuild/freebsd-arm64@0.28.2': optional: true - '@esbuild/freebsd-x64@0.27.4': + '@esbuild/freebsd-x64@0.28.2': optional: true - '@esbuild/linux-arm64@0.27.4': + '@esbuild/linux-arm64@0.28.2': optional: true - '@esbuild/linux-arm@0.27.4': + '@esbuild/linux-arm@0.28.2': optional: true - '@esbuild/linux-ia32@0.27.4': + '@esbuild/linux-ia32@0.28.2': optional: true - '@esbuild/linux-loong64@0.27.4': + '@esbuild/linux-loong64@0.28.2': optional: true - '@esbuild/linux-mips64el@0.27.4': + '@esbuild/linux-mips64el@0.28.2': optional: true - '@esbuild/linux-ppc64@0.27.4': + '@esbuild/linux-ppc64@0.28.2': optional: true - '@esbuild/linux-riscv64@0.27.4': + '@esbuild/linux-riscv64@0.28.2': optional: true - '@esbuild/linux-s390x@0.27.4': + '@esbuild/linux-s390x@0.28.2': optional: true - '@esbuild/linux-x64@0.27.4': + '@esbuild/linux-x64@0.28.2': optional: true - '@esbuild/netbsd-arm64@0.27.4': + '@esbuild/netbsd-arm64@0.28.2': optional: true - '@esbuild/netbsd-x64@0.27.4': + '@esbuild/netbsd-x64@0.28.2': optional: true - '@esbuild/openbsd-arm64@0.27.4': + '@esbuild/openbsd-arm64@0.28.2': optional: true - '@esbuild/openbsd-x64@0.27.4': + '@esbuild/openbsd-x64@0.28.2': optional: true - '@esbuild/openharmony-arm64@0.27.4': + '@esbuild/openharmony-arm64@0.28.2': optional: true - '@esbuild/sunos-x64@0.27.4': + '@esbuild/sunos-x64@0.28.2': optional: true - '@esbuild/win32-arm64@0.27.4': + '@esbuild/win32-arm64@0.28.2': optional: true - '@esbuild/win32-ia32@0.27.4': + '@esbuild/win32-ia32@0.28.2': optional: true - '@esbuild/win32-x64@0.27.4': + '@esbuild/win32-x64@0.28.2': optional: true '@eslint-community/eslint-utils@4.9.1(eslint@9.39.4)': @@ -4791,7 +5095,7 @@ snapshots: '@jest/transform@30.3.0': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.7 '@jest/types': 30.3.0 '@jridgewell/trace-mapping': 0.3.31 babel-plugin-istanbul: 7.0.1 @@ -4841,7 +5145,7 @@ snapshots: '@modelcontextprotocol/server@2.0.0-alpha.4': dependencies: - zod: 4.4.3 + zod: 4.6.7 '@napi-rs/wasm-runtime@0.2.12': dependencies: @@ -4850,13 +5154,6 @@ snapshots: '@tybys/wasm-util': 0.10.4 optional: true - '@napi-rs/wasm-runtime@1.2.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': - dependencies: - '@emnapi/core': 1.10.0 - '@emnapi/runtime': 1.10.0 - '@tybys/wasm-util': 0.10.4 - optional: true - '@noble/ciphers@1.3.0': {} '@noble/curves@1.9.1': @@ -4881,60 +5178,56 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.20.1 - '@oxc-project/types@0.133.0': {} + '@oxc-project/types@0.155.0': {} '@pkgjs/parseargs@0.11.0': optional: true '@pkgr/core@0.2.9': {} - '@rolldown/binding-android-arm64@1.0.3': + '@rolldown/binding-android-arm-eabi@1.2.15': optional: true - '@rolldown/binding-darwin-arm64@1.0.3': + '@rolldown/binding-android-arm64@1.2.15': optional: true - '@rolldown/binding-darwin-x64@1.0.3': + '@rolldown/binding-darwin-arm64@1.2.15': optional: true - '@rolldown/binding-freebsd-x64@1.0.3': + '@rolldown/binding-darwin-x64@1.2.15': optional: true - '@rolldown/binding-linux-arm-gnueabihf@1.0.3': + '@rolldown/binding-freebsd-x64@1.2.15': optional: true - '@rolldown/binding-linux-arm64-gnu@1.0.3': + '@rolldown/binding-linux-arm-gnueabihf@1.2.15': optional: true - '@rolldown/binding-linux-arm64-musl@1.0.3': + '@rolldown/binding-linux-arm64-gnu@1.2.15': optional: true - '@rolldown/binding-linux-ppc64-gnu@1.0.3': + '@rolldown/binding-linux-arm64-musl@1.2.15': optional: true - '@rolldown/binding-linux-s390x-gnu@1.0.3': + '@rolldown/binding-linux-ppc64-gnu@1.2.15': optional: true - '@rolldown/binding-linux-x64-gnu@1.0.3': + '@rolldown/binding-linux-s390x-gnu@1.2.15': optional: true - '@rolldown/binding-linux-x64-musl@1.0.3': + '@rolldown/binding-linux-x64-gnu@1.2.15': optional: true - '@rolldown/binding-openharmony-arm64@1.0.3': + '@rolldown/binding-linux-x64-musl@1.2.15': optional: true - '@rolldown/binding-wasm32-wasi@1.0.3': - dependencies: - '@emnapi/core': 1.10.0 - '@emnapi/runtime': 1.10.0 - '@napi-rs/wasm-runtime': 1.2.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + '@rolldown/binding-openharmony-arm64@1.2.15': optional: true - '@rolldown/binding-win32-arm64-msvc@1.0.3': + '@rolldown/binding-win32-arm64-msvc@1.2.15': optional: true - '@rolldown/binding-win32-x64-msvc@1.0.3': + '@rolldown/binding-win32-x64-msvc@1.2.15': optional: true '@rolldown/pluginutils@1.0.1': {} @@ -5059,23 +5352,33 @@ snapshots: dependencies: '@sinonjs/commons': 3.0.1 - '@solana-program/compute-budget@0.11.0(@solana/kit@6.10.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6))': + '@solana-program/compute-budget@0.15.0(@solana/kit@6.10.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6))': dependencies: '@solana/kit': 6.10.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6) - '@solana-program/compute-budget@0.15.0(@solana/kit@6.10.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6))': + '@solana-program/compute-budget@0.18.1(@solana/kit@8.5.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6))': dependencies: - '@solana/kit': 6.10.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6) + '@solana/kit': 8.5.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6) + + '@solana-program/compute-budget@0.20.0(@solana/kit@8.5.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6))': + dependencies: + '@solana/kit': 8.5.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6) '@solana-program/record@0.3.0(@solana/kit@6.10.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6))': dependencies: '@solana/kit': 6.10.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6) - '@solana-program/system@0.12.0(@solana/kit@6.10.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6))': + '@solana-program/record@0.4.1(@solana/kit@8.5.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6))': dependencies: - '@solana/kit': 6.10.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6) + '@solana-program/system': 0.14.1(@solana/kit@8.5.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6)) + '@solana/kit': 8.5.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6) + + '@solana-program/record@0.6.0(@solana/kit@8.5.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6))': + dependencies: + '@solana-program/system': 0.16.0(@solana/kit@8.5.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6)) + '@solana/kit': 8.5.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6) - '@solana-program/system@0.12.2(@solana/kit@6.10.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6))': + '@solana-program/system@0.12.0(@solana/kit@6.10.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6))': dependencies: '@solana/kit': 6.10.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6) @@ -5083,12 +5386,13 @@ snapshots: dependencies: '@solana/kit': 6.10.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6) - '@solana-program/token-2022@0.11.0(@solana/kit@6.10.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6))(@solana/sysvars@5.5.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))': + '@solana-program/system@0.14.1(@solana/kit@8.5.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6))': dependencies: - '@noble/curves': 1.9.7 - '@solana-program/zk-elgamal-proof': 0.1.0(@solana/kit@6.10.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6)) - '@solana/kit': 6.10.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6) - '@solana/sysvars': 5.5.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/kit': 8.5.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6) + + '@solana-program/system@0.16.0(@solana/kit@8.5.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6))': + dependencies: + '@solana/kit': 8.5.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6) '@solana-program/token-2022@0.14.1(@solana/kit@6.10.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6))(@solana/sysvars@7.1.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))': dependencies: @@ -5098,19 +5402,26 @@ snapshots: '@solana/kit': 6.10.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6) '@solana/sysvars': 7.1.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) - '@solana-program/token-2022@0.6.1(@solana/kit@6.10.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6))(@solana/sysvars@5.5.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))': + '@solana-program/token-2022@0.16.1(@solana/kit@8.5.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6))(@solana/sysvars@8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))': dependencies: - '@solana/kit': 6.10.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6) - '@solana/sysvars': 5.5.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@noble/curves': 1.9.7 + '@solana-program/record': 0.4.1(@solana/kit@8.5.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6)) + '@solana-program/system': 0.14.1(@solana/kit@8.5.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6)) + '@solana-program/zk-elgamal-proof': 0.4.0(@solana/kit@8.5.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6)) + '@solana/kit': 8.5.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6) + '@solana/sysvars': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) - '@solana-program/token@0.11.0(@solana/kit@6.10.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6))': + '@solana-program/token-2022@0.20.0(@solana/kit@8.5.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6))(@solana/sysvars@8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))': dependencies: - '@solana-program/system': 0.12.0(@solana/kit@6.10.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6)) - '@solana/kit': 6.10.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6) + '@solana-program/record': 0.6.0(@solana/kit@8.5.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6)) + '@solana-program/system': 0.16.0(@solana/kit@8.5.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6)) + '@solana-program/zk-elgamal-proof': 0.5.0(@solana/kit@8.5.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6)) + '@solana/kit': 8.5.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6) + '@solana/sysvars': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) - '@solana-program/token@0.13.0(@solana/kit@6.10.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6))': + '@solana-program/token@0.11.0(@solana/kit@6.10.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6))': dependencies: - '@solana-program/system': 0.12.2(@solana/kit@6.10.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6)) + '@solana-program/system': 0.12.0(@solana/kit@6.10.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6)) '@solana/kit': 6.10.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6) '@solana-program/token@0.15.0(@solana/kit@6.10.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6))': @@ -5118,32 +5429,30 @@ snapshots: '@solana-program/system': 0.13.0(@solana/kit@6.10.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6)) '@solana/kit': 6.10.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6) - '@solana-program/token@0.9.0(@solana/kit@6.10.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6))': + '@solana-program/token@0.16.1(@solana/kit@8.5.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6))': dependencies: - '@solana/kit': 6.10.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6) + '@solana-program/system': 0.14.1(@solana/kit@8.5.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6)) + '@solana/kit': 8.5.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6) - '@solana-program/zk-elgamal-proof@0.1.0(@solana/kit@6.10.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6))': + '@solana-program/token@0.18.0(@solana/kit@8.5.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6))': dependencies: - '@solana-program/system': 0.12.2(@solana/kit@6.10.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6)) - '@solana/kit': 6.10.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6) + '@solana-program/system': 0.16.0(@solana/kit@8.5.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6)) + '@solana/kit': 8.5.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6) '@solana-program/zk-elgamal-proof@0.3.2(@solana/kit@6.10.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6))': dependencies: '@solana-program/system': 0.13.0(@solana/kit@6.10.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6)) '@solana/kit': 6.10.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6) - '@solana/accounts@5.5.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + '@solana-program/zk-elgamal-proof@0.4.0(@solana/kit@8.5.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6))': dependencies: - '@solana/addresses': 5.5.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) - '@solana/codecs-core': 5.5.1(typescript@5.9.3) - '@solana/codecs-strings': 5.5.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) - '@solana/errors': 5.5.1(typescript@5.9.3) - '@solana/rpc-spec': 5.5.1(typescript@5.9.3) - '@solana/rpc-types': 5.5.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder + '@solana-program/system': 0.14.1(@solana/kit@8.5.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6)) + '@solana/kit': 8.5.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6) + + '@solana-program/zk-elgamal-proof@0.5.0(@solana/kit@8.5.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6))': + dependencies: + '@solana-program/system': 0.16.0(@solana/kit@8.5.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6)) + '@solana/kit': 8.5.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6) '@solana/accounts@6.10.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': dependencies: @@ -5171,13 +5480,14 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/addresses@5.5.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + '@solana/accounts@8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': dependencies: - '@solana/assertions': 5.5.1(typescript@5.9.3) - '@solana/codecs-core': 5.5.1(typescript@5.9.3) - '@solana/codecs-strings': 5.5.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) - '@solana/errors': 5.5.1(typescript@5.9.3) - '@solana/nominal-types': 5.5.1(typescript@5.9.3) + '@solana/addresses': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-strings': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/rpc-spec': 8.5.0(typescript@5.9.3) + '@solana/rpc-types': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: @@ -5207,11 +5517,17 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/assertions@5.5.1(typescript@5.9.3)': + '@solana/addresses@8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': dependencies: - '@solana/errors': 5.5.1(typescript@5.9.3) + '@solana/assertions': 8.5.0(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-strings': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/nominal-types': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder '@solana/assertions@6.10.0(typescript@5.9.3)': dependencies: @@ -5225,9 +5541,9 @@ snapshots: optionalDependencies: typescript: 5.9.3 - '@solana/codecs-core@5.5.1(typescript@5.9.3)': + '@solana/assertions@8.5.0(typescript@5.9.3)': dependencies: - '@solana/errors': 5.5.1(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 @@ -5243,11 +5559,9 @@ snapshots: optionalDependencies: typescript: 5.9.3 - '@solana/codecs-data-structures@5.5.1(typescript@5.9.3)': + '@solana/codecs-core@8.5.0(typescript@5.9.3)': dependencies: - '@solana/codecs-core': 5.5.1(typescript@5.9.3) - '@solana/codecs-numbers': 5.5.1(typescript@5.9.3) - '@solana/errors': 5.5.1(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 @@ -5267,10 +5581,11 @@ snapshots: optionalDependencies: typescript: 5.9.3 - '@solana/codecs-numbers@5.5.1(typescript@5.9.3)': + '@solana/codecs-data-structures@8.5.0(typescript@5.9.3)': dependencies: - '@solana/codecs-core': 5.5.1(typescript@5.9.3) - '@solana/errors': 5.5.1(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 @@ -5288,13 +5603,11 @@ snapshots: optionalDependencies: typescript: 5.9.3 - '@solana/codecs-strings@5.5.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + '@solana/codecs-numbers@8.5.0(typescript@5.9.3)': dependencies: - '@solana/codecs-core': 5.5.1(typescript@5.9.3) - '@solana/codecs-numbers': 5.5.1(typescript@5.9.3) - '@solana/errors': 5.5.1(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) optionalDependencies: - fastestsmallesttextencoderdecoder: 1.0.22 typescript: 5.9.3 '@solana/codecs-strings@6.10.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': @@ -5315,17 +5628,14 @@ snapshots: fastestsmallesttextencoderdecoder: 1.0.22 typescript: 5.9.3 - '@solana/codecs@5.5.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + '@solana/codecs-strings@8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': dependencies: - '@solana/codecs-core': 5.5.1(typescript@5.9.3) - '@solana/codecs-data-structures': 5.5.1(typescript@5.9.3) - '@solana/codecs-numbers': 5.5.1(typescript@5.9.3) - '@solana/codecs-strings': 5.5.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) - '@solana/options': 5.5.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) optionalDependencies: + fastestsmallesttextencoderdecoder: 1.0.22 typescript: 5.9.3 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder '@solana/codecs@6.10.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': dependencies: @@ -5340,12 +5650,18 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/errors@5.5.1(typescript@5.9.3)': + '@solana/codecs@8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': dependencies: - chalk: 5.6.2 - commander: 14.0.2 + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-data-structures': 8.5.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.5.0(typescript@5.9.3) + '@solana/codecs-strings': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/fixed-points': 8.5.0(typescript@5.9.3) + '@solana/options': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder '@solana/errors@6.10.0(typescript@5.9.3)': dependencies: @@ -5361,6 +5677,13 @@ snapshots: optionalDependencies: typescript: 5.9.3 + '@solana/errors@8.5.0(typescript@5.9.3)': + dependencies: + chalk: 5.6.2 + commander: 15.0.0 + optionalDependencies: + typescript: 5.9.3 + '@solana/eslint-config-solana@6.0.0(@eslint/js@9.39.4)(@types/eslint@9.6.1)(@types/eslint__js@9.14.0)(eslint-plugin-jest@29.15.0(@typescript-eslint/eslint-plugin@8.57.1(@typescript-eslint/parser@8.57.1(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(jest@30.3.0(@types/node@25.5.0))(typescript@5.9.3))(eslint-plugin-react-hooks@7.0.1(eslint@9.39.4))(eslint-plugin-simple-import-sort@12.1.1(eslint@9.39.4))(eslint-plugin-sort-keys-fix@1.1.2)(eslint-plugin-typescript-sort-keys@3.3.0(@typescript-eslint/parser@8.57.1(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(globals@16.5.0)(jest@30.3.0(@types/node@25.5.0))(typescript-eslint@8.57.1(eslint@9.39.4)(typescript@5.9.3))(typescript@5.9.3)': dependencies: '@eslint/js': 9.39.4 @@ -5381,6 +5704,10 @@ snapshots: optionalDependencies: typescript: 5.9.3 + '@solana/fast-stable-stringify@8.5.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) @@ -5395,6 +5722,13 @@ snapshots: optionalDependencies: typescript: 5.9.3 + '@solana/fixed-points@8.5.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + '@solana/functional@6.10.0(typescript@5.9.3)': optionalDependencies: typescript: 5.9.3 @@ -5403,6 +5737,10 @@ snapshots: optionalDependencies: typescript: 5.9.3 + '@solana/functional@8.5.0(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + '@solana/instruction-plans@6.10.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': dependencies: '@solana/errors': 6.10.0(typescript@5.9.3) @@ -5429,6 +5767,19 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/instruction-plans@8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/instructions': 8.5.0(typescript@5.9.3) + '@solana/keys': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/promises': 8.5.0(typescript@5.9.3) + '@solana/transaction-messages': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transactions': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(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) @@ -5443,23 +5794,30 @@ snapshots: optionalDependencies: typescript: 5.9.3 - '@solana/keychain-core@1.3.0(@solana/addresses@7.1.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))(@solana/codecs-core@7.1.1(typescript@5.9.3))(@solana/codecs-strings@7.1.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))(@solana/keys@7.1.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))(@solana/signers@7.1.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))(@solana/transactions@7.1.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))': + '@solana/instructions@8.5.0(typescript@5.9.3)': dependencies: - '@solana/addresses': 7.1.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) - '@solana/codecs-core': 7.1.1(typescript@5.9.3) - '@solana/codecs-strings': 7.1.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) - '@solana/keys': 7.1.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) - '@solana/signers': 7.1.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) - '@solana/transactions': 7.1.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 - '@solana/keychain-memory@1.3.0(@solana/addresses@7.1.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))(@solana/codecs-core@7.1.1(typescript@5.9.3))(@solana/codecs-strings@7.1.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))(@solana/keys@7.1.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))(@solana/signers@7.1.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))(@solana/transactions@7.1.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))': + '@solana/keychain-core@1.3.0(@solana/addresses@8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))(@solana/codecs-core@8.5.0(typescript@5.9.3))(@solana/codecs-strings@8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))(@solana/keys@8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))(@solana/signers@8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))(@solana/transactions@8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))': dependencies: - '@solana/addresses': 7.1.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) - '@solana/codecs-strings': 7.1.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) - '@solana/keychain-core': 1.3.0(@solana/addresses@7.1.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))(@solana/codecs-core@7.1.1(typescript@5.9.3))(@solana/codecs-strings@7.1.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))(@solana/keys@7.1.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))(@solana/signers@7.1.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))(@solana/transactions@7.1.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)) - '@solana/keys': 7.1.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) - '@solana/signers': 7.1.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) - '@solana/transactions': 7.1.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/addresses': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-strings': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/keys': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/signers': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transactions': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + + '@solana/keychain-memory@1.3.0(@solana/addresses@8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))(@solana/codecs-core@8.5.0(typescript@5.9.3))(@solana/codecs-strings@8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))(@solana/keys@8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))(@solana/signers@8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))(@solana/transactions@8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))': + dependencies: + '@solana/addresses': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-strings': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/keychain-core': 1.3.0(@solana/addresses@8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))(@solana/codecs-core@8.5.0(typescript@5.9.3))(@solana/codecs-strings@8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))(@solana/keys@8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))(@solana/signers@8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))(@solana/transactions@8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)) + '@solana/keys': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/signers': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transactions': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) transitivePeerDependencies: - '@solana/codecs-core' @@ -5489,6 +5847,19 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/keys@8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/assertions': 8.5.0(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-strings': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/nominal-types': 8.5.0(typescript@5.9.3) + '@solana/promises': 8.5.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/kit-client-rpc@0.8.0(@solana/kit@6.10.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6))': dependencies: '@solana/kit': 6.10.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6) @@ -5555,9 +5926,41 @@ snapshots: - fastestsmallesttextencoderdecoder - utf-8-validate - '@solana/nominal-types@5.5.1(typescript@5.9.3)': + '@solana/kit@8.5.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6)': + dependencies: + '@solana/accounts': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/addresses': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/functional': 8.5.0(typescript@5.9.3) + '@solana/instruction-plans': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/instructions': 8.5.0(typescript@5.9.3) + '@solana/keys': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/offchain-messages': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/plugin-core': 8.5.0(typescript@5.9.3) + '@solana/plugin-interfaces': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/program-client-core': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/programs': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/promises': 8.5.0(typescript@5.9.3) + '@solana/rpc': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-api': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-parsed-types': 8.5.0(typescript@5.9.3) + '@solana/rpc-spec-types': 8.5.0(typescript@5.9.3) + '@solana/rpc-subscriptions': 8.5.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6) + '@solana/rpc-types': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/signers': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/subscribable': 8.5.0(typescript@5.9.3) + '@solana/sysvars': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transaction-confirmation': 8.5.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6) + '@solana/transaction-introspection': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transaction-messages': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transactions': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(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: @@ -5567,6 +5970,10 @@ snapshots: optionalDependencies: typescript: 5.9.3 + '@solana/nominal-types@8.5.0(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + '@solana/offchain-messages@6.10.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': dependencies: '@solana/addresses': 6.10.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) @@ -5597,13 +6004,16 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/options@5.5.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + '@solana/offchain-messages@8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': dependencies: - '@solana/codecs-core': 5.5.1(typescript@5.9.3) - '@solana/codecs-data-structures': 5.5.1(typescript@5.9.3) - '@solana/codecs-numbers': 5.5.1(typescript@5.9.3) - '@solana/codecs-strings': 5.5.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) - '@solana/errors': 5.5.1(typescript@5.9.3) + '@solana/addresses': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-data-structures': 8.5.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.5.0(typescript@5.9.3) + '@solana/codecs-strings': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/keys': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/nominal-types': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: @@ -5621,10 +6031,26 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/options@8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-data-structures': 8.5.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.5.0(typescript@5.9.3) + '@solana/codecs-strings': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 8.5.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.5.0(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + '@solana/plugin-interfaces@6.10.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': dependencies: '@solana/addresses': 6.10.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) @@ -5654,6 +6080,22 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/plugin-interfaces@8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/accounts': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/addresses': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/instruction-plans': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/keys': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-spec': 8.5.0(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 8.5.0(typescript@5.9.3) + '@solana/rpc-types': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/signers': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transactions': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/prettier-config-solana@0.0.6(prettier@3.8.1)': dependencies: prettier: 3.8.1 @@ -5690,6 +6132,22 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/program-client-core@8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/accounts': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/addresses': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/instruction-plans': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/instructions': 8.5.0(typescript@5.9.3) + '@solana/plugin-interfaces': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-api': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/signers': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/programs@6.10.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': dependencies: '@solana/addresses': 6.10.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) @@ -5699,6 +6157,15 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/programs@8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 8.5.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 @@ -5707,6 +6174,10 @@ snapshots: optionalDependencies: typescript: 5.9.3 + '@solana/promises@8.5.0(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + '@solana/rpc-api@6.10.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': dependencies: '@solana/addresses': 6.10.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) @@ -5743,6 +6214,24 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/rpc-api@8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-strings': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/keys': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-parsed-types': 8.5.0(typescript@5.9.3) + '@solana/rpc-spec': 8.5.0(typescript@5.9.3) + '@solana/rpc-transformers': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-types': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transaction-messages': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transactions': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(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 @@ -5751,7 +6240,7 @@ snapshots: optionalDependencies: typescript: 5.9.3 - '@solana/rpc-spec-types@5.5.1(typescript@5.9.3)': + '@solana/rpc-parsed-types@8.5.0(typescript@5.9.3)': optionalDependencies: typescript: 5.9.3 @@ -5765,10 +6254,9 @@ snapshots: optionalDependencies: typescript: 5.9.3 - '@solana/rpc-spec@5.5.1(typescript@5.9.3)': + '@solana/rpc-spec-types@8.5.0(typescript@5.9.3)': dependencies: - '@solana/errors': 5.5.1(typescript@5.9.3) - '@solana/rpc-spec-types': 5.5.1(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 @@ -5788,6 +6276,14 @@ snapshots: optionalDependencies: typescript: 5.9.3 + '@solana/rpc-spec@8.5.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/rpc-spec-types': 8.5.0(typescript@5.9.3) + '@solana/subscribable': 8.5.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + '@solana/rpc-subscriptions-api@6.10.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': dependencies: '@solana/addresses': 6.10.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) @@ -5802,6 +6298,20 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/rpc-subscriptions-api@8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/keys': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 8.5.0(typescript@5.9.3) + '@solana/rpc-transformers': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-types': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transaction-messages': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transactions': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/rpc-subscriptions-channel-websocket@6.10.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)': dependencies: '@solana/errors': 6.10.0(typescript@5.9.3) @@ -5815,6 +6325,19 @@ snapshots: - bufferutil - utf-8-validate + '@solana/rpc-subscriptions-channel-websocket@8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)': + dependencies: + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/functional': 8.5.0(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 8.5.0(typescript@5.9.3) + '@solana/subscribable': 8.5.0(typescript@5.9.3) + ws: 8.21.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) + 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) @@ -5833,6 +6356,15 @@ snapshots: optionalDependencies: typescript: 5.9.3 + '@solana/rpc-subscriptions-spec@8.5.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/promises': 8.5.0(typescript@5.9.3) + '@solana/rpc-spec-types': 8.5.0(typescript@5.9.3) + '@solana/subscribable': 8.5.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + '@solana/rpc-subscriptions@6.10.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6)': dependencies: '@solana/errors': 6.10.0(typescript@5.9.3) @@ -5853,6 +6385,26 @@ snapshots: - fastestsmallesttextencoderdecoder - utf-8-validate + '@solana/rpc-subscriptions@8.5.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6)': + dependencies: + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/fast-stable-stringify': 8.5.0(typescript@5.9.3) + '@solana/functional': 8.5.0(typescript@5.9.3) + '@solana/promises': 8.5.0(typescript@5.9.3) + '@solana/rpc-spec-types': 8.5.0(typescript@5.9.3) + '@solana/rpc-subscriptions-api': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-subscriptions-channel-websocket': 8.5.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6) + '@solana/rpc-subscriptions-spec': 8.5.0(typescript@5.9.3) + '@solana/rpc-transformers': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-types': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/subscribable': 8.5.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - bufferutil + - fastestsmallesttextencoderdecoder + - utf-8-validate + '@solana/rpc-transformers@6.10.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': dependencies: '@solana/errors': 6.10.0(typescript@5.9.3) @@ -5877,6 +6429,18 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/rpc-transformers@8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/functional': 8.5.0(typescript@5.9.3) + '@solana/nominal-types': 8.5.0(typescript@5.9.3) + '@solana/rpc-spec-types': 8.5.0(typescript@5.9.3) + '@solana/rpc-types': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(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) @@ -5886,18 +6450,14 @@ snapshots: optionalDependencies: typescript: 5.9.3 - '@solana/rpc-types@5.5.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + '@solana/rpc-transport-http@8.5.0(typescript@5.9.3)': dependencies: - '@solana/addresses': 5.5.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) - '@solana/codecs-core': 5.5.1(typescript@5.9.3) - '@solana/codecs-numbers': 5.5.1(typescript@5.9.3) - '@solana/codecs-strings': 5.5.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) - '@solana/errors': 5.5.1(typescript@5.9.3) - '@solana/nominal-types': 5.5.1(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/rpc-spec': 8.5.0(typescript@5.9.3) + '@solana/rpc-spec-types': 8.5.0(typescript@5.9.3) + undici-types: 8.12.3 optionalDependencies: typescript: 5.9.3 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder '@solana/rpc-types@6.10.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': dependencies: @@ -5927,6 +6487,20 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/rpc-types@8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.5.0(typescript@5.9.3) + '@solana/codecs-strings': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/fixed-points': 8.5.0(typescript@5.9.3) + '@solana/nominal-types': 8.5.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/rpc@6.10.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': dependencies: '@solana/errors': 6.10.0(typescript@5.9.3) @@ -5943,6 +6517,22 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/rpc@8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/fast-stable-stringify': 8.5.0(typescript@5.9.3) + '@solana/functional': 8.5.0(typescript@5.9.3) + '@solana/rpc-api': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-spec': 8.5.0(typescript@5.9.3) + '@solana/rpc-spec-types': 8.5.0(typescript@5.9.3) + '@solana/rpc-transformers': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-transport-http': 8.5.0(typescript@5.9.3) + '@solana/rpc-types': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/signers@6.10.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': dependencies: '@solana/addresses': 6.10.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) @@ -5975,6 +6565,22 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/signers@8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/instructions': 8.5.0(typescript@5.9.3) + '@solana/keys': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/nominal-types': 8.5.0(typescript@5.9.3) + '@solana/offchain-messages': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transaction-messages': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transactions': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(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) @@ -5989,6 +6595,13 @@ snapshots: optionalDependencies: typescript: 5.9.3 + '@solana/subscribable@8.5.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/promises': 8.5.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + '@solana/subscriptions@0.5.0(@solana/kit@6.10.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6))(@solana/sysvars@7.1.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': dependencies: '@solana-program/token': 0.15.0(@solana/kit@6.10.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6)) @@ -6003,17 +6616,6 @@ snapshots: - fastestsmallesttextencoderdecoder - typescript - '@solana/sysvars@5.5.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': - dependencies: - '@solana/accounts': 5.5.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) - '@solana/codecs': 5.5.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) - '@solana/errors': 5.5.1(typescript@5.9.3) - '@solana/rpc-types': 5.5.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - '@solana/sysvars@6.10.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': dependencies: '@solana/accounts': 6.10.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) @@ -6040,6 +6642,19 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/sysvars@8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/accounts': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-data-structures': 8.5.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/rpc-types': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/transaction-confirmation@6.10.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6)': dependencies: '@solana/addresses': 6.10.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) @@ -6059,6 +6674,40 @@ snapshots: - fastestsmallesttextencoderdecoder - utf-8-validate + '@solana/transaction-confirmation@8.5.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6)': + dependencies: + '@solana/addresses': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-strings': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/keys': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/promises': 8.5.0(typescript@5.9.3) + '@solana/rpc': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-subscriptions': 8.5.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6) + '@solana/rpc-types': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transaction-messages': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transactions': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - bufferutil + - fastestsmallesttextencoderdecoder + - utf-8-validate + + '@solana/transaction-introspection@8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-strings': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/instructions': 8.5.0(typescript@5.9.3) + '@solana/rpc-types': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transaction-messages': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transactions': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/transaction-messages@6.10.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': dependencies: '@solana/addresses': 6.10.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) @@ -6091,6 +6740,22 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/transaction-messages@8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-data-structures': 8.5.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.5.0(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/functional': 8.5.0(typescript@5.9.3) + '@solana/instructions': 8.5.0(typescript@5.9.3) + '@solana/nominal-types': 8.5.0(typescript@5.9.3) + '@solana/rpc-types': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/transactions@6.10.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': dependencies: '@solana/addresses': 6.10.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) @@ -6129,6 +6794,25 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/transactions@8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 8.5.0(typescript@5.9.3) + '@solana/codecs-data-structures': 8.5.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.5.0(typescript@5.9.3) + '@solana/codecs-strings': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 8.5.0(typescript@5.9.3) + '@solana/functional': 8.5.0(typescript@5.9.3) + '@solana/instructions': 8.5.0(typescript@5.9.3) + '@solana/keys': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/nominal-types': 8.5.0(typescript@5.9.3) + '@solana/rpc-types': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transaction-messages': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@standard-schema/spec@1.1.0': {} '@stripe/stripe-js@9.9.0': {} @@ -6142,24 +6826,24 @@ snapshots: '@types/babel__core@7.20.5': dependencies: - '@babel/parser': 7.29.2 - '@babel/types': 7.29.0 + '@babel/parser': 7.29.11 + '@babel/types': 7.29.11 '@types/babel__generator': 7.27.0 '@types/babel__template': 7.4.4 '@types/babel__traverse': 7.28.0 '@types/babel__generator@7.27.0': dependencies: - '@babel/types': 7.29.0 + '@babel/types': 7.29.11 '@types/babel__template@7.4.4': dependencies: - '@babel/parser': 7.29.2 - '@babel/types': 7.29.0 + '@babel/parser': 7.29.11 + '@babel/types': 7.29.11 '@types/babel__traverse@7.28.0': dependencies: - '@babel/types': 7.29.0 + '@babel/types': 7.29.11 '@types/chai@5.2.3': dependencies: @@ -6414,10 +7098,10 @@ snapshots: '@unrs/resolver-binding-win32-x64-msvc@1.11.1': optional: true - '@vitest/coverage-v8@4.1.11(vitest@4.1.11)': + '@vitest/coverage-v8@4.1.12(vitest@4.1.12)': dependencies: '@bcoe/v8-coverage': 1.0.2 - '@vitest/utils': 4.1.11 + '@vitest/utils': 4.1.12 ast-v8-to-istanbul: 1.0.0 istanbul-lib-coverage: 3.2.2 istanbul-lib-report: 3.0.1 @@ -6426,71 +7110,72 @@ snapshots: obug: 2.2.1 std-env: 4.2.0 tinyrainbow: 3.1.1 - vitest: 4.1.11(@types/node@25.5.0)(@vitest/coverage-v8@4.1.11)(vite@8.0.16(@types/node@25.5.0)(esbuild@0.27.4)(tsx@4.21.0)(yaml@2.9.0)) + vitest: 4.1.12(@types/node@25.5.0)(@vitest/coverage-v8@4.1.12)(vite@8.3.5(@types/node@25.5.0)(esbuild@0.28.2)(tsx@4.21.0)(yaml@2.9.0)) - '@vitest/expect@4.1.11': + '@vitest/expect@4.1.12': dependencies: '@standard-schema/spec': 1.1.0 '@types/chai': 5.2.3 - '@vitest/spy': 4.1.11 - '@vitest/utils': 4.1.11 + '@vitest/spy': 4.1.12 + '@vitest/utils': 4.1.12 chai: 6.2.2 tinyrainbow: 3.1.1 - '@vitest/mocker@4.1.11(vite@8.0.16(@types/node@25.5.0)(esbuild@0.27.4)(tsx@4.21.0)(yaml@2.9.0))': + '@vitest/mocker@4.1.12(vite@8.3.5(@types/node@25.5.0)(esbuild@0.28.2)(tsx@4.21.0)(yaml@2.9.0))': dependencies: - '@vitest/spy': 4.1.11 + '@vitest/spy': 4.1.12 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 8.0.16(@types/node@25.5.0)(esbuild@0.27.4)(tsx@4.21.0)(yaml@2.9.0) + vite: 8.3.5(@types/node@25.5.0)(esbuild@0.28.2)(tsx@4.21.0)(yaml@2.9.0) - '@vitest/pretty-format@4.1.11': + '@vitest/pretty-format@4.1.12': dependencies: tinyrainbow: 3.1.1 - '@vitest/runner@4.1.11': + '@vitest/runner@4.1.12': dependencies: - '@vitest/utils': 4.1.11 + '@vitest/utils': 4.1.12 pathe: 2.0.3 - '@vitest/snapshot@4.1.11': + '@vitest/snapshot@4.1.12': dependencies: - '@vitest/pretty-format': 4.1.11 - '@vitest/utils': 4.1.11 + '@vitest/pretty-format': 4.1.12 + '@vitest/utils': 4.1.12 magic-string: 0.30.21 pathe: 2.0.3 - '@vitest/spy@4.1.11': {} + '@vitest/spy@4.1.12': {} - '@vitest/utils@4.1.11': + '@vitest/utils@4.1.12': dependencies: - '@vitest/pretty-format': 4.1.11 + '@vitest/pretty-format': 4.1.12 convert-source-map: 2.0.0 tinyrainbow: 3.1.1 - '@x402/core@file:.x402-vendor/x402-core-2.26.0.tgz': + '@x402/core@file:.x402-vendor/x402-core-2.28.0.tgz': dependencies: - zod: 3.25.76 + zod: 4.6.7 - '@x402/svm@file:.x402-vendor/x402-svm-2.26.0.tgz(@solana/kit@6.10.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6))(@solana/sysvars@5.5.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + '@x402/svm@file:.x402-vendor/x402-svm-2.28.0.tgz(@solana/kit@8.5.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6))(@solana/sysvars@8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': dependencies: '@noble/hashes': 1.8.0 - '@solana-program/compute-budget': 0.11.0(@solana/kit@6.10.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6)) - '@solana-program/token': 0.9.0(@solana/kit@6.10.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6)) - '@solana-program/token-2022': 0.6.1(@solana/kit@6.10.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6))(@solana/sysvars@5.5.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)) - '@solana/kit': 6.10.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6) - '@solana/program-client-core': 6.10.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) - '@x402/core': file:.x402-vendor/x402-core-2.26.0.tgz + '@solana-program/compute-budget': 0.18.1(@solana/kit@8.5.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6)) + '@solana-program/token': 0.16.1(@solana/kit@8.5.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6)) + '@solana-program/token-2022': 0.16.1(@solana/kit@8.5.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6))(@solana/sysvars@8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)) + '@solana/kit': 8.5.0(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@6.0.6) + '@solana/program-client-core': 8.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@x402/core': file:.x402-vendor/x402-core-2.28.0.tgz transitivePeerDependencies: - '@solana/sysvars' + - '@solana/zk-sdk' - fastestsmallesttextencoderdecoder - typescript - abitype@1.2.3(typescript@5.9.3)(zod@4.4.3): + abitype@1.2.3(typescript@5.9.3)(zod@4.6.7): optionalDependencies: typescript: 5.9.3 - zod: 4.4.3 + zod: 4.6.7 accepts@2.0.0: dependencies: @@ -6552,13 +7237,13 @@ snapshots: estree-walker: 3.0.3 js-tokens: 10.0.0 - babel-jest@30.3.0(@babel/core@7.29.0): + babel-jest@30.3.0(@babel/core@7.29.7): dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.7 '@jest/transform': 30.3.0 '@types/babel__core': 7.20.5 babel-plugin-istanbul: 7.0.1 - babel-preset-jest: 30.3.0(@babel/core@7.29.0) + babel-preset-jest: 30.3.0(@babel/core@7.29.7) chalk: 4.1.2 graceful-fs: 4.2.11 slash: 3.0.0 @@ -6579,30 +7264,30 @@ snapshots: dependencies: '@types/babel__core': 7.20.5 - babel-preset-current-node-syntax@1.2.0(@babel/core@7.29.0): - dependencies: - '@babel/core': 7.29.0 - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.29.0) - '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.29.0) - '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.29.0) - '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.29.0) - '@babel/plugin-syntax-import-attributes': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.29.0) - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.29.0) - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.29.0) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.29.0) - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.29.0) - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.29.0) - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.29.0) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.29.0) - '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.29.0) - '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.29.0) - - babel-preset-jest@30.3.0(@babel/core@7.29.0): - dependencies: - '@babel/core': 7.29.0 + babel-preset-current-node-syntax@1.2.0(@babel/core@7.29.7): + dependencies: + '@babel/core': 7.29.7 + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.29.7) + '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.29.7) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.29.7) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.29.7) + '@babel/plugin-syntax-import-attributes': 7.28.6(@babel/core@7.29.7) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.29.7) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.29.7) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.29.7) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.29.7) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.29.7) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.29.7) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.29.7) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.29.7) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.29.7) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.29.7) + + babel-preset-jest@30.3.0(@babel/core@7.29.7): + dependencies: + '@babel/core': 7.29.7 babel-plugin-jest-hoist: 30.3.0 - babel-preset-current-node-syntax: 1.2.0(@babel/core@7.29.0) + babel-preset-current-node-syntax: 1.2.0(@babel/core@7.29.7) balanced-match@1.0.2: {} @@ -6610,13 +7295,13 @@ snapshots: baseline-browser-mapping@2.11.0: {} - body-parser@2.3.0: + body-parser@2.4.0: dependencies: bytes: 3.1.2 - content-type: 2.0.0 + content-type: 2.1.0 debug: 4.4.3 http-errors: 2.0.1 - iconv-lite: 0.7.2 + iconv-lite: 0.7.3 on-finished: 2.4.1 qs: 6.16.0 raw-body: 3.0.2 @@ -6661,9 +7346,9 @@ snapshots: node-gyp-build: 4.8.4 optional: true - bundle-require@5.1.0(esbuild@0.27.4): + bundle-require@5.1.0(esbuild@0.28.2): dependencies: - esbuild: 0.27.4 + esbuild: 0.28.2 load-tsconfig: 0.2.5 bytes@3.1.2: @@ -6726,8 +7411,6 @@ snapshots: color-name@1.1.4: {} - commander@14.0.2: {} - commander@15.0.0: {} commander@4.1.1: {} @@ -6744,7 +7427,7 @@ snapshots: content-type@1.0.5: optional: true - content-type@2.0.0: + content-type@2.1.0: optional: true convert-source-map@2.0.0: {} @@ -6824,34 +7507,34 @@ snapshots: es-errors: 1.3.0 optional: true - esbuild@0.27.4: - optionalDependencies: - '@esbuild/aix-ppc64': 0.27.4 - '@esbuild/android-arm': 0.27.4 - '@esbuild/android-arm64': 0.27.4 - '@esbuild/android-x64': 0.27.4 - '@esbuild/darwin-arm64': 0.27.4 - '@esbuild/darwin-x64': 0.27.4 - '@esbuild/freebsd-arm64': 0.27.4 - '@esbuild/freebsd-x64': 0.27.4 - '@esbuild/linux-arm': 0.27.4 - '@esbuild/linux-arm64': 0.27.4 - '@esbuild/linux-ia32': 0.27.4 - '@esbuild/linux-loong64': 0.27.4 - '@esbuild/linux-mips64el': 0.27.4 - '@esbuild/linux-ppc64': 0.27.4 - '@esbuild/linux-riscv64': 0.27.4 - '@esbuild/linux-s390x': 0.27.4 - '@esbuild/linux-x64': 0.27.4 - '@esbuild/netbsd-arm64': 0.27.4 - '@esbuild/netbsd-x64': 0.27.4 - '@esbuild/openbsd-arm64': 0.27.4 - '@esbuild/openbsd-x64': 0.27.4 - '@esbuild/openharmony-arm64': 0.27.4 - '@esbuild/sunos-x64': 0.27.4 - '@esbuild/win32-arm64': 0.27.4 - '@esbuild/win32-ia32': 0.27.4 - '@esbuild/win32-x64': 0.27.4 + 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 escalade@3.2.0: {} @@ -6875,12 +7558,12 @@ snapshots: eslint-plugin-react-hooks@7.0.1(eslint@9.39.4): dependencies: - '@babel/core': 7.29.0 - '@babel/parser': 7.29.2 + '@babel/core': 7.29.7 + '@babel/parser': 7.29.11 eslint: 9.39.4 hermes-parser: 0.25.1 - zod: 4.4.3 - zod-validation-error: 4.0.2(zod@4.4.3) + zod: 4.6.7 + zod-validation-error: 4.0.2(zod@4.6.7) transitivePeerDependencies: - supports-color @@ -7028,7 +7711,7 @@ snapshots: express@5.2.1: dependencies: accepts: 2.0.0 - body-parser: 2.3.0 + body-parser: 2.4.0 content-disposition: 1.0.1 content-type: 1.0.5 cookie: 0.7.2 @@ -7255,7 +7938,7 @@ snapshots: human-signals@2.1.0: {} - iconv-lite@0.7.2: + iconv-lite@0.7.3: dependencies: safer-buffer: 2.1.2 optional: true @@ -7284,7 +7967,7 @@ snapshots: '@toon-format/toon': 2.3.1 tokenx: 1.3.0 yaml: 2.9.0 - zod: 4.4.3 + zod: 4.6.7 inflight@1.0.6: dependencies: @@ -7325,8 +8008,8 @@ snapshots: istanbul-lib-instrument@6.0.3: dependencies: - '@babel/core': 7.29.0 - '@babel/parser': 7.29.2 + '@babel/core': 7.29.7 + '@babel/parser': 7.29.11 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.2 semver: 7.7.4 @@ -7411,12 +8094,12 @@ snapshots: jest-config@30.3.0(@types/node@25.5.0): dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.7 '@jest/get-type': 30.1.0 '@jest/pattern': 30.0.1 '@jest/test-sequencer': 30.3.0 '@jest/types': 30.3.0 - babel-jest: 30.3.0(@babel/core@7.29.0) + babel-jest: 30.3.0(@babel/core@7.29.7) chalk: 4.1.2 ci-info: 4.4.0 deepmerge: 4.3.1 @@ -7498,7 +8181,7 @@ snapshots: jest-message-util@30.3.0: dependencies: - '@babel/code-frame': 7.29.0 + '@babel/code-frame': 7.29.7 '@jest/types': 30.3.0 '@types/stack-utils': 2.0.3 chalk: 4.1.2 @@ -7594,17 +8277,17 @@ snapshots: jest-snapshot@30.3.0: dependencies: - '@babel/core': 7.29.0 - '@babel/generator': 7.29.1 - '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.0) - '@babel/types': 7.29.0 + '@babel/core': 7.29.7 + '@babel/generator': 7.29.8 + '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.7) + '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.7) + '@babel/types': 7.29.11 '@jest/expect-utils': 30.3.0 '@jest/get-type': 30.1.0 '@jest/snapshot-utils': 30.3.0 '@jest/transform': 30.3.0 '@jest/types': 30.3.0 - babel-preset-current-node-syntax: 1.2.0(@babel/core@7.29.0) + babel-preset-current-node-syntax: 1.2.0(@babel/core@7.29.7) chalk: 4.1.2 expect: 30.3.0 graceful-fs: 4.2.11 @@ -7703,54 +8386,54 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 - lightningcss-android-arm64@1.32.0: + lightningcss-android-arm64@1.33.0: optional: true - lightningcss-darwin-arm64@1.32.0: + lightningcss-darwin-arm64@1.33.0: optional: true - lightningcss-darwin-x64@1.32.0: + lightningcss-darwin-x64@1.33.0: optional: true - lightningcss-freebsd-x64@1.32.0: + lightningcss-freebsd-x64@1.33.0: optional: true - lightningcss-linux-arm-gnueabihf@1.32.0: + lightningcss-linux-arm-gnueabihf@1.33.0: optional: true - lightningcss-linux-arm64-gnu@1.32.0: + lightningcss-linux-arm64-gnu@1.33.0: optional: true - lightningcss-linux-arm64-musl@1.32.0: + lightningcss-linux-arm64-musl@1.33.0: optional: true - lightningcss-linux-x64-gnu@1.32.0: + lightningcss-linux-x64-gnu@1.33.0: optional: true - lightningcss-linux-x64-musl@1.32.0: + lightningcss-linux-x64-musl@1.33.0: optional: true - lightningcss-win32-arm64-msvc@1.32.0: + lightningcss-win32-arm64-msvc@1.33.0: optional: true - lightningcss-win32-x64-msvc@1.32.0: + lightningcss-win32-x64-msvc@1.33.0: optional: true - lightningcss@1.32.0: + lightningcss@1.33.0: dependencies: detect-libc: 2.1.2 optionalDependencies: - lightningcss-android-arm64: 1.32.0 - lightningcss-darwin-arm64: 1.32.0 - lightningcss-darwin-x64: 1.32.0 - lightningcss-freebsd-x64: 1.32.0 - lightningcss-linux-arm-gnueabihf: 1.32.0 - lightningcss-linux-arm64-gnu: 1.32.0 - lightningcss-linux-arm64-musl: 1.32.0 - lightningcss-linux-x64-gnu: 1.32.0 - lightningcss-linux-x64-musl: 1.32.0 - lightningcss-win32-arm64-msvc: 1.32.0 - lightningcss-win32-x64-msvc: 1.32.0 + lightningcss-android-arm64: 1.33.0 + lightningcss-darwin-arm64: 1.33.0 + lightningcss-darwin-x64: 1.33.0 + lightningcss-freebsd-x64: 1.33.0 + lightningcss-linux-arm-gnueabihf: 1.33.0 + lightningcss-linux-arm64-gnu: 1.33.0 + lightningcss-linux-arm64-musl: 1.33.0 + lightningcss-linux-x64-gnu: 1.33.0 + lightningcss-linux-x64-musl: 1.33.0 + lightningcss-win32-arm64-msvc: 1.33.0 + lightningcss-win32-x64-msvc: 1.33.0 lilconfig@3.1.3: {} @@ -7798,7 +8481,7 @@ snapshots: dependencies: tmpl: 1.0.5 - markdown-it@14.3.1: + markdown-it@14.3.3: dependencies: argparse: 2.0.1 entities: 4.5.0 @@ -7862,14 +8545,14 @@ snapshots: pkg-types: 1.3.1 ufo: 1.6.4 - mppx@0.8.15(express@5.2.1)(typescript@5.9.3)(viem@2.55.10(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.4.3)): + mppx@0.8.15(express@5.2.1)(typescript@5.9.3)(viem@2.55.10(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.6.7)): dependencies: '@stripe/stripe-js': 9.9.0 eventsource-parser: 3.1.0 incur: 0.4.26 - ox: 0.14.33(typescript@5.9.3)(zod@4.4.3) - viem: 2.55.10(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.4.3) - zod: 4.4.3 + ox: 0.14.33(typescript@5.9.3)(zod@4.6.7) + viem: 2.55.10(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.6.7) + zod: 4.6.7 optionalDependencies: express: 5.2.1 transitivePeerDependencies: @@ -7936,7 +8619,7 @@ snapshots: type-check: 0.4.0 word-wrap: 1.2.5 - ox@0.14.33(typescript@5.9.3)(zod@4.4.3): + ox@0.14.33(typescript@5.9.3)(zod@4.6.7): dependencies: '@adraffy/ens-normalize': 1.11.1 '@noble/ciphers': 1.3.0 @@ -7944,7 +8627,7 @@ snapshots: '@noble/hashes': 1.8.0 '@scure/bip32': 1.7.0 '@scure/bip39': 1.6.0 - abitype: 1.2.3(typescript@5.9.3)(zod@4.4.3) + abitype: 1.2.3(typescript@5.9.3)(zod@4.6.7) eventemitter3: 5.0.1 optionalDependencies: typescript: 5.9.3 @@ -7977,7 +8660,7 @@ snapshots: parse-json@5.2.0: dependencies: - '@babel/code-frame': 7.29.0 + '@babel/code-frame': 7.29.7 error-ex: 1.3.4 json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 @@ -8072,7 +8755,7 @@ snapshots: dependencies: bytes: 3.1.2 http-errors: 2.0.1 - iconv-lite: 0.7.2 + iconv-lite: 0.7.3 unpipe: 1.0.0 optional: true @@ -8096,26 +8779,26 @@ snapshots: reusify@1.1.0: {} - rolldown@1.0.3: + rolldown@1.2.15: dependencies: - '@oxc-project/types': 0.133.0 + '@oxc-project/types': 0.155.0 '@rolldown/pluginutils': 1.0.1 optionalDependencies: - '@rolldown/binding-android-arm64': 1.0.3 - '@rolldown/binding-darwin-arm64': 1.0.3 - '@rolldown/binding-darwin-x64': 1.0.3 - '@rolldown/binding-freebsd-x64': 1.0.3 - '@rolldown/binding-linux-arm-gnueabihf': 1.0.3 - '@rolldown/binding-linux-arm64-gnu': 1.0.3 - '@rolldown/binding-linux-arm64-musl': 1.0.3 - '@rolldown/binding-linux-ppc64-gnu': 1.0.3 - '@rolldown/binding-linux-s390x-gnu': 1.0.3 - '@rolldown/binding-linux-x64-gnu': 1.0.3 - '@rolldown/binding-linux-x64-musl': 1.0.3 - '@rolldown/binding-openharmony-arm64': 1.0.3 - '@rolldown/binding-wasm32-wasi': 1.0.3 - '@rolldown/binding-win32-arm64-msvc': 1.0.3 - '@rolldown/binding-win32-x64-msvc': 1.0.3 + '@rolldown/binding-android-arm-eabi': 1.2.15 + '@rolldown/binding-android-arm64': 1.2.15 + '@rolldown/binding-darwin-arm64': 1.2.15 + '@rolldown/binding-darwin-x64': 1.2.15 + '@rolldown/binding-freebsd-x64': 1.2.15 + '@rolldown/binding-linux-arm-gnueabihf': 1.2.15 + '@rolldown/binding-linux-arm64-gnu': 1.2.15 + '@rolldown/binding-linux-arm64-musl': 1.2.15 + '@rolldown/binding-linux-ppc64-gnu': 1.2.15 + '@rolldown/binding-linux-s390x-gnu': 1.2.15 + '@rolldown/binding-linux-x64-gnu': 1.2.15 + '@rolldown/binding-linux-x64-musl': 1.2.15 + '@rolldown/binding-openharmony-arm64': 1.2.15 + '@rolldown/binding-win32-arm64-msvc': 1.2.15 + '@rolldown/binding-win32-x64-msvc': 1.2.15 rollup@4.62.0: dependencies: @@ -8394,12 +9077,12 @@ snapshots: tsup@8.5.1(postcss@8.5.23)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.9.0): dependencies: - bundle-require: 5.1.0(esbuild@0.27.4) + bundle-require: 5.1.0(esbuild@0.28.2) cac: 6.7.14 chokidar: 4.0.3 consola: 3.4.2 debug: 4.4.3 - esbuild: 0.27.4 + esbuild: 0.28.2 fix-dts-default-cjs-exports: 1.0.1 joycon: 3.1.1 picocolors: 1.1.1 @@ -8427,7 +9110,7 @@ snapshots: tsx@4.21.0: dependencies: - esbuild: 0.27.4 + esbuild: 0.28.2 get-tsconfig: 4.13.6 optionalDependencies: fsevents: 2.3.3 @@ -8442,7 +9125,7 @@ snapshots: type-is@2.1.0: dependencies: - content-type: 2.0.0 + content-type: 2.1.0 media-typer: 1.1.0 mime-types: 3.0.2 optional: true @@ -8455,7 +9138,7 @@ snapshots: dependencies: '@gerrit0/mini-shiki': 3.23.0 lunr: 2.3.9 - markdown-it: 14.3.1 + markdown-it: 14.3.3 minimatch: 10.2.5 typescript: 5.9.3 yaml: 2.9.0 @@ -8479,6 +9162,8 @@ snapshots: undici-types@7.18.2: {} + undici-types@8.12.3: {} + undici-types@8.5.0: {} unpipe@1.0.0: @@ -8532,15 +9217,15 @@ snapshots: vary@1.1.2: optional: true - viem@2.55.10(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.4.3): + viem@2.55.10(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.6.7): dependencies: '@noble/curves': 1.9.1 '@noble/hashes': 1.8.0 '@scure/bip32': 1.7.0 '@scure/bip39': 1.6.0 - abitype: 1.2.3(typescript@5.9.3)(zod@4.4.3) + abitype: 1.2.3(typescript@5.9.3)(zod@4.6.7) isows: 1.0.7(ws@8.21.0(bufferutil@4.1.0)(utf-8-validate@6.0.6)) - ox: 0.14.33(typescript@5.9.3)(zod@4.4.3) + ox: 0.14.33(typescript@5.9.3)(zod@4.6.7) ws: 8.21.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) optionalDependencies: typescript: 5.9.3 @@ -8549,29 +9234,29 @@ snapshots: - utf-8-validate - zod - vite@8.0.16(@types/node@25.5.0)(esbuild@0.27.4)(tsx@4.21.0)(yaml@2.9.0): + vite@8.3.5(@types/node@25.5.0)(esbuild@0.28.2)(tsx@4.21.0)(yaml@2.9.0): dependencies: - lightningcss: 1.32.0 + lightningcss: 1.33.0 picomatch: 4.0.7 postcss: 8.5.23 - rolldown: 1.0.3 + rolldown: 1.2.15 tinyglobby: 0.2.17 optionalDependencies: '@types/node': 25.5.0 - esbuild: 0.27.4 + esbuild: 0.28.2 fsevents: 2.3.3 tsx: 4.21.0 yaml: 2.9.0 - vitest@4.1.11(@types/node@25.5.0)(@vitest/coverage-v8@4.1.11)(vite@8.0.16(@types/node@25.5.0)(esbuild@0.27.4)(tsx@4.21.0)(yaml@2.9.0)): + vitest@4.1.12(@types/node@25.5.0)(@vitest/coverage-v8@4.1.12)(vite@8.3.5(@types/node@25.5.0)(esbuild@0.28.2)(tsx@4.21.0)(yaml@2.9.0)): dependencies: - '@vitest/expect': 4.1.11 - '@vitest/mocker': 4.1.11(vite@8.0.16(@types/node@25.5.0)(esbuild@0.27.4)(tsx@4.21.0)(yaml@2.9.0)) - '@vitest/pretty-format': 4.1.11 - '@vitest/runner': 4.1.11 - '@vitest/snapshot': 4.1.11 - '@vitest/spy': 4.1.11 - '@vitest/utils': 4.1.11 + '@vitest/expect': 4.1.12 + '@vitest/mocker': 4.1.12(vite@8.3.5(@types/node@25.5.0)(esbuild@0.28.2)(tsx@4.21.0)(yaml@2.9.0)) + '@vitest/pretty-format': 4.1.12 + '@vitest/runner': 4.1.12 + '@vitest/snapshot': 4.1.12 + '@vitest/spy': 4.1.12 + '@vitest/utils': 4.1.12 es-module-lexer: 2.3.2 expect-type: 1.4.0 magic-string: 0.30.21 @@ -8583,11 +9268,11 @@ snapshots: tinyexec: 1.3.1 tinyglobby: 0.2.17 tinyrainbow: 3.1.1 - vite: 8.0.16(@types/node@25.5.0)(esbuild@0.27.4)(tsx@4.21.0)(yaml@2.9.0) + vite: 8.3.5(@types/node@25.5.0)(esbuild@0.28.2)(tsx@4.21.0)(yaml@2.9.0) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 25.5.0 - '@vitest/coverage-v8': 4.1.11(vitest@4.1.11) + '@vitest/coverage-v8': 4.1.12(vitest@4.1.12) transitivePeerDependencies: - msw @@ -8650,10 +9335,8 @@ snapshots: yocto-queue@0.1.0: {} - zod-validation-error@4.0.2(zod@4.4.3): + zod-validation-error@4.0.2(zod@4.6.7): dependencies: - zod: 4.4.3 - - zod@3.25.76: {} + zod: 4.6.7 - zod@4.4.3: {} + zod@4.6.7: {} diff --git a/typescript/pnpm-workspace.yaml b/typescript/pnpm-workspace.yaml index e3019811e..5832dcd0b 100644 --- a/typescript/pnpm-workspace.yaml +++ b/typescript/pnpm-workspace.yaml @@ -16,7 +16,7 @@ minimumReleaseAgeExclude: # @solana/kit > @solana/rpc-subscriptions > @solana/rpc-subscriptions-channel-websocket. overrides: ws: '^8.21.0' - '@x402/core': 'file:.x402-vendor/x402-core-2.26.0.tgz' + '@x402/core': 'file:.x402-vendor/x402-core-2.28.0.tgz' '@hono/node-server': '>=2.0.10' '@humanfs/node': '0.16.8' baseline-browser-mapping: '2.11.0' @@ -26,12 +26,21 @@ overrides: 'brace-expansion@5.0.4': '5.0.12' 'brace-expansion@5.0.6': '5.0.12' 'linkify-it': '5.0.2' - 'markdown-it': '14.3.1' + # GHSA-r7fv-28h4-cvq7, GHSA-gfr2-rv44-r23c, GHSA-vfgh-jcmw-g37q: quadratic-time + # parsing, patched in 14.3.3. Reaches us via typedoc. + 'markdown-it': '>=14.3.3 <15' 'nanoid@3.3.11': '3.3.18' 'picomatch@2.3.1': '2.3.2' postcss: '8.5.23' source-map-js: '1.2.2' - vite: '8.0.16' + # GHSA-587h-7wmj-h5pm and siblings (launch-editor, fs.allow, custom + # middleware), patched in 8.1.6. Reaches us via vitest. + vite: '>=8.1.6 <9' + # GHSA-g7r4-m6w7-qqqr: dev-server file read on Windows, patched in 0.28.1. + # Reaches us via tsx, tsup and vite. + esbuild: '>=0.28.1 <0.29' + # GHSA-4x5r-pxfx-6jf8: file read via sourceMappingURL, patched in 7.29.6. + '@babel/core': '>=7.29.6 <8' # fast-uri/hono/ip-address floors below track advisories reached via # @modelcontextprotocol/sdk (see `pnpm why `); bump as new CVEs land. '@modelcontextprotocol/sdk': '>=1.31.0' @@ -42,7 +51,13 @@ overrides: path-to-regexp: '>=8.4.0' qs: '>=6.16.0' yaml: '>=2.8.3' - body-parser: '>=2.3.0' + # GHSA-27r3-jxmh-p828: compressed-body trailing-bytes denial of service, + # patched in 2.4.0. Reaches us via mppx > express. + body-parser: '>=2.4.0' + # GHSA-mrhx-c7xc-m3w5: memory exhaustion validating oversized constrained + # collections, patched in 4.6.6. Reaches us directly (packages/mpp) and via + # mppx > incur. + zod: '>=4.6.6 <5' # GHSA-jqcg-44mw-7w3h: forwarded-header denial of service, patched in 2.0.8. # Reaches us via mppx > express. proxy-addr: '>=2.0.8'