From 9e2a21d1749d8e4fa4f194f3f46f9bd84fb9cbd6 Mon Sep 17 00:00:00 2001 From: MarkFeder Date: Sun, 30 Aug 2026 19:01:29 +0200 Subject: [PATCH 1/5] feat(token-2022/transfer-hook/hello-world): add pinocchio example Ports the minimal transfer-hook example to Pinocchio, covering the three instructions the Anchor version exposes: - initialize: creates a Token-2022 mint naming this program as its transfer hook, by hand-building the TransferHookExtension(Initialize) and InitializeMint2 CPIs, then reading the extension back to confirm it. - initialize_extra_account_meta_list: creates the [b"extra-account-metas", mint] PDA holding the serialized, empty ExtraAccountMetaList that Token-2022 reads before every transfer. - Execute: the interface instruction Token-2022 CPIs during a transfer. It checks the source account's TransferHookAccount `transferring` flag, which is what stops the hook being invoked outside a transfer. The two interface discriminators are fixed by spl-transfer-hook-interface (the first eight bytes of sha256("spl-transfer-hook-interface:")), so they are matched before this example's own one-byte tag. There is no Pinocchio crate for Token-2022, so the mint and token-account TLV extension area is walked by a small bounds-checked reader rather than depending on spl-token-2022. LiteSVM tests cover mint creation and its decoded extension, the meta list bytes, a real transfer that asserts the hook logged from inside Token-2022's CPI, and a direct Execute call rejected with IsNotCurrentlyTransferring. --- Cargo.lock | 10 + Cargo.toml | 1 + README.md | 2 +- .../hello-world/pinocchio/cicd.sh | 8 + .../hello-world/pinocchio/package.json | 24 + .../hello-world/pinocchio/pnpm-lock.yaml | 2914 +++++++++++++++++ .../hello-world/pinocchio/program/Cargo.toml | 20 + .../pinocchio/program/src/error.rs | 18 + .../program/src/instructions/initialize.rs | 143 + .../initialize_extra_account_meta_list.rs | 81 + .../pinocchio/program/src/instructions/mod.rs | 24 + .../program/src/instructions/transfer_hook.rs | 59 + .../hello-world/pinocchio/program/src/lib.rs | 16 + .../pinocchio/program/src/processor.rs | 45 + .../pinocchio/program/src/token2022.rs | 56 + .../hello-world/pinocchio/tests/test.ts | 286 ++ .../hello-world/pinocchio/tsconfig.json | 15 + 17 files changed, 3721 insertions(+), 1 deletion(-) create mode 100644 tokens/token-2022/transfer-hook/hello-world/pinocchio/cicd.sh create mode 100644 tokens/token-2022/transfer-hook/hello-world/pinocchio/package.json create mode 100644 tokens/token-2022/transfer-hook/hello-world/pinocchio/pnpm-lock.yaml create mode 100644 tokens/token-2022/transfer-hook/hello-world/pinocchio/program/Cargo.toml create mode 100644 tokens/token-2022/transfer-hook/hello-world/pinocchio/program/src/error.rs create mode 100644 tokens/token-2022/transfer-hook/hello-world/pinocchio/program/src/instructions/initialize.rs create mode 100644 tokens/token-2022/transfer-hook/hello-world/pinocchio/program/src/instructions/initialize_extra_account_meta_list.rs create mode 100644 tokens/token-2022/transfer-hook/hello-world/pinocchio/program/src/instructions/mod.rs create mode 100644 tokens/token-2022/transfer-hook/hello-world/pinocchio/program/src/instructions/transfer_hook.rs create mode 100644 tokens/token-2022/transfer-hook/hello-world/pinocchio/program/src/lib.rs create mode 100644 tokens/token-2022/transfer-hook/hello-world/pinocchio/program/src/processor.rs create mode 100644 tokens/token-2022/transfer-hook/hello-world/pinocchio/program/src/token2022.rs create mode 100644 tokens/token-2022/transfer-hook/hello-world/pinocchio/tests/test.ts create mode 100644 tokens/token-2022/transfer-hook/hello-world/pinocchio/tsconfig.json diff --git a/Cargo.lock b/Cargo.lock index 2a87face1..bc9d91f08 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6046,6 +6046,16 @@ dependencies = [ "spl-token-2022-interface", ] +[[package]] +name = "token-2022-transfer-hook-hello-world-pinocchio-program" +version = "0.1.0" +dependencies = [ + "pinocchio", + "pinocchio-log", + "pinocchio-system", + "solana-address 2.6.1", +] + [[package]] name = "toml" version = "0.8.23" diff --git a/Cargo.toml b/Cargo.toml index f703dde94..cfd737ff5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -73,6 +73,7 @@ members = [ "tokens/token-2022/permanent-delegate/pinocchio/program", "tokens/token-2022/multiple-extensions/pinocchio/program", "tokens/token-2022/immutable-owner/pinocchio/program", + "tokens/token-2022/transfer-hook/hello-world/pinocchio/program", ] resolver = "2" diff --git a/README.md b/README.md index afbd9cdca..e90d02af6 100644 --- a/README.md +++ b/README.md @@ -262,7 +262,7 @@ Create tokens with an inbuilt transfer fee. A minimal transfer hook program that executes custom logic on every token transfer. -[anchor](./tokens/token-2022/transfer-hook/hello-world/anchor) +[anchor](./tokens/token-2022/transfer-hook/hello-world/anchor) [pinocchio](./tokens/token-2022/transfer-hook/hello-world/pinocchio) ### Transfer hook - counter diff --git a/tokens/token-2022/transfer-hook/hello-world/pinocchio/cicd.sh b/tokens/token-2022/transfer-hook/hello-world/pinocchio/cicd.sh new file mode 100644 index 000000000..e41db2140 --- /dev/null +++ b/tokens/token-2022/transfer-hook/hello-world/pinocchio/cicd.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +# This script is for quick building & deploying of the program. +# It also serves as a reference for the commands used for building & deploying Solana programs. +# Run this bad boy with "bash cicd.sh" or "./cicd.sh" + +cargo build-sbf --manifest-path=./program/Cargo.toml --sbf-out-dir=./program/target/so +solana program deploy ./program/target/so/*.so diff --git a/tokens/token-2022/transfer-hook/hello-world/pinocchio/package.json b/tokens/token-2022/transfer-hook/hello-world/pinocchio/package.json new file mode 100644 index 000000000..e872785e1 --- /dev/null +++ b/tokens/token-2022/transfer-hook/hello-world/pinocchio/package.json @@ -0,0 +1,24 @@ +{ + "type": "module", + "scripts": { + "test": "mocha --import=tsx -t 1000000 ./tests/test.ts", + "build-and-test": "cargo build-sbf --manifest-path=./program/Cargo.toml --sbf-out-dir=./tests/fixtures && pnpm test", + "build": "cargo build-sbf --manifest-path=./program/Cargo.toml --sbf-out-dir=./program/target/so", + "deploy": "solana program deploy ./program/target/so/*.so" + }, + "dependencies": { + "@solana-program/system": "^0.12.2", + "@solana-program/token-2022": "^0.12.0", + "@solana/kit": "^7.0.0", + "litesvm": "^1.3.0" + }, + "devDependencies": { + "@types/chai": "^5.2.3", + "@types/mocha": "^10.0.10", + "@types/node": "^26.1.0", + "chai": "^6.2.2", + "mocha": "^11.7.5", + "typescript": "^5.9.3", + "tsx": "^4.19.2" + } +} diff --git a/tokens/token-2022/transfer-hook/hello-world/pinocchio/pnpm-lock.yaml b/tokens/token-2022/transfer-hook/hello-world/pinocchio/pnpm-lock.yaml new file mode 100644 index 000000000..c3783c1f9 --- /dev/null +++ b/tokens/token-2022/transfer-hook/hello-world/pinocchio/pnpm-lock.yaml @@ -0,0 +1,2914 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@solana-program/system': + specifier: ^0.12.2 + version: 0.12.2(@solana/kit@7.1.1(typescript@5.9.3)) + '@solana-program/token-2022': + specifier: ^0.12.0 + version: 0.12.0(@solana/kit@7.1.1(typescript@5.9.3))(@solana/sysvars@8.2.0(typescript@5.9.3)) + '@solana/kit': + specifier: ^7.0.0 + version: 7.1.1(typescript@5.9.3) + litesvm: + specifier: ^1.3.0 + version: 1.4.1(typescript@5.9.3) + devDependencies: + '@types/chai': + specifier: ^5.2.3 + version: 5.2.3 + '@types/mocha': + specifier: ^10.0.10 + version: 10.0.10 + '@types/node': + specifier: ^26.1.0 + version: 26.4.0 + chai: + specifier: ^6.2.2 + version: 6.2.2 + mocha: + specifier: ^11.7.5 + version: 11.8.0 + tsx: + specifier: ^4.19.2 + version: 4.23.13 + typescript: + specifier: ^5.9.3 + version: 5.9.3 + +packages: + + '@esbuild/aix-ppc64@0.28.2': + resolution: {integrity: sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.28.2': + resolution: {integrity: sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.28.2': + resolution: {integrity: sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.28.2': + resolution: {integrity: sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.28.2': + resolution: {integrity: sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.28.2': + resolution: {integrity: sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.28.2': + resolution: {integrity: sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.28.2': + resolution: {integrity: sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.28.2': + resolution: {integrity: sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.28.2': + resolution: {integrity: sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.28.2': + resolution: {integrity: sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.28.2': + resolution: {integrity: sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.28.2': + resolution: {integrity: sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.28.2': + resolution: {integrity: sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.28.2': + resolution: {integrity: sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.28.2': + resolution: {integrity: sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.28.2': + resolution: {integrity: sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.28.2': + resolution: {integrity: sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.28.2': + resolution: {integrity: sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.28.2': + resolution: {integrity: sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.28.2': + resolution: {integrity: sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.28.2': + resolution: {integrity: sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.28.2': + resolution: {integrity: sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.28.2': + resolution: {integrity: sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.28.2': + resolution: {integrity: sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.28.2': + resolution: {integrity: sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@isaacs/cliui@8.0.2': + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + + '@noble/curves@1.9.7': + resolution: {integrity: sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==} + engines: {node: ^14.21.3 || >=16} + + '@noble/hashes@1.8.0': + resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==} + engines: {node: ^14.21.3 || >=16} + + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + + '@solana-program/system@0.12.2': + resolution: {integrity: sha512-MaBeOxlvTruQhA7UYkOb3hVTEHPPagOtd+PvTm6a8rGgvEAP0kD4BbC37NceOaR4ABNqdaCmD5OMVRKgrE6KAg==} + peerDependencies: + '@solana/kit': ^6.4.0 + + '@solana-program/system@0.14.0': + resolution: {integrity: sha512-Pjs2RINZHYmk/pqWNBCuQmfNjZT9woPJ/w7QkzzCSwcqcokbARtxsnIdgj4lJVxvr1DuxG8JGIbKnq6z1QRY6Q==} + peerDependencies: + '@solana/kit': ^8.0.0 + + '@solana-program/token-2022@0.12.0': + resolution: {integrity: sha512-SXkN6Epy9sC3OEELJLhc0hZtUijsAlR2Nb5gP6jcc0WVrtj5wEAmksWxF/yYrAB8AisJVgxvODkhIAnrd02DIw==} + engines: {node: '>=24.0.0'} + peerDependencies: + '@solana/kit': ^6.4.0 + '@solana/sysvars': ^5.0 + '@solana/zk-sdk': ^0.4.2 + peerDependenciesMeta: + '@solana/zk-sdk': + optional: true + + '@solana-program/token@0.16.0': + resolution: {integrity: sha512-VuFIu5vXsw1zwqls4/sGB88234oucmpuig553A33UnrbYnPZ8yXmqLYULBD92/k1pCGnMK+NMLWvsKzlZQ/1Kw==} + engines: {node: '>=24.0.0'} + peerDependencies: + '@solana/kit': ^8.0.0 + + '@solana-program/zk-elgamal-proof@0.2.0': + resolution: {integrity: sha512-znu1asnySKVp0VyOlfXCLZhpdWvyq/tJ7GRrX61Z6vyXXqJ/OMizv2BkgYL/VbzDKkFmUiYfiFwF3gDtZHv7VA==} + peerDependencies: + '@solana/kit': ^5.0 + + '@solana/accounts@7.1.1': + resolution: {integrity: sha512-7sy9VIFMdmu/7+2kVBRMU6mEvYx/DDjfam8DsBXbh+JszaTNZH3V8FutQYHRxrca3jxiumVfsy5USwKfVg8ElQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/accounts@8.2.0': + resolution: {integrity: sha512-An3BICrQJQ7jR5EIgXzYnaKyCE7+ZusW9xX8m6Vj7U2cKo8t6Y3PTQ+aMjEajwzsQfxEL8QnpClFC9hdoIu7MA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/addresses@7.1.1': + resolution: {integrity: sha512-/Tk2aTOT7UEcaJrdEcB3+SK09v5cZ/92NWqHBzEobxusTPNoeOFxa3MwV74Q1MgPecWdLz7TPreEhAKpcvV/vw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/addresses@8.2.0': + resolution: {integrity: sha512-7Okh8u7d3QrKu7ltJa3PASniUhasn1cdbcMQ/8gpGsmHQNCvdtAmvw18xSTdr4m62RJ/0cI/DtTVQyNwooeAXQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/assertions@7.1.1': + resolution: {integrity: sha512-tD07UKuw5i9Tw5xloVH+TUMrLzbHKixaB4DlGXumMEQU+JbYRPtFNqtMlrpVLuVM45nkbPfFp2Da0sXNRIqFHA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/assertions@8.2.0': + resolution: {integrity: sha512-izrnF8ZsviZDK0WCKl9ha5Ht4TNDHoU2QzMrPYOqkSkKkVh15p3MjTRXVFnM4CA+Xigtu8y8OPu2UnQNcAUVHQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/codecs-core@7.1.1': + resolution: {integrity: sha512-C1UOAQ7LH8RuCTfaij6hthTZeBlpp8GuD2g9Nag/xgiNKJGvAfVrcorb+kO/sufdYI8Lu+BiVvPeKOjQDQiKqg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/codecs-core@8.2.0': + resolution: {integrity: sha512-ORwzswFXbqNqlyVigogFIrn3Ge5cpDQkuMY0u3M40HBwHcC6a79uqM87DpoZypncKJDWA1DfJ/3w9hhTGumYAw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/codecs-data-structures@7.1.1': + resolution: {integrity: sha512-MO+wMAuaatAQ96N3HhTsd7Uno+79rJw88P+OiU2n+pHK/rZuyu1yB2j12veqK4jUNWPR0aOyCuZ4rB2idrDjpg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/codecs-data-structures@8.2.0': + resolution: {integrity: sha512-uq59oSAXM9QR+cO7R3JmSTxBiNNJnayVWz2VHBdhhCQS8DEmd6hhqY1RVmPTpFtE0Jix5MkRV3Bu5GTmf6Y66A==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/codecs-numbers@7.1.1': + resolution: {integrity: sha512-TWWrQq6Wp5Yf5bSc6RbxDDYCRUBBmRtRgjvUMHGp0P9K+4uFwxllRjSZFzBPHgXj3UTeZmFJdcoD271QhAgibg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/codecs-numbers@8.2.0': + resolution: {integrity: sha512-GTOYzyk0SxQJS7MAN9zsyax4RFUtQDYzkVcpRf0Zo7eOy2/hPfuih09VJL2YdLPBJBcg8satdAYBYxxC282PYQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/codecs-strings@7.1.1': + resolution: {integrity: sha512-6qWl+atG60D2LmP47GyGapQFhVsG1sVhVrEaM3lV09vwrGOMeOZARZ4ObaQ5m6uQmM04G+f8dY9d17nCMbGHGg==} + engines: {node: '>=20.18.0'} + peerDependencies: + fastestsmallesttextencoderdecoder: ^1.0.22 + typescript: '>=5.4.0' + peerDependenciesMeta: + fastestsmallesttextencoderdecoder: + optional: true + typescript: + optional: true + + '@solana/codecs-strings@8.2.0': + resolution: {integrity: sha512-Dt/+rJ6gmH/OcOtvrhm6CtbB9jtVOGMxcIXoi62eNXw39Z1kJyN1gkqTjzBSS8Xb+X5lfkL70GHE9EDBb1JmqA==} + engines: {node: '>=20.18.0'} + peerDependencies: + fastestsmallesttextencoderdecoder: ^1.0.22 + typescript: '>=5.4.0' + peerDependenciesMeta: + fastestsmallesttextencoderdecoder: + optional: true + typescript: + optional: true + + '@solana/codecs@7.1.1': + resolution: {integrity: sha512-1ZErMXzbbz7+jusem58dMO1haVWNlvFYKftc2dPhFu9MqlmZRfPS06GiZDjlLnD/6PHHBy7OKFMASoYw+fBAKg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/codecs@8.2.0': + resolution: {integrity: sha512-kn2esyzFznx6Pbb+8FUe3YNKYRZUB8H81pCiXSIe1+0WJ44lRhZHMo0s4L3FQMKhWHOnlV30sWeIg8taHLVW7g==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/errors@7.1.1': + resolution: {integrity: sha512-q35qck8rBnNvJlPU00mnHEQm7gWvghzYz8khqVoLhjgodTzGp46VqnIOyI1LXOAF6XDal58bMNDO980MQgq8yw==} + engines: {node: '>=20.18.0'} + hasBin: true + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/errors@8.2.0': + resolution: {integrity: sha512-BXc9mafl3SOnRL542jY02ezBSXHgqQOUCzREN/vvh1ASUPrUB3iorOEc62cSxFdDU4aDVMcugowJawmVNTXXSg==} + engines: {node: '>=20.18.0'} + hasBin: true + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/fast-stable-stringify@7.1.1': + resolution: {integrity: sha512-eVxOeAXYVBIWOIRfGwvuGQ6gPetQiiiOqSCK0xjwQo/yjXNVlSbpF6wLtQRnd3lbYkWsKdeV99FYe9cVY/g7/Q==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/fast-stable-stringify@8.2.0': + resolution: {integrity: sha512-OND76Qsng/fiTVSUvaNZFv0WKEULlwcGRtgeIE2keA2xYoHYNTSoD6mxv4iWANfeDo4EH7D/HnOwnGEFXMjr9w==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/fixed-points@7.1.1': + resolution: {integrity: sha512-qPj/V7kcFG/P0kuEa1U529+5L6mbkMwRIwvYBTDgBqPOt6wOdk9/c7Qn2VUQgSV0HgCXWxdHUdwaxBrYqO2ibg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/fixed-points@8.2.0': + resolution: {integrity: sha512-w19JKErcbbENZzw4B+oBGwJXVKMIOi8TC7WxBawmpuv0XJSk6LP6surosg+XeoBHhtEsVCNHDtizi0mAS6OmMw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/functional@7.1.1': + resolution: {integrity: sha512-AnFohvUHGrqAu3kTxxC0rZyU4JddA08hOUZ1/DT9XogCZWetBpNJktX9uNuXQe+sN4FKTX2MfL//iBFBAsxtDA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/functional@8.2.0': + resolution: {integrity: sha512-+oTPl9yRZBbppUZU8qs4eu93iWPvs4Ij+HELPHISxLFo/cuG2YZGTDcWBVEzc8XEw0DUwwBOvou/wP7v1SnH+A==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/instruction-plans@7.1.1': + resolution: {integrity: sha512-KQGpsjeDflMcbKCdcF4KZVHcotYMS94DveRs0ZiBOsxb45dgkYrFmQ6ExJ/2exUOVF/rlp73knAP5ACrPMIAzA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/instruction-plans@8.2.0': + resolution: {integrity: sha512-DDVHBAPifG3Q0s5e2hiBbfvrruLb3AhumTupDK+3f3f7MDc0Dth6rX054HtIINloqbFIw15f6/A3Z4VTh74CTg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/instructions@7.1.1': + resolution: {integrity: sha512-VxMpJI++RTwaqSBLIP1GTjOPLtlYOqxOJ93ug6DlSdu9jku8M/or77DiXDUi62VmEh3bbsECR646vTJXUaPArw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/instructions@8.2.0': + resolution: {integrity: sha512-SFts84wW6hDXGSrLK5spl8nbKxKns2aR+S2ar0Zi3I0bl007heyoO7UKyxAoUvhfhObIfEIMuy2/qLoo6vDcjQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/keys@7.1.1': + resolution: {integrity: sha512-Rx+vzWAXUa/Ko7W6wG1HOG9B3nQFZ5dALz113WoAmBZf7iQvaLG7U4ECDM/ydR+Nbdy6wYww7zQKRIye+1d+Nw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/keys@8.2.0': + resolution: {integrity: sha512-DezFZ0/ya98nILq+eSeq9fu9onVfqQYb7mtuDctdWxY1QFJvix562zkkFuFqnjOLL7XMEpdVPMxxQOzZ33wGCg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/kit@7.1.1': + resolution: {integrity: sha512-By3kv5d8fIMr2SPmvI41hBXUwn0XuDu2MC8B7anaLHtY8MENTKhjg8sSfybf/RTH3387ErxhxmrAijTiHqTy/g==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/kit@8.2.0': + resolution: {integrity: sha512-1BfmnYmWe17u3RRX3HuNxjWkr2/n9Bai+yIG/XjMpgviobF3n8zsisZBJHPH2uORqvjkTFnOqGXoEQC8vUZHzw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/nominal-types@7.1.1': + resolution: {integrity: sha512-do4rmmOlSplVYN92zV6nROJxkiRn0c7juoH1lka2Pmq+cAC3QhQXKYAwWffTFYDJJDO9qCOh00uv2hhSZi6RDw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/nominal-types@8.2.0': + resolution: {integrity: sha512-iuDE6ewgT7LJOSVC6UK4HR6n8INujujbglYVVFWNK/xWKi5p1y8JCOEEWAl/htK26LhLC51A1nMNfmBmTjP3ZQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/offchain-messages@7.1.1': + resolution: {integrity: sha512-Py0/8HaIF0y+KSXHAWdQYDdZlGNoaqOZonTFuGKyDsrkgvod3wRc0cpZ5I/D/Rei4tVpvjNUfCXLpyoiJAZ7kg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/offchain-messages@8.2.0': + resolution: {integrity: sha512-yXfVtK1VoQ/Eyz2jH/1+avixhYcpCPkGkXuiXxA3Vf73WCvniC8mNVQ5ppsV+OqCNw62mxaFMmNiVgiAQapKuw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/options@7.1.1': + resolution: {integrity: sha512-iuPpfMbnRFjC4IoAIpKNA9UpizomxjW0E3F1LxUYQHXm1vCoF78kThp4qqgx2V3DmDFbhXGtXGSJPwmDdpLoBg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/options@8.2.0': + resolution: {integrity: sha512-b3//UzZe/uBaIpw4fT/nvCOghh5IHoNkW7FCMA/nzvQ48A16n8qpLki9/+lLHi0V0o7/Jz5Sof0UYc0aSf1Dig==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/plugin-core@7.1.1': + resolution: {integrity: sha512-35h7+QssfnT9Rwq5spUvdGc41WtTVWzJUCbiwvnUHtVwm3z96xSPwj765UtX/enfrcRHJRTDvej2ZjsvO1aeuQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/plugin-core@8.2.0': + resolution: {integrity: sha512-V7oSIhYXbUzjd5LUY4tbSUnyBka1hmULPFKuqxNzYxeY4eLI7S8GmTOg7xg6tOC0bJ+HLPvv64asuMXAn/PklQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/plugin-interfaces@7.1.1': + resolution: {integrity: sha512-2SHkGiftGmxg5xA5esxbwiY5wf+BOUsJG5rxD64/SHadUMaN3L0SDUSJfAXETJq5dCmVWxWGGPf2yVox4RIfdA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/plugin-interfaces@8.2.0': + resolution: {integrity: sha512-goOhGI493Fq+xhZ8JKl9/FDVFd0SJdkv5Lh0L2ubqekzUiGRCvHNwgXL8nVS7fso2UxIssDQmYKwXvubfhBVhw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/program-client-core@7.1.1': + resolution: {integrity: sha512-zoMq8Qg6psj6tFYpA35xKhSrF/LpdiVflV6nKohxZg3ocwtRqRhQfbY8/mjCA9EfH8vqvsn5il5CnxALRqmJJA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/program-client-core@8.2.0': + resolution: {integrity: sha512-miQ7qKW0d0etaa2YAehGU3heV5Y4ip5BBCwZXb/yg8yWndTt4d4E+8z+5Q/oS5kOuFraOFYr+Uev7SQKngNXBg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/programs@7.1.1': + resolution: {integrity: sha512-nWpJKDBxj+cRpzH+lzdp+ztEm6MAothts56s7PIPFIKJe3zGRUpske0G3jIVHOGvtzCgQtmZUMCS1uBRiDRKDQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/programs@8.2.0': + resolution: {integrity: sha512-yttl6ps7G9vM83pdfekyregTIqmRThFpdcrCIZ3y2qOLZ63KVxVMhNJ8kn8FrX3MyWh5rr/hTWdWKc4/U12Epg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/promises@7.1.1': + resolution: {integrity: sha512-d3lhCfiFwiVyTRR6zhy1lcjDIh+l0a5gp1WPe64Vfa2gP0myC8P5C1Tknfjrp4d97DF3uBPqKAb5vV8hahNcNA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/promises@8.2.0': + resolution: {integrity: sha512-i33ll+en6/Qcjw10gPeikCmU687W1pQNZPxirEuRWO/+PhE2qDQ9ZODgEakVi/1k+vSwL8sK941qfWig+3D0dQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-api@7.1.1': + resolution: {integrity: sha512-ELGIqNbz8apeAxCLdD1PEPAnu6KtgHmWvUbH4VqqNg2jgWquyUOfTI5rblvdflx2Hcb7GK05w8/iiUaknOQKnw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-api@8.2.0': + resolution: {integrity: sha512-lGvk1xeOo4cbypuD/5AAkJPHv5E3g7lqbzRIxZhsQPBkK+knVuEb7e3UncOnjuWkijZoFiB/k+Rfk83gmlhdpg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-parsed-types@7.1.1': + resolution: {integrity: sha512-DiQSj2rNnhOKOTs6YDjQ2y4KuOkv8lh6moLFiQnY0+TvanJrGrQjxLSrHdCUQxymQcUxzrraZL9k6vxNzId4gw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-parsed-types@8.2.0': + resolution: {integrity: sha512-JJ4BfUlX8eCIUh3zm8jTkHkNLf6HyY9UjJmi4GPicFPJZ5MXSUeh42eaSxvHszXUoS7u9V30kTt1hznwfF5fqA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-spec-types@7.1.1': + resolution: {integrity: sha512-FDDgXfAPfq28sQNnGhZr/+2kp5QTTcNZ5m/Q9y9Jrlux6brdPsbf9Sh1Q/lgz7i76arzNW/rzRY125RzqGWANg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-spec-types@8.2.0': + resolution: {integrity: sha512-pKOezoP0vuVwyjUKcS4Ewl3Mm/owv/16n7RocqFC3nx94qtk5FpSOAtielUHzBQ3JUgRLJrSKonw2yWxqgtVFg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-spec@7.1.1': + resolution: {integrity: sha512-1FwhgL18qasRYlWffdBNIUoxQyGLzdh3YMQW3y33M61vk/q1ldEGJRypV9B/SrXmxwqDiUbQ+m+zgainCTp1ZA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-spec@8.2.0': + resolution: {integrity: sha512-fR0hv/NP3K4WNePK9+97GYrDjzoN7kF0hlffRlSygksAC0FKvtKQ5lPBMg0ptWtswInp8Kk7Cz1zTCf6S+wLUQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-subscriptions-api@7.1.1': + resolution: {integrity: sha512-QTiQHmw2I/+fzeYsqII1guASiZskS7KZwPCI+6Arfk6Hxo9hBH8APuIu6uS8beSlVfnBCoOMybVDsnPF88fAoQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-subscriptions-api@8.2.0': + resolution: {integrity: sha512-37UHtjFmBUagtRw9NeWViTqSJlExyuI2j88m3jJSw9c6WRw7lLzUJIRGA51ArYyhAyhtAoGjXpUZiODKSE9lEw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-subscriptions-channel-websocket@7.1.1': + resolution: {integrity: sha512-DRakQwjJsvbLDMDafMC9hM82YotUwSnrzqUDsrm6+e4YpKvzjXCyWlQ9kDJtrYeAA15sNVRpfs4L9Y7SoiWgrw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-subscriptions-channel-websocket@8.2.0': + resolution: {integrity: sha512-R9pk8Lq030M1+bAz6e2qKv6ldGLmICFYJOaLxVifyDE4VBb1BGV3Tt1VTAaFIfHyYucmFmxGRmPFmedA3Kysqw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-subscriptions-spec@7.1.1': + resolution: {integrity: sha512-yrqd+fV2Ae4hkzXX42aKRmTrz3FwvzKqO4h0ahs88dzSvXpy8l6Svu1k+uRgMlZ64g2P83jfQW+3Pj5fBoxmdw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-subscriptions-spec@8.2.0': + resolution: {integrity: sha512-ajcncAnQ7XzE85MZ8uajjO9E7NyLwLWFVUYG+y82vb04ZWFRN3DrMswIC4T5m14OkU3RY/Z2WGxC9nT1W4wPWw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-subscriptions@7.1.1': + resolution: {integrity: sha512-5BaCgzPnf9WSEXBdASnM7iuPWtdrXKtG16qVTfm+9icLHDAkv2y62XF6XMSQQllH2k1RvLH1yOryZazAbaIyHA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-subscriptions@8.2.0': + resolution: {integrity: sha512-pHf/RiDqIHeGp2blseYRVjzWz4WUAY/5vkOya+BQhjx+7Odr/J19G3ZVDwExgtU95UhCDL9gVHPyAgKr0mNcUg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-transformers@7.1.1': + resolution: {integrity: sha512-k8a/JZFso/nvPBgurOGJ/ZC6sXCtYE3lCvTj95i29pl45C4SgjdetJrAH/pWEEhQXcxaJs7OLBGmCh2enazlJw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-transformers@8.2.0': + resolution: {integrity: sha512-tiMdJ9ZRgqANBNxlXK7OSDbwixAy7K1MzowzO7vNdlJbV+0WN0Lm/X5hEhKnlU42AD+clC6t9qZjVbg7BhQrqw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-transport-http@7.1.1': + resolution: {integrity: sha512-Tljuh/sSkKMHrTqdYNaguUOkZ0T+Oj4+yHsUjKAzRsyffNLa67jx9gd5CtGfz3tpBpxDLVdNvdIaZgkhFwXk9g==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-transport-http@8.2.0': + resolution: {integrity: sha512-eOkgv52ZSMFLYNQaCsvxmPciZeXplWaPjbEcl9iZkGOAp3B2bO6KyMg8trEjaZNfcLC15+CpXMOZpMArXXSBCg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-types@7.1.1': + resolution: {integrity: sha512-yHlSUWgynaaqevuqipGhhcZnmFVNs+F6KIlbUZ0kQY6NMVtaSzx5AQrtQjbtAQzNRsRTDYkKuQg8nOruiDoseQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-types@8.2.0': + resolution: {integrity: sha512-rGF2vB8Bk0G2DYNxgEbDlANk+KirQGHVS1qRLxsi6OxACrgsSrGqrp0Onb5J8HLRMTEF+QrbbORDz9TQ5Q71fQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc@7.1.1': + resolution: {integrity: sha512-yXEzCrLrWb1m5QqAJEGodJ9cqu5QiwfirSZTUWiMg1JtUl4uXOm1sqWQVLrwBz/+ctvtZTvG8+bQQAemVQiqPA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc@8.2.0': + resolution: {integrity: sha512-Of/2KqDf728HxKzJlwlZRvRSrgpHoDAg5+t/3RwdXWBoRQ1r3FXqwBXOrBT2g47w+fUy1iJcy5XZ7LXnXBXPIg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/signers@7.1.1': + resolution: {integrity: sha512-UfWYnAglm21q5hS3Op1bU5mYiWfx0VesovZcIur0uYPc3EJlfBVikl8pf745x+bB77xG6lIzNbb+99t48SQbkg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/signers@8.2.0': + resolution: {integrity: sha512-wfLiDhtPMnE9Mn8IeSAJ0RMfCyHUqeNZllFLfgDY3RUsCf5s9EgMC5U+HNSvtEWJ8ABGWWR5nYyWMXTWiMeuPA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/subscribable@7.1.1': + resolution: {integrity: sha512-l4Wzc2L+7WQPeC/kaCiia1aaUY/SJJdrNHnLibKchS2pb7YbF7J2OygsweHXliWCVpG0jZwcvIVpusgygbZQLw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/subscribable@8.2.0': + resolution: {integrity: sha512-ATJBeJkaCUIxU3JWUcgfOjnOM3nn9qDfTigEkr0Cp3xFzIHnIVwis3W4Hcc/de1z0uvOXQOIYroahDr8H+djOg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/sysvars@7.1.1': + resolution: {integrity: sha512-EscE/HKbBRKedG6AtQ0t9LOX87bw409viferac5YSuvuDxtZvbMpCCJs89uEQPVpgvHtjMJhfsjEwMK97uG9pA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/sysvars@8.2.0': + resolution: {integrity: sha512-kwhOwBfUvUGuGGGnwTGHtNVQ02O3YCfXpp4xwUhe6bjUyp9M9wEmf70up6I9x2D4uB1nHaZRfco1CXfxhcH8sg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/transaction-confirmation@7.1.1': + resolution: {integrity: sha512-Kb3V5smmMbvdft/Z/Iu9MlsF+i44f3GLK8c8TVu0+yHo41rF7OeTnOvlQ+uw1NpCfOto4GgPMFDXklIiKdauuA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/transaction-confirmation@8.2.0': + resolution: {integrity: sha512-3L1LlMQ00l2kb3pcejvQ7vMKzyFayFhc6PqvZyh3M0/FNPfsc4z46yUf35I79SI6cuFWy2VkzA+a2ylOuCNC7w==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/transaction-introspection@7.1.1': + resolution: {integrity: sha512-o0f/wbwmgqRSqzr+RtCG8xZ5zTMVxnYv8LBmcDDCYvTeDPEF0EfHN8Oe28c7grQsXCIeaE+zXZ2p40lkTGZy4g==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/transaction-introspection@8.2.0': + resolution: {integrity: sha512-unha6ugKrZa1TcB5Slnxisa/uQC56fyYi7BDvfCVI60OLEowtOTTvmJMKe35ETMzbimjBEPE/B5EgbydOHVBnQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/transaction-messages@7.1.1': + resolution: {integrity: sha512-UBgd/TU0c8blrYDC9sD9P+wgmOOEK4OdODxD8CxB7oumN4ZAENv20u0AdZuvu1n4OwWwc1ikhtKjwg18e4wTIg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/transaction-messages@8.2.0': + resolution: {integrity: sha512-+0U4iR/WRb8UiBXRhJJUY0+BmAOv+bQj7fifUF6o7x/IPg/K2Y4CmH4m7dOT2yhcg0KDzZPkXidXLm6saBX0Hw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/transactions@7.1.1': + resolution: {integrity: sha512-jop8y4+xiDJlocRLxqN++33Z5PDTe72HwmtgGrcIuGB4zq7U/lUX0uZM1JVcs9d3lJ3wBy2CcLTCyoYb78Swhg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/transactions@8.2.0': + resolution: {integrity: sha512-WfbzFTf2BvpW14OIOin/9Mj29XE5GJVORAnziDK+GEiTPnruNzNkHBrd2kt/ACg12dh12kmutDj5WI3pzrN3Bw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@types/chai@5.2.3': + resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} + + '@types/deep-eql@4.0.2': + resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + + '@types/mocha@10.0.10': + resolution: {integrity: sha512-xPyYSz1cMPnJQhl0CLMH68j3gprKZaTjG3s5Vi+fDgx+uhG9NOXwbVt52eFS8ECyXhyKcjDLCBEqBExKuiZb7Q==} + + '@types/node@26.4.0': + resolution: {integrity: sha512-faiGnoIrLH/V8cibOMEAZ8pMw6oXqSukl29ra4mN8GdaB2ZewzeaLj+INpV5N+Z1eKWzY+IzaIZH2EIR6YZRNQ==} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-regex@6.3.0: + resolution: {integrity: sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==} + engines: {node: '>=12'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + ansi-styles@6.2.3: + resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} + engines: {node: '>=12'} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + brace-expansion@2.1.4: + resolution: {integrity: sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==} + + browser-stdout@1.3.1: + resolution: {integrity: sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==} + + camelcase@6.3.0: + resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} + engines: {node: '>=10'} + + chai@6.2.2: + resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} + engines: {node: '>=18'} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + chalk@5.6.2: + resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + + chokidar@4.0.3: + resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} + engines: {node: '>= 14.16.0'} + + cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + commander@15.0.0: + resolution: {integrity: sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==} + engines: {node: '>=22.12.0'} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decamelize@4.0.0: + resolution: {integrity: sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==} + engines: {node: '>=10'} + + diff@7.0.0: + resolution: {integrity: sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==} + engines: {node: '>=0.3.1'} + + eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + + esbuild@0.28.2: + resolution: {integrity: sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==} + engines: {node: '>=18'} + hasBin: true + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + flat@5.0.2: + resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==} + hasBin: true + + foreground-child@3.3.1: + resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} + engines: {node: '>=14'} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + + glob@10.5.0: + resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me + hasBin: true + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + he@1.2.0: + resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} + hasBin: true + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-path-inside@3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} + engines: {node: '>=8'} + + is-plain-obj@2.1.0: + resolution: {integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==} + engines: {node: '>=8'} + + is-unicode-supported@0.1.0: + resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} + engines: {node: '>=10'} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + jackspeak@3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + + js-yaml@4.3.2: + resolution: {integrity: sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==} + hasBin: true + + litesvm-darwin-arm64@1.4.1: + resolution: {integrity: sha512-6dofWLOxtknSL0W6N9W3f/kdnitsJ3xR0oE1W37CLcfd5kX4qCMVbaejZWJkLo4G2JzAk+hFZi965Z2OPyJACg==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [darwin] + + litesvm-darwin-x64@1.4.1: + resolution: {integrity: sha512-Rjyg6SfnSKAO5/vMpnZpIHTcBWEUzjFj/GshXwzdyiWorrpC0poQjK3OJ9RJneJW2YDd+oUsGZCfwAplTXPGfg==} + engines: {node: '>= 20'} + cpu: [x64] + os: [darwin] + + litesvm-linux-arm64-gnu@1.4.1: + resolution: {integrity: sha512-hyL/tcuFisAwNEwVzDGjtDRuLYDc+8PoX9QZU/M46vsLrdU2WCBU3g4WdV5z0z1nPl16TzcHVboqydyBy3ImFQ==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + litesvm-linux-arm64-musl@1.4.1: + resolution: {integrity: sha512-Folc4nWAXwkWvwK5iqf3C74eNAPRERg8Yn2QGVW+6pMgCXtaQt77PuIB9m32mLo+W+LZxiU+t3et0ZiFEm4YgQ==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + libc: [musl] + + litesvm-linux-x64-gnu@1.4.1: + resolution: {integrity: sha512-sAKax22lAMS0DpWQcT6ICt8vs6phEjRJXT84LhhftnlNkcU03b0RJziFDr34LUTrkY5SMi/uqZEy0T86Xokg+w==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + libc: [glibc] + + litesvm-linux-x64-musl@1.4.1: + resolution: {integrity: sha512-kKsOVhF7o8/sMiP6mgZCoIYr7zWEzwOBQdC0WrWp29JvOJpKOOgz3jioFdgWv/LnSYfkbJ+wZNWI8tMhAkmNOw==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + libc: [musl] + + litesvm@1.4.1: + resolution: {integrity: sha512-SGMdN6c44m5Deo27nZX7GIn42e/OlfQ4jIv0JIVxR3F5vU8ZbbjsLRGUj3b/r5jCITyN22u14JnuP+mhDyNLlg==} + engines: {node: '>= 20'} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + log-symbols@4.1.0: + resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} + engines: {node: '>=10'} + + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + + minimatch@9.0.9: + resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} + engines: {node: '>=16 || 14 >=14.17'} + + minipass@7.1.3: + resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} + engines: {node: '>=16 || 14 >=14.17'} + + mocha@11.8.0: + resolution: {integrity: sha512-VyCeUdGN3A9lmCTTgG4yuvY9ixxaDk+xt2R/7/+1AP6EqNG+G9OKkzBwhVtVYoNX8YsxNSgAl8mOv3IAeOpFbw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + hasBin: true + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + randombytes@2.1.0: + resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} + + readdirp@4.1.2: + resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} + engines: {node: '>= 14.18.0'} + + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + serialize-javascript@6.0.2: + resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-ansi@7.2.0: + resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} + engines: {node: '>=12'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + + tsx@4.23.13: + resolution: {integrity: sha512-BL5MGkRln6aDYhb0xbQlEAGw743BaZYWdbWtdJOBriYJboKgUUYCadFp2/FpBBZquBC/ezNBn7wMMPx7FDZUDw==} + engines: {node: '>=18.0.0'} + hasBin: true + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + undici-types@8.10.0: + resolution: {integrity: sha512-ibvdovq3nCFs8Msrd95BW+zUOq+aOVbT+wpHUoPWhztbHEoPc6oof51iFDB6Es8lTKvNvVW9jNSAB8dwrKTMGg==} + + undici-types@8.3.0: + resolution: {integrity: sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + workerpool@9.3.4: + resolution: {integrity: sha512-TmPRQYYSAnnDiEB0P/Ytip7bFGvqnSU6I2BcuSw7Hx+JSg/DsUi5ebYfc8GYaSdpuvOcEs6dXxPurOYpe9QFwg==} + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + + ws@8.21.3: + resolution: {integrity: sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + + yargs-unparser@2.0.0: + resolution: {integrity: sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==} + engines: {node: '>=10'} + + yargs@17.7.3: + resolution: {integrity: sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==} + engines: {node: '>=12'} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + +snapshots: + + '@esbuild/aix-ppc64@0.28.2': + optional: true + + '@esbuild/android-arm64@0.28.2': + optional: true + + '@esbuild/android-arm@0.28.2': + optional: true + + '@esbuild/android-x64@0.28.2': + optional: true + + '@esbuild/darwin-arm64@0.28.2': + optional: true + + '@esbuild/darwin-x64@0.28.2': + optional: true + + '@esbuild/freebsd-arm64@0.28.2': + optional: true + + '@esbuild/freebsd-x64@0.28.2': + optional: true + + '@esbuild/linux-arm64@0.28.2': + optional: true + + '@esbuild/linux-arm@0.28.2': + optional: true + + '@esbuild/linux-ia32@0.28.2': + optional: true + + '@esbuild/linux-loong64@0.28.2': + optional: true + + '@esbuild/linux-mips64el@0.28.2': + optional: true + + '@esbuild/linux-ppc64@0.28.2': + optional: true + + '@esbuild/linux-riscv64@0.28.2': + optional: true + + '@esbuild/linux-s390x@0.28.2': + optional: true + + '@esbuild/linux-x64@0.28.2': + optional: true + + '@esbuild/netbsd-arm64@0.28.2': + optional: true + + '@esbuild/netbsd-x64@0.28.2': + optional: true + + '@esbuild/openbsd-arm64@0.28.2': + optional: true + + '@esbuild/openbsd-x64@0.28.2': + optional: true + + '@esbuild/openharmony-arm64@0.28.2': + optional: true + + '@esbuild/sunos-x64@0.28.2': + optional: true + + '@esbuild/win32-arm64@0.28.2': + optional: true + + '@esbuild/win32-ia32@0.28.2': + optional: true + + '@esbuild/win32-x64@0.28.2': + optional: true + + '@isaacs/cliui@8.0.2': + dependencies: + string-width: 5.1.2 + string-width-cjs: string-width@4.2.3 + strip-ansi: 7.2.0 + strip-ansi-cjs: strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: wrap-ansi@7.0.0 + + '@noble/curves@1.9.7': + dependencies: + '@noble/hashes': 1.8.0 + + '@noble/hashes@1.8.0': {} + + '@pkgjs/parseargs@0.11.0': + optional: true + + '@solana-program/system@0.12.2(@solana/kit@7.1.1(typescript@5.9.3))': + dependencies: + '@solana/kit': 7.1.1(typescript@5.9.3) + + '@solana-program/system@0.14.0(@solana/kit@8.2.0(typescript@5.9.3))': + dependencies: + '@solana/kit': 8.2.0(typescript@5.9.3) + + '@solana-program/token-2022@0.12.0(@solana/kit@7.1.1(typescript@5.9.3))(@solana/sysvars@8.2.0(typescript@5.9.3))': + dependencies: + '@noble/curves': 1.9.7 + '@solana-program/zk-elgamal-proof': 0.2.0(@solana/kit@7.1.1(typescript@5.9.3)) + '@solana/kit': 7.1.1(typescript@5.9.3) + '@solana/sysvars': 8.2.0(typescript@5.9.3) + + '@solana-program/token@0.16.0(@solana/kit@8.2.0(typescript@5.9.3))': + dependencies: + '@solana-program/system': 0.14.0(@solana/kit@8.2.0(typescript@5.9.3)) + '@solana/kit': 8.2.0(typescript@5.9.3) + + '@solana-program/zk-elgamal-proof@0.2.0(@solana/kit@7.1.1(typescript@5.9.3))': + dependencies: + '@solana-program/system': 0.12.2(@solana/kit@7.1.1(typescript@5.9.3)) + '@solana/kit': 7.1.1(typescript@5.9.3) + + '@solana/accounts@7.1.1(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/errors': 7.1.1(typescript@5.9.3) + '@solana/rpc-spec': 7.1.1(typescript@5.9.3) + '@solana/rpc-types': 7.1.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/accounts@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.2.0(typescript@5.9.3) + '@solana/codecs-core': 8.2.0(typescript@5.9.3) + '@solana/codecs-strings': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/rpc-spec': 8.2.0(typescript@5.9.3) + '@solana/rpc-types': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/addresses@7.1.1(typescript@5.9.3)': + dependencies: + '@solana/assertions': 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/errors': 7.1.1(typescript@5.9.3) + '@solana/nominal-types': 7.1.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/addresses@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/assertions': 8.2.0(typescript@5.9.3) + '@solana/codecs-core': 8.2.0(typescript@5.9.3) + '@solana/codecs-strings': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/nominal-types': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/assertions@7.1.1(typescript@5.9.3)': + dependencies: + '@solana/errors': 7.1.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/assertions@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/codecs-core@7.1.1(typescript@5.9.3)': + dependencies: + '@solana/errors': 7.1.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/codecs-core@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/codecs-data-structures@7.1.1(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 7.1.1(typescript@5.9.3) + '@solana/codecs-numbers': 7.1.1(typescript@5.9.3) + '@solana/errors': 7.1.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/codecs-data-structures@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 8.2.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/codecs-numbers@7.1.1(typescript@5.9.3)': + dependencies: + '@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/codecs-numbers@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/codecs-strings@7.1.1(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 7.1.1(typescript@5.9.3) + '@solana/codecs-numbers': 7.1.1(typescript@5.9.3) + '@solana/errors': 7.1.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/codecs-strings@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 8.2.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/codecs@7.1.1(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 7.1.1(typescript@5.9.3) + '@solana/codecs-data-structures': 7.1.1(typescript@5.9.3) + '@solana/codecs-numbers': 7.1.1(typescript@5.9.3) + '@solana/codecs-strings': 7.1.1(typescript@5.9.3) + '@solana/fixed-points': 7.1.1(typescript@5.9.3) + '@solana/options': 7.1.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/codecs@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 8.2.0(typescript@5.9.3) + '@solana/codecs-data-structures': 8.2.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.2.0(typescript@5.9.3) + '@solana/codecs-strings': 8.2.0(typescript@5.9.3) + '@solana/fixed-points': 8.2.0(typescript@5.9.3) + '@solana/options': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/errors@7.1.1(typescript@5.9.3)': + dependencies: + chalk: 5.6.2 + commander: 15.0.0 + optionalDependencies: + typescript: 5.9.3 + + '@solana/errors@8.2.0(typescript@5.9.3)': + dependencies: + chalk: 5.6.2 + commander: 15.0.0 + optionalDependencies: + typescript: 5.9.3 + + '@solana/fast-stable-stringify@7.1.1(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + + '@solana/fast-stable-stringify@8.2.0(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + + '@solana/fixed-points@7.1.1(typescript@5.9.3)': + dependencies: + '@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@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/functional@7.1.1(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + + '@solana/functional@8.2.0(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + + '@solana/instruction-plans@7.1.1(typescript@5.9.3)': + dependencies: + '@solana/errors': 7.1.1(typescript@5.9.3) + '@solana/instructions': 7.1.1(typescript@5.9.3) + '@solana/keys': 7.1.1(typescript@5.9.3) + '@solana/promises': 7.1.1(typescript@5.9.3) + '@solana/transaction-messages': 7.1.1(typescript@5.9.3) + '@solana/transactions': 7.1.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/instruction-plans@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/instructions': 8.2.0(typescript@5.9.3) + '@solana/keys': 8.2.0(typescript@5.9.3) + '@solana/promises': 8.2.0(typescript@5.9.3) + '@solana/transaction-messages': 8.2.0(typescript@5.9.3) + '@solana/transactions': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/instructions@7.1.1(typescript@5.9.3)': + dependencies: + '@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/instructions@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/keys@7.1.1(typescript@5.9.3)': + dependencies: + '@solana/assertions': 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/errors': 7.1.1(typescript@5.9.3) + '@solana/nominal-types': 7.1.1(typescript@5.9.3) + '@solana/promises': 7.1.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/keys@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/assertions': 8.2.0(typescript@5.9.3) + '@solana/codecs-core': 8.2.0(typescript@5.9.3) + '@solana/codecs-strings': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/nominal-types': 8.2.0(typescript@5.9.3) + '@solana/promises': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/kit@7.1.1(typescript@5.9.3)': + dependencies: + '@solana/accounts': 7.1.1(typescript@5.9.3) + '@solana/addresses': 7.1.1(typescript@5.9.3) + '@solana/codecs': 7.1.1(typescript@5.9.3) + '@solana/errors': 7.1.1(typescript@5.9.3) + '@solana/functional': 7.1.1(typescript@5.9.3) + '@solana/instruction-plans': 7.1.1(typescript@5.9.3) + '@solana/instructions': 7.1.1(typescript@5.9.3) + '@solana/keys': 7.1.1(typescript@5.9.3) + '@solana/offchain-messages': 7.1.1(typescript@5.9.3) + '@solana/plugin-core': 7.1.1(typescript@5.9.3) + '@solana/plugin-interfaces': 7.1.1(typescript@5.9.3) + '@solana/program-client-core': 7.1.1(typescript@5.9.3) + '@solana/programs': 7.1.1(typescript@5.9.3) + '@solana/promises': 7.1.1(typescript@5.9.3) + '@solana/rpc': 7.1.1(typescript@5.9.3) + '@solana/rpc-api': 7.1.1(typescript@5.9.3) + '@solana/rpc-parsed-types': 7.1.1(typescript@5.9.3) + '@solana/rpc-spec-types': 7.1.1(typescript@5.9.3) + '@solana/rpc-subscriptions': 7.1.1(typescript@5.9.3) + '@solana/rpc-types': 7.1.1(typescript@5.9.3) + '@solana/signers': 7.1.1(typescript@5.9.3) + '@solana/subscribable': 7.1.1(typescript@5.9.3) + '@solana/sysvars': 7.1.1(typescript@5.9.3) + '@solana/transaction-confirmation': 7.1.1(typescript@5.9.3) + '@solana/transaction-introspection': 7.1.1(typescript@5.9.3) + '@solana/transaction-messages': 7.1.1(typescript@5.9.3) + '@solana/transactions': 7.1.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - bufferutil + - fastestsmallesttextencoderdecoder + - utf-8-validate + + '@solana/kit@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/accounts': 8.2.0(typescript@5.9.3) + '@solana/addresses': 8.2.0(typescript@5.9.3) + '@solana/codecs': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/functional': 8.2.0(typescript@5.9.3) + '@solana/instruction-plans': 8.2.0(typescript@5.9.3) + '@solana/instructions': 8.2.0(typescript@5.9.3) + '@solana/keys': 8.2.0(typescript@5.9.3) + '@solana/offchain-messages': 8.2.0(typescript@5.9.3) + '@solana/plugin-core': 8.2.0(typescript@5.9.3) + '@solana/plugin-interfaces': 8.2.0(typescript@5.9.3) + '@solana/program-client-core': 8.2.0(typescript@5.9.3) + '@solana/programs': 8.2.0(typescript@5.9.3) + '@solana/promises': 8.2.0(typescript@5.9.3) + '@solana/rpc': 8.2.0(typescript@5.9.3) + '@solana/rpc-api': 8.2.0(typescript@5.9.3) + '@solana/rpc-parsed-types': 8.2.0(typescript@5.9.3) + '@solana/rpc-spec-types': 8.2.0(typescript@5.9.3) + '@solana/rpc-subscriptions': 8.2.0(typescript@5.9.3) + '@solana/rpc-types': 8.2.0(typescript@5.9.3) + '@solana/signers': 8.2.0(typescript@5.9.3) + '@solana/subscribable': 8.2.0(typescript@5.9.3) + '@solana/sysvars': 8.2.0(typescript@5.9.3) + '@solana/transaction-confirmation': 8.2.0(typescript@5.9.3) + '@solana/transaction-introspection': 8.2.0(typescript@5.9.3) + '@solana/transaction-messages': 8.2.0(typescript@5.9.3) + '@solana/transactions': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - bufferutil + - fastestsmallesttextencoderdecoder + - utf-8-validate + + '@solana/nominal-types@7.1.1(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + + '@solana/nominal-types@8.2.0(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + + '@solana/offchain-messages@7.1.1(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-data-structures': 7.1.1(typescript@5.9.3) + '@solana/codecs-numbers': 7.1.1(typescript@5.9.3) + '@solana/codecs-strings': 7.1.1(typescript@5.9.3) + '@solana/errors': 7.1.1(typescript@5.9.3) + '@solana/keys': 7.1.1(typescript@5.9.3) + '@solana/nominal-types': 7.1.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/offchain-messages@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.2.0(typescript@5.9.3) + '@solana/codecs-core': 8.2.0(typescript@5.9.3) + '@solana/codecs-data-structures': 8.2.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.2.0(typescript@5.9.3) + '@solana/codecs-strings': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/keys': 8.2.0(typescript@5.9.3) + '@solana/nominal-types': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/options@7.1.1(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 7.1.1(typescript@5.9.3) + '@solana/codecs-data-structures': 7.1.1(typescript@5.9.3) + '@solana/codecs-numbers': 7.1.1(typescript@5.9.3) + '@solana/codecs-strings': 7.1.1(typescript@5.9.3) + '@solana/errors': 7.1.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/options@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 8.2.0(typescript@5.9.3) + '@solana/codecs-data-structures': 8.2.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.2.0(typescript@5.9.3) + '@solana/codecs-strings': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/plugin-core@7.1.1(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + + '@solana/plugin-core@8.2.0(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + + '@solana/plugin-interfaces@7.1.1(typescript@5.9.3)': + dependencies: + '@solana/accounts': 7.1.1(typescript@5.9.3) + '@solana/addresses': 7.1.1(typescript@5.9.3) + '@solana/instruction-plans': 7.1.1(typescript@5.9.3) + '@solana/keys': 7.1.1(typescript@5.9.3) + '@solana/rpc-spec': 7.1.1(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 7.1.1(typescript@5.9.3) + '@solana/rpc-types': 7.1.1(typescript@5.9.3) + '@solana/signers': 7.1.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/plugin-interfaces@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/accounts': 8.2.0(typescript@5.9.3) + '@solana/addresses': 8.2.0(typescript@5.9.3) + '@solana/instruction-plans': 8.2.0(typescript@5.9.3) + '@solana/keys': 8.2.0(typescript@5.9.3) + '@solana/rpc-spec': 8.2.0(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 8.2.0(typescript@5.9.3) + '@solana/rpc-types': 8.2.0(typescript@5.9.3) + '@solana/signers': 8.2.0(typescript@5.9.3) + '@solana/transactions': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/program-client-core@7.1.1(typescript@5.9.3)': + dependencies: + '@solana/accounts': 7.1.1(typescript@5.9.3) + '@solana/addresses': 7.1.1(typescript@5.9.3) + '@solana/codecs-core': 7.1.1(typescript@5.9.3) + '@solana/errors': 7.1.1(typescript@5.9.3) + '@solana/instruction-plans': 7.1.1(typescript@5.9.3) + '@solana/instructions': 7.1.1(typescript@5.9.3) + '@solana/plugin-interfaces': 7.1.1(typescript@5.9.3) + '@solana/rpc-api': 7.1.1(typescript@5.9.3) + '@solana/signers': 7.1.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/program-client-core@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/accounts': 8.2.0(typescript@5.9.3) + '@solana/addresses': 8.2.0(typescript@5.9.3) + '@solana/codecs-core': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/instruction-plans': 8.2.0(typescript@5.9.3) + '@solana/instructions': 8.2.0(typescript@5.9.3) + '@solana/plugin-interfaces': 8.2.0(typescript@5.9.3) + '@solana/rpc-api': 8.2.0(typescript@5.9.3) + '@solana/signers': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/programs@7.1.1(typescript@5.9.3)': + dependencies: + '@solana/addresses': 7.1.1(typescript@5.9.3) + '@solana/errors': 7.1.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/programs@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/promises@7.1.1(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + + '@solana/promises@8.2.0(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + + '@solana/rpc-api@7.1.1(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/errors': 7.1.1(typescript@5.9.3) + '@solana/keys': 7.1.1(typescript@5.9.3) + '@solana/rpc-parsed-types': 7.1.1(typescript@5.9.3) + '@solana/rpc-spec': 7.1.1(typescript@5.9.3) + '@solana/rpc-transformers': 7.1.1(typescript@5.9.3) + '@solana/rpc-types': 7.1.1(typescript@5.9.3) + '@solana/transaction-messages': 7.1.1(typescript@5.9.3) + '@solana/transactions': 7.1.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/rpc-api@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.2.0(typescript@5.9.3) + '@solana/codecs-core': 8.2.0(typescript@5.9.3) + '@solana/codecs-strings': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/keys': 8.2.0(typescript@5.9.3) + '@solana/rpc-parsed-types': 8.2.0(typescript@5.9.3) + '@solana/rpc-spec': 8.2.0(typescript@5.9.3) + '@solana/rpc-transformers': 8.2.0(typescript@5.9.3) + '@solana/rpc-types': 8.2.0(typescript@5.9.3) + '@solana/transaction-messages': 8.2.0(typescript@5.9.3) + '@solana/transactions': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/rpc-parsed-types@7.1.1(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + + '@solana/rpc-parsed-types@8.2.0(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + + '@solana/rpc-spec-types@7.1.1(typescript@5.9.3)': + dependencies: + '@solana/errors': 7.1.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/rpc-spec-types@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/rpc-spec@7.1.1(typescript@5.9.3)': + dependencies: + '@solana/errors': 7.1.1(typescript@5.9.3) + '@solana/rpc-spec-types': 7.1.1(typescript@5.9.3) + '@solana/subscribable': 7.1.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/rpc-spec@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/rpc-spec-types': 8.2.0(typescript@5.9.3) + '@solana/subscribable': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/rpc-subscriptions-api@7.1.1(typescript@5.9.3)': + dependencies: + '@solana/addresses': 7.1.1(typescript@5.9.3) + '@solana/keys': 7.1.1(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 7.1.1(typescript@5.9.3) + '@solana/rpc-transformers': 7.1.1(typescript@5.9.3) + '@solana/rpc-types': 7.1.1(typescript@5.9.3) + '@solana/transaction-messages': 7.1.1(typescript@5.9.3) + '@solana/transactions': 7.1.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/rpc-subscriptions-api@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.2.0(typescript@5.9.3) + '@solana/keys': 8.2.0(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 8.2.0(typescript@5.9.3) + '@solana/rpc-transformers': 8.2.0(typescript@5.9.3) + '@solana/rpc-types': 8.2.0(typescript@5.9.3) + '@solana/transaction-messages': 8.2.0(typescript@5.9.3) + '@solana/transactions': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/rpc-subscriptions-channel-websocket@7.1.1(typescript@5.9.3)': + dependencies: + '@solana/errors': 7.1.1(typescript@5.9.3) + '@solana/functional': 7.1.1(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 7.1.1(typescript@5.9.3) + '@solana/subscribable': 7.1.1(typescript@5.9.3) + ws: 8.21.3 + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@solana/rpc-subscriptions-channel-websocket@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/functional': 8.2.0(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 8.2.0(typescript@5.9.3) + '@solana/subscribable': 8.2.0(typescript@5.9.3) + ws: 8.21.3 + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@solana/rpc-subscriptions-spec@7.1.1(typescript@5.9.3)': + dependencies: + '@solana/errors': 7.1.1(typescript@5.9.3) + '@solana/promises': 7.1.1(typescript@5.9.3) + '@solana/rpc-spec-types': 7.1.1(typescript@5.9.3) + '@solana/subscribable': 7.1.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/rpc-subscriptions-spec@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/promises': 8.2.0(typescript@5.9.3) + '@solana/rpc-spec-types': 8.2.0(typescript@5.9.3) + '@solana/subscribable': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/rpc-subscriptions@7.1.1(typescript@5.9.3)': + dependencies: + '@solana/errors': 7.1.1(typescript@5.9.3) + '@solana/fast-stable-stringify': 7.1.1(typescript@5.9.3) + '@solana/functional': 7.1.1(typescript@5.9.3) + '@solana/promises': 7.1.1(typescript@5.9.3) + '@solana/rpc-spec-types': 7.1.1(typescript@5.9.3) + '@solana/rpc-subscriptions-api': 7.1.1(typescript@5.9.3) + '@solana/rpc-subscriptions-channel-websocket': 7.1.1(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 7.1.1(typescript@5.9.3) + '@solana/rpc-transformers': 7.1.1(typescript@5.9.3) + '@solana/rpc-types': 7.1.1(typescript@5.9.3) + '@solana/subscribable': 7.1.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - bufferutil + - fastestsmallesttextencoderdecoder + - utf-8-validate + + '@solana/rpc-subscriptions@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/fast-stable-stringify': 8.2.0(typescript@5.9.3) + '@solana/functional': 8.2.0(typescript@5.9.3) + '@solana/promises': 8.2.0(typescript@5.9.3) + '@solana/rpc-spec-types': 8.2.0(typescript@5.9.3) + '@solana/rpc-subscriptions-api': 8.2.0(typescript@5.9.3) + '@solana/rpc-subscriptions-channel-websocket': 8.2.0(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 8.2.0(typescript@5.9.3) + '@solana/rpc-transformers': 8.2.0(typescript@5.9.3) + '@solana/rpc-types': 8.2.0(typescript@5.9.3) + '@solana/subscribable': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - bufferutil + - fastestsmallesttextencoderdecoder + - utf-8-validate + + '@solana/rpc-transformers@7.1.1(typescript@5.9.3)': + dependencies: + '@solana/errors': 7.1.1(typescript@5.9.3) + '@solana/functional': 7.1.1(typescript@5.9.3) + '@solana/nominal-types': 7.1.1(typescript@5.9.3) + '@solana/rpc-spec-types': 7.1.1(typescript@5.9.3) + '@solana/rpc-types': 7.1.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/rpc-transformers@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/functional': 8.2.0(typescript@5.9.3) + '@solana/nominal-types': 8.2.0(typescript@5.9.3) + '@solana/rpc-spec-types': 8.2.0(typescript@5.9.3) + '@solana/rpc-types': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/rpc-transport-http@7.1.1(typescript@5.9.3)': + dependencies: + '@solana/errors': 7.1.1(typescript@5.9.3) + '@solana/rpc-spec': 7.1.1(typescript@5.9.3) + '@solana/rpc-spec-types': 7.1.1(typescript@5.9.3) + undici-types: 8.10.0 + optionalDependencies: + typescript: 5.9.3 + + '@solana/rpc-transport-http@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/rpc-spec': 8.2.0(typescript@5.9.3) + '@solana/rpc-spec-types': 8.2.0(typescript@5.9.3) + undici-types: 8.10.0 + optionalDependencies: + typescript: 5.9.3 + + '@solana/rpc-types@7.1.1(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-numbers': 7.1.1(typescript@5.9.3) + '@solana/codecs-strings': 7.1.1(typescript@5.9.3) + '@solana/errors': 7.1.1(typescript@5.9.3) + '@solana/fixed-points': 7.1.1(typescript@5.9.3) + '@solana/nominal-types': 7.1.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/rpc-types@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.2.0(typescript@5.9.3) + '@solana/codecs-core': 8.2.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.2.0(typescript@5.9.3) + '@solana/codecs-strings': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/fixed-points': 8.2.0(typescript@5.9.3) + '@solana/nominal-types': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/rpc@7.1.1(typescript@5.9.3)': + dependencies: + '@solana/errors': 7.1.1(typescript@5.9.3) + '@solana/fast-stable-stringify': 7.1.1(typescript@5.9.3) + '@solana/functional': 7.1.1(typescript@5.9.3) + '@solana/rpc-api': 7.1.1(typescript@5.9.3) + '@solana/rpc-spec': 7.1.1(typescript@5.9.3) + '@solana/rpc-spec-types': 7.1.1(typescript@5.9.3) + '@solana/rpc-transformers': 7.1.1(typescript@5.9.3) + '@solana/rpc-transport-http': 7.1.1(typescript@5.9.3) + '@solana/rpc-types': 7.1.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/rpc@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/fast-stable-stringify': 8.2.0(typescript@5.9.3) + '@solana/functional': 8.2.0(typescript@5.9.3) + '@solana/rpc-api': 8.2.0(typescript@5.9.3) + '@solana/rpc-spec': 8.2.0(typescript@5.9.3) + '@solana/rpc-spec-types': 8.2.0(typescript@5.9.3) + '@solana/rpc-transformers': 8.2.0(typescript@5.9.3) + '@solana/rpc-transport-http': 8.2.0(typescript@5.9.3) + '@solana/rpc-types': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/signers@7.1.1(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/errors': 7.1.1(typescript@5.9.3) + '@solana/instructions': 7.1.1(typescript@5.9.3) + '@solana/keys': 7.1.1(typescript@5.9.3) + '@solana/nominal-types': 7.1.1(typescript@5.9.3) + '@solana/offchain-messages': 7.1.1(typescript@5.9.3) + '@solana/transaction-messages': 7.1.1(typescript@5.9.3) + '@solana/transactions': 7.1.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/signers@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.2.0(typescript@5.9.3) + '@solana/codecs-core': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/instructions': 8.2.0(typescript@5.9.3) + '@solana/keys': 8.2.0(typescript@5.9.3) + '@solana/nominal-types': 8.2.0(typescript@5.9.3) + '@solana/offchain-messages': 8.2.0(typescript@5.9.3) + '@solana/transaction-messages': 8.2.0(typescript@5.9.3) + '@solana/transactions': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/subscribable@7.1.1(typescript@5.9.3)': + dependencies: + '@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@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/promises': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/sysvars@7.1.1(typescript@5.9.3)': + dependencies: + '@solana/accounts': 7.1.1(typescript@5.9.3) + '@solana/codecs-core': 7.1.1(typescript@5.9.3) + '@solana/codecs-data-structures': 7.1.1(typescript@5.9.3) + '@solana/codecs-numbers': 7.1.1(typescript@5.9.3) + '@solana/errors': 7.1.1(typescript@5.9.3) + '@solana/rpc-types': 7.1.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/sysvars@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/accounts': 8.2.0(typescript@5.9.3) + '@solana/codecs-core': 8.2.0(typescript@5.9.3) + '@solana/codecs-data-structures': 8.2.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/rpc-types': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/transaction-confirmation@7.1.1(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/errors': 7.1.1(typescript@5.9.3) + '@solana/keys': 7.1.1(typescript@5.9.3) + '@solana/promises': 7.1.1(typescript@5.9.3) + '@solana/rpc': 7.1.1(typescript@5.9.3) + '@solana/rpc-subscriptions': 7.1.1(typescript@5.9.3) + '@solana/rpc-types': 7.1.1(typescript@5.9.3) + '@solana/transaction-messages': 7.1.1(typescript@5.9.3) + '@solana/transactions': 7.1.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - bufferutil + - fastestsmallesttextencoderdecoder + - utf-8-validate + + '@solana/transaction-confirmation@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.2.0(typescript@5.9.3) + '@solana/codecs-strings': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/keys': 8.2.0(typescript@5.9.3) + '@solana/promises': 8.2.0(typescript@5.9.3) + '@solana/rpc': 8.2.0(typescript@5.9.3) + '@solana/rpc-subscriptions': 8.2.0(typescript@5.9.3) + '@solana/rpc-types': 8.2.0(typescript@5.9.3) + '@solana/transaction-messages': 8.2.0(typescript@5.9.3) + '@solana/transactions': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - bufferutil + - fastestsmallesttextencoderdecoder + - utf-8-validate + + '@solana/transaction-introspection@7.1.1(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/errors': 7.1.1(typescript@5.9.3) + '@solana/instructions': 7.1.1(typescript@5.9.3) + '@solana/rpc-types': 7.1.1(typescript@5.9.3) + '@solana/transaction-messages': 7.1.1(typescript@5.9.3) + '@solana/transactions': 7.1.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/transaction-introspection@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.2.0(typescript@5.9.3) + '@solana/codecs-core': 8.2.0(typescript@5.9.3) + '@solana/codecs-strings': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/instructions': 8.2.0(typescript@5.9.3) + '@solana/rpc-types': 8.2.0(typescript@5.9.3) + '@solana/transaction-messages': 8.2.0(typescript@5.9.3) + '@solana/transactions': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/transaction-messages@7.1.1(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-data-structures': 7.1.1(typescript@5.9.3) + '@solana/codecs-numbers': 7.1.1(typescript@5.9.3) + '@solana/errors': 7.1.1(typescript@5.9.3) + '@solana/functional': 7.1.1(typescript@5.9.3) + '@solana/instructions': 7.1.1(typescript@5.9.3) + '@solana/nominal-types': 7.1.1(typescript@5.9.3) + '@solana/rpc-types': 7.1.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/transaction-messages@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.2.0(typescript@5.9.3) + '@solana/codecs-core': 8.2.0(typescript@5.9.3) + '@solana/codecs-data-structures': 8.2.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/functional': 8.2.0(typescript@5.9.3) + '@solana/instructions': 8.2.0(typescript@5.9.3) + '@solana/nominal-types': 8.2.0(typescript@5.9.3) + '@solana/rpc-types': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/transactions@7.1.1(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-data-structures': 7.1.1(typescript@5.9.3) + '@solana/codecs-numbers': 7.1.1(typescript@5.9.3) + '@solana/codecs-strings': 7.1.1(typescript@5.9.3) + '@solana/errors': 7.1.1(typescript@5.9.3) + '@solana/functional': 7.1.1(typescript@5.9.3) + '@solana/instructions': 7.1.1(typescript@5.9.3) + '@solana/keys': 7.1.1(typescript@5.9.3) + '@solana/nominal-types': 7.1.1(typescript@5.9.3) + '@solana/rpc-types': 7.1.1(typescript@5.9.3) + '@solana/transaction-messages': 7.1.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/transactions@8.2.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.2.0(typescript@5.9.3) + '@solana/codecs-core': 8.2.0(typescript@5.9.3) + '@solana/codecs-data-structures': 8.2.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.2.0(typescript@5.9.3) + '@solana/codecs-strings': 8.2.0(typescript@5.9.3) + '@solana/errors': 8.2.0(typescript@5.9.3) + '@solana/functional': 8.2.0(typescript@5.9.3) + '@solana/instructions': 8.2.0(typescript@5.9.3) + '@solana/keys': 8.2.0(typescript@5.9.3) + '@solana/nominal-types': 8.2.0(typescript@5.9.3) + '@solana/rpc-types': 8.2.0(typescript@5.9.3) + '@solana/transaction-messages': 8.2.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@types/chai@5.2.3': + dependencies: + '@types/deep-eql': 4.0.2 + assertion-error: 2.0.1 + + '@types/deep-eql@4.0.2': {} + + '@types/mocha@10.0.10': {} + + '@types/node@26.4.0': + dependencies: + undici-types: 8.3.0 + + ansi-regex@5.0.1: {} + + ansi-regex@6.3.0: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansi-styles@6.2.3: {} + + argparse@2.0.1: {} + + assertion-error@2.0.1: {} + + balanced-match@1.0.2: {} + + brace-expansion@2.1.4: + dependencies: + balanced-match: 1.0.2 + + browser-stdout@1.3.1: {} + + camelcase@6.3.0: {} + + chai@6.2.2: {} + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + chalk@5.6.2: {} + + chokidar@4.0.3: + dependencies: + readdirp: 4.1.2 + + cliui@8.0.1: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + commander@15.0.0: {} + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + debug@4.4.3(supports-color@8.1.1): + dependencies: + ms: 2.1.3 + optionalDependencies: + supports-color: 8.1.1 + + decamelize@4.0.0: {} + + diff@7.0.0: {} + + eastasianwidth@0.2.0: {} + + emoji-regex@8.0.0: {} + + emoji-regex@9.2.2: {} + + 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: {} + + escape-string-regexp@4.0.0: {} + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + flat@5.0.2: {} + + foreground-child@3.3.1: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + + fsevents@2.3.3: + optional: true + + get-caller-file@2.0.5: {} + + glob@10.5.0: + dependencies: + foreground-child: 3.3.1 + jackspeak: 3.4.3 + minimatch: 9.0.9 + minipass: 7.1.3 + package-json-from-dist: 1.0.1 + path-scurry: 1.11.1 + + has-flag@4.0.0: {} + + he@1.2.0: {} + + is-fullwidth-code-point@3.0.0: {} + + is-path-inside@3.0.3: {} + + is-plain-obj@2.1.0: {} + + is-unicode-supported@0.1.0: {} + + isexe@2.0.0: {} + + jackspeak@3.4.3: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + + js-yaml@4.3.2: + dependencies: + argparse: 2.0.1 + + litesvm-darwin-arm64@1.4.1: + optional: true + + litesvm-darwin-x64@1.4.1: + optional: true + + litesvm-linux-arm64-gnu@1.4.1: + optional: true + + litesvm-linux-arm64-musl@1.4.1: + optional: true + + litesvm-linux-x64-gnu@1.4.1: + optional: true + + litesvm-linux-x64-musl@1.4.1: + optional: true + + litesvm@1.4.1(typescript@5.9.3): + dependencies: + '@solana-program/system': 0.14.0(@solana/kit@8.2.0(typescript@5.9.3)) + '@solana-program/token': 0.16.0(@solana/kit@8.2.0(typescript@5.9.3)) + '@solana/kit': 8.2.0(typescript@5.9.3) + optionalDependencies: + litesvm-darwin-arm64: 1.4.1 + litesvm-darwin-x64: 1.4.1 + litesvm-linux-arm64-gnu: 1.4.1 + litesvm-linux-arm64-musl: 1.4.1 + litesvm-linux-x64-gnu: 1.4.1 + litesvm-linux-x64-musl: 1.4.1 + transitivePeerDependencies: + - bufferutil + - fastestsmallesttextencoderdecoder + - typescript + - utf-8-validate + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + log-symbols@4.1.0: + dependencies: + chalk: 4.1.2 + is-unicode-supported: 0.1.0 + + lru-cache@10.4.3: {} + + minimatch@9.0.9: + dependencies: + brace-expansion: 2.1.4 + + minipass@7.1.3: {} + + mocha@11.8.0: + dependencies: + browser-stdout: 1.3.1 + chokidar: 4.0.3 + debug: 4.4.3(supports-color@8.1.1) + diff: 7.0.0 + escape-string-regexp: 4.0.0 + find-up: 5.0.0 + glob: 10.5.0 + he: 1.2.0 + is-path-inside: 3.0.3 + js-yaml: 4.3.2 + log-symbols: 4.1.0 + minimatch: 9.0.9 + ms: 2.1.3 + picocolors: 1.1.1 + serialize-javascript: 6.0.2 + strip-json-comments: 3.1.1 + supports-color: 8.1.1 + workerpool: 9.3.4 + yargs: 17.7.3 + yargs-parser: 21.1.1 + yargs-unparser: 2.0.0 + + ms@2.1.3: {} + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + package-json-from-dist@1.0.1: {} + + path-exists@4.0.0: {} + + path-key@3.1.1: {} + + path-scurry@1.11.1: + dependencies: + lru-cache: 10.4.3 + minipass: 7.1.3 + + picocolors@1.1.1: {} + + randombytes@2.1.0: + dependencies: + safe-buffer: 5.2.1 + + readdirp@4.1.2: {} + + require-directory@2.1.1: {} + + safe-buffer@5.2.1: {} + + serialize-javascript@6.0.2: + dependencies: + randombytes: 2.1.0 + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + signal-exit@4.1.0: {} + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string-width@5.1.2: + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.2.0 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-ansi@7.2.0: + dependencies: + ansi-regex: 6.3.0 + + strip-json-comments@3.1.1: {} + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-color@8.1.1: + dependencies: + has-flag: 4.0.0 + + tsx@4.23.13: + dependencies: + esbuild: 0.28.2 + optionalDependencies: + fsevents: 2.3.3 + + typescript@5.9.3: {} + + undici-types@8.10.0: {} + + undici-types@8.3.0: {} + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + workerpool@9.3.4: {} + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@8.1.0: + dependencies: + ansi-styles: 6.2.3 + string-width: 5.1.2 + strip-ansi: 7.2.0 + + ws@8.21.3: {} + + y18n@5.0.8: {} + + yargs-parser@21.1.1: {} + + yargs-unparser@2.0.0: + dependencies: + camelcase: 6.3.0 + decamelize: 4.0.0 + flat: 5.0.2 + is-plain-obj: 2.1.0 + + yargs@17.7.3: + dependencies: + cliui: 8.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + + yocto-queue@0.1.0: {} diff --git a/tokens/token-2022/transfer-hook/hello-world/pinocchio/program/Cargo.toml b/tokens/token-2022/transfer-hook/hello-world/pinocchio/program/Cargo.toml new file mode 100644 index 000000000..051f7982b --- /dev/null +++ b/tokens/token-2022/transfer-hook/hello-world/pinocchio/program/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "token-2022-transfer-hook-hello-world-pinocchio-program" +version = "0.1.0" +edition = "2021" + +[dependencies] +pinocchio.workspace = true +solana-address.workspace = true +pinocchio-log.workspace = true +pinocchio-system.workspace = true + +[lib] +crate-type = ["cdylib", "lib"] + +[features] +custom-heap = [] +custom-panic = [] + +[lints.rust] +unexpected_cfgs = { level = "warn", check-cfg = ['cfg(target_os, values("solana"))'] } diff --git a/tokens/token-2022/transfer-hook/hello-world/pinocchio/program/src/error.rs b/tokens/token-2022/transfer-hook/hello-world/pinocchio/program/src/error.rs new file mode 100644 index 000000000..4f5a3daed --- /dev/null +++ b/tokens/token-2022/transfer-hook/hello-world/pinocchio/program/src/error.rs @@ -0,0 +1,18 @@ +use pinocchio::error::ProgramError; + +/// Errors returned by this example, surfaced as `ProgramError::Custom`. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum TransferHookError { + /// The hook was invoked while the source account was not mid-transfer. + IsNotCurrentlyTransferring = 0, + /// The mint does not carry a `TransferHook` extension. + MissingTransferHookExtension = 1, + /// The `TransferHook` extension does not name the expected authority and program. + UnexpectedTransferHookConfig = 2, +} + +impl From for ProgramError { + fn from(error: TransferHookError) -> Self { + ProgramError::Custom(error as u32) + } +} diff --git a/tokens/token-2022/transfer-hook/hello-world/pinocchio/program/src/instructions/initialize.rs b/tokens/token-2022/transfer-hook/hello-world/pinocchio/program/src/instructions/initialize.rs new file mode 100644 index 000000000..a23d226dd --- /dev/null +++ b/tokens/token-2022/transfer-hook/hello-world/pinocchio/program/src/instructions/initialize.rs @@ -0,0 +1,143 @@ +use alloc::vec::Vec; + +use pinocchio::{ + cpi::invoke, + error::ProgramError, + instruction::{InstructionAccount, InstructionView}, + sysvars::{rent::Rent, Sysvar}, + AccountView, Address, ProgramResult, +}; +use pinocchio_log::log; +use pinocchio_system::instructions::CreateAccount; + +use crate::{ + error::TransferHookError, + instructions::TOKEN_2022_PROGRAM_ID, + token2022::{get_extension_data, TRANSFER_HOOK}, +}; + +/// Token-2022 instruction discriminators built by hand here. +const TRANSFER_HOOK_EXTENSION: u8 = 36; +const INITIALIZE_MINT_2: u8 = 20; + +/// Sub-discriminator of `TransferHookInstruction::Initialize`, which follows the +/// `TransferHookExtension` byte. +const TRANSFER_HOOK_INITIALIZE: u8 = 0; + +/// Size of a Token-2022 mint carrying the `TransferHook` extension: +/// +/// ```text +/// base mint (82), padded to Account::LEN (165) + +/// account-type byte (1) + +/// TransferHook TLV: type (2) + length (2) + value (64) = 234 +/// ``` +/// +/// The 64-byte value is two `OptionalNonZeroPubkey`s — the extension authority +/// and the hook program — where all-zero means `None`. This mirrors +/// `ExtensionType::try_calculate_account_len::(&[TransferHook])`. +const MINT_SIZE: usize = 234; + +/// Length of the `TransferHook` extension value. +const TRANSFER_HOOK_EXTENSION_LEN: usize = 64; + +/// Creates a Token-2022 mint that names this program as its transfer hook. +/// +/// Every transfer of the resulting mint makes Token-2022 CPI back into this +/// program's `Execute` instruction. +/// +/// Accounts: +/// 0. `[signer, writable]` payer (funds the mint; becomes mint and hook authority) +/// 1. `[signer, writable]` mint (a fresh keypair to initialize) +/// 2. `[]` Token-2022 program +/// 3. `[]` system program +/// +/// Instruction data: `[decimals: u8]` +pub fn initialize(program_id: &Address, accounts: &mut [AccountView], data: &[u8]) -> ProgramResult { + // `token_program` and `system_program` are unused directly, but must be + // supplied so they are present in the transaction for the CPIs below. + let [payer, mint, _token_program, _system_program] = accounts else { + return Err(ProgramError::NotEnoughAccountKeys); + }; + + if !payer.is_signer() || !mint.is_signer() { + return Err(ProgramError::MissingRequiredSignature); + } + + let decimals = *data.first().ok_or(ProgramError::InvalidInstructionData)?; + + let lamports = Rent::get()?.try_minimum_balance(MINT_SIZE)?; + + log!("Creating mint account"); + CreateAccount { from: payer, to: mint, lamports, space: MINT_SIZE as u64, owner: &TOKEN_2022_PROGRAM_ID } + .invoke()?; + + // Extensions must be initialized *before* the mint itself: once the mint is + // initialized Token-2022 rejects further extension setup. + log!("Initializing transfer hook extension"); + let hook_data = build_transfer_hook_initialize_data(payer.address(), program_id); + let hook_accounts = [InstructionAccount::writable(mint.address())]; + invoke( + &InstructionView { program_id: &TOKEN_2022_PROGRAM_ID, accounts: &hook_accounts, data: &hook_data }, + &[*mint], + )?; + + log!("Initializing mint"); + let mint_data = build_initialize_mint2_data(decimals, payer.address()); + let mint_accounts = [InstructionAccount::writable(mint.address())]; + invoke( + &InstructionView { program_id: &TOKEN_2022_PROGRAM_ID, accounts: &mint_accounts, data: &mint_data }, + &[*mint], + )?; + + // Read the extension back — this both confirms the mint was configured as + // intended and demonstrates how to parse mint extension data in-program. + check_transfer_hook_extension(mint, payer.address(), program_id)?; + + log!("Mint created with transfer hook"); + Ok(()) +} + +/// Confirms the freshly created mint carries a `TransferHook` extension naming +/// `authority` and this program. +fn check_transfer_hook_extension(mint: &AccountView, authority: &Address, program_id: &Address) -> ProgramResult { + let mint_data = mint.try_borrow()?; + let extension = + get_extension_data(&mint_data, TRANSFER_HOOK).ok_or(TransferHookError::MissingTransferHookExtension)?; + + if extension.len() != TRANSFER_HOOK_EXTENSION_LEN { + return Err(TransferHookError::MissingTransferHookExtension.into()); + } + + if &extension[..32] != authority.as_ref() || &extension[32..] != program_id.as_ref() { + return Err(TransferHookError::UnexpectedTransferHookConfig.into()); + } + + Ok(()) +} + +/// Serializes a `TransferHookExtension(Initialize)` instruction. +/// +/// Layout: `[36, 0] authority: Pubkey, program_id: Pubkey`. Both are +/// `OptionalNonZeroPubkey`s, so an all-zero value would mean `None`; here both +/// are set. +fn build_transfer_hook_initialize_data(authority: &Address, hook_program_id: &Address) -> Vec { + let mut data = Vec::with_capacity(66); + data.push(TRANSFER_HOOK_EXTENSION); + data.push(TRANSFER_HOOK_INITIALIZE); + data.extend_from_slice(authority.as_ref()); + data.extend_from_slice(hook_program_id.as_ref()); + data +} + +/// Serializes an `InitializeMint2` instruction (variant 20). +/// +/// Layout: `[20] decimals: u8, mint_authority: Pubkey, freeze_authority: COption`. +/// The freeze authority is left unset, which packs as a single `0` byte. +fn build_initialize_mint2_data(decimals: u8, mint_authority: &Address) -> Vec { + let mut data = Vec::with_capacity(35); + data.push(INITIALIZE_MINT_2); + data.push(decimals); + data.extend_from_slice(mint_authority.as_ref()); + data.push(0); + data +} diff --git a/tokens/token-2022/transfer-hook/hello-world/pinocchio/program/src/instructions/initialize_extra_account_meta_list.rs b/tokens/token-2022/transfer-hook/hello-world/pinocchio/program/src/instructions/initialize_extra_account_meta_list.rs new file mode 100644 index 000000000..44c242b82 --- /dev/null +++ b/tokens/token-2022/transfer-hook/hello-world/pinocchio/program/src/instructions/initialize_extra_account_meta_list.rs @@ -0,0 +1,81 @@ +use pinocchio::{ + cpi::{Seed, Signer}, + error::ProgramError, + sysvars::{rent::Rent, Sysvar}, + AccountView, Address, ProgramResult, +}; +use pinocchio_log::log; +use pinocchio_system::instructions::CreateAccount; + +use crate::instructions::EXTRA_ACCOUNT_METAS_SEED; + +/// A serialized, empty `ExtraAccountMetaList`. +/// +/// The account is one TLV entry keyed by the `Execute` discriminator, so +/// Token-2022 can find the account list belonging to the instruction it is +/// about to CPI: +/// +/// ```text +/// [105, 37, 101, 197, 75, 251, 102, 26] Execute discriminator +/// [4, 0, 0, 0] value length (u32) = 4 +/// [0, 0, 0, 0] account count (u32) = 0 +/// ``` +/// +/// This example resolves no extra accounts, so the list is always these 16 +/// bytes — a constant, rather than a dependency on the TLV encoder. +const EXTRA_ACCOUNT_METAS_DATA: [u8; 16] = [105, 37, 101, 197, 75, 251, 102, 26, 4, 0, 0, 0, 0, 0, 0, 0]; + +/// Creates the `ExtraAccountMetaList` PDA for `mint`. +/// +/// Token-2022 reads this account before every transfer to learn which accounts +/// beyond the four transfer accounts the hook expects. It must exist even when +/// the list is empty, otherwise transfers of the mint fail. +/// +/// Accounts: +/// 0. `[signer, writable]` payer (funds the account) +/// 1. `[writable]` extra account meta list (PDA `[b"extra-account-metas", mint]`) +/// 2. `[]` mint +/// 3. `[]` Token-2022 program +/// 4. `[]` associated token program +/// 5. `[]` system program +/// +/// Instruction data: none beyond the interface discriminator. +pub fn initialize_extra_account_meta_list(program_id: &Address, accounts: &mut [AccountView]) -> ProgramResult { + // The trailing programs are unused directly, but mirror the account list of + // the Anchor version of this example. + let [payer, extra_account_meta_list, mint, _token_program, _associated_token_program, _system_program] = accounts + else { + return Err(ProgramError::NotEnoughAccountKeys); + }; + + if !payer.is_signer() { + return Err(ProgramError::MissingRequiredSignature); + } + + let (expected_address, bump) = + Address::find_program_address(&[EXTRA_ACCOUNT_METAS_SEED, mint.address().as_ref()], program_id); + if extra_account_meta_list.address() != &expected_address { + return Err(ProgramError::InvalidSeeds); + } + + let bump_bytes = [bump]; + let seeds = [Seed::from(EXTRA_ACCOUNT_METAS_SEED), Seed::from(mint.address().as_ref()), Seed::from(&bump_bytes)]; + + let lamports = Rent::get()?.try_minimum_balance(EXTRA_ACCOUNT_METAS_DATA.len())?; + + log!("Creating extra account meta list"); + CreateAccount { + from: payer, + to: extra_account_meta_list, + lamports, + space: EXTRA_ACCOUNT_METAS_DATA.len() as u64, + owner: program_id, + } + .invoke_signed(&[Signer::from(&seeds)])?; + + let mut account_data = extra_account_meta_list.try_borrow_mut()?; + account_data.copy_from_slice(&EXTRA_ACCOUNT_METAS_DATA); + + log!("Extra account meta list created"); + Ok(()) +} diff --git a/tokens/token-2022/transfer-hook/hello-world/pinocchio/program/src/instructions/mod.rs b/tokens/token-2022/transfer-hook/hello-world/pinocchio/program/src/instructions/mod.rs new file mode 100644 index 000000000..38e816ba4 --- /dev/null +++ b/tokens/token-2022/transfer-hook/hello-world/pinocchio/program/src/instructions/mod.rs @@ -0,0 +1,24 @@ +mod initialize; +mod initialize_extra_account_meta_list; +mod transfer_hook; + +pub use initialize::*; +pub use initialize_extra_account_meta_list::*; +pub use transfer_hook::*; + +/// The SPL Token-2022 program ID +/// (`TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb`). +/// +/// Unlike the legacy SPL Token program (which `pinocchio-token` wraps), there is +/// no pinocchio crate for Token-2022, so its instructions are built by hand and +/// CPI'd into this program. +pub const TOKEN_2022_PROGRAM_ID: pinocchio::Address = + pinocchio::Address::from_str_const("TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb"); + +/// Seed prefix for the `ExtraAccountMetaList` PDA. +/// +/// Fixed by the transfer-hook interface: during a transfer Token-2022 derives +/// `[b"extra-account-metas", mint]` against the hook program to discover which +/// additional accounts the hook needs, so the account must live at exactly this +/// address to be found. +pub const EXTRA_ACCOUNT_METAS_SEED: &[u8] = b"extra-account-metas"; diff --git a/tokens/token-2022/transfer-hook/hello-world/pinocchio/program/src/instructions/transfer_hook.rs b/tokens/token-2022/transfer-hook/hello-world/pinocchio/program/src/instructions/transfer_hook.rs new file mode 100644 index 000000000..8b95b3761 --- /dev/null +++ b/tokens/token-2022/transfer-hook/hello-world/pinocchio/program/src/instructions/transfer_hook.rs @@ -0,0 +1,59 @@ +use pinocchio::{error::ProgramError, AccountView, Address, ProgramResult}; +use pinocchio_log::log; + +use crate::{ + error::TransferHookError, + instructions::EXTRA_ACCOUNT_METAS_SEED, + token2022::{get_extension_data, TRANSFER_HOOK_ACCOUNT}, +}; + +/// The `Execute` instruction of the transfer-hook interface: Token-2022 CPIs +/// this during every transfer of a mint that names this program as its hook. +/// +/// The account order is fixed by the interface — the four transfer accounts, +/// then the `ExtraAccountMetaList`, then whatever extra accounts that list +/// resolves to (none in this example). +/// +/// Accounts: +/// 0. `[]` source token account +/// 1. `[]` mint +/// 2. `[]` destination token account +/// 3. `[]` source token account owner +/// 4. `[]` extra account meta list (PDA `[b"extra-account-metas", mint]`) +/// +/// Instruction data: `[amount: u64 (LE)]`, unused here. +pub fn transfer_hook(program_id: &Address, accounts: &mut [AccountView], _data: &[u8]) -> ProgramResult { + let [source_token, mint, _destination_token, _owner, extra_account_meta_list, ..] = accounts else { + return Err(ProgramError::NotEnoughAccountKeys); + }; + + // Anyone can call this instruction directly, so confirm the account list + // really belongs to this mint rather than trusting the caller's choice. + let (expected_address, _) = + Address::find_program_address(&[EXTRA_ACCOUNT_METAS_SEED, mint.address().as_ref()], program_id); + if extra_account_meta_list.address() != &expected_address { + return Err(ProgramError::InvalidSeeds); + } + + check_is_transferring(source_token)?; + + log!("Hello Transfer Hook!"); + Ok(()) +} + +/// Fails unless the source account is mid-transfer. +/// +/// Token-2022 raises the `TransferHookAccount` extension's `transferring` flag +/// only for the duration of the transfer it is executing. Checking it is what +/// stops the hook from being invoked directly, outside any transfer — a real +/// hook that grants or records something must not be callable on its own. +fn check_is_transferring(source_token: &AccountView) -> ProgramResult { + let account_data = source_token.try_borrow()?; + let extension = get_extension_data(&account_data, TRANSFER_HOOK_ACCOUNT) + .ok_or(TransferHookError::IsNotCurrentlyTransferring)?; + + match extension.first() { + Some(1) => Ok(()), + _ => Err(TransferHookError::IsNotCurrentlyTransferring.into()), + } +} diff --git a/tokens/token-2022/transfer-hook/hello-world/pinocchio/program/src/lib.rs b/tokens/token-2022/transfer-hook/hello-world/pinocchio/program/src/lib.rs new file mode 100644 index 000000000..c81917e85 --- /dev/null +++ b/tokens/token-2022/transfer-hook/hello-world/pinocchio/program/src/lib.rs @@ -0,0 +1,16 @@ +#![no_std] + +// The `entrypoint!` macro installs the default (bump) global allocator, so the +// `alloc` crate is available — we use it to build the Token-2022 instruction +// data at runtime. +extern crate alloc; + +pub mod error; +pub mod instructions; +pub mod processor; +pub mod token2022; + +use pinocchio::{entrypoint, nostd_panic_handler}; + +entrypoint!(processor::process_instruction); +nostd_panic_handler!(); diff --git a/tokens/token-2022/transfer-hook/hello-world/pinocchio/program/src/processor.rs b/tokens/token-2022/transfer-hook/hello-world/pinocchio/program/src/processor.rs new file mode 100644 index 000000000..11f3c7b57 --- /dev/null +++ b/tokens/token-2022/transfer-hook/hello-world/pinocchio/program/src/processor.rs @@ -0,0 +1,45 @@ +use pinocchio::{error::ProgramError, AccountView, Address, ProgramResult}; +use pinocchio_log::log; + +use crate::instructions::{initialize, initialize_extra_account_meta_list, transfer_hook}; + +/// `spl-transfer-hook-interface` discriminators: the first eight bytes of +/// `sha256("spl-transfer-hook-interface:")`. +/// +/// These are fixed by the interface rather than chosen here — Token-2022 CPIs +/// this program with `EXECUTE` during a transfer, so the program is only usable +/// as a hook if it answers to exactly these bytes. +const EXECUTE: [u8; 8] = [105, 37, 101, 197, 75, 251, 102, 26]; +const INITIALIZE_EXTRA_ACCOUNT_META_LIST: [u8; 8] = [43, 34, 13, 49, 167, 88, 235, 235]; + +/// Creating the mint is this example's own convenience instruction, not part of +/// the interface, so its discriminator is a single byte we pick. It cannot +/// collide with the two above, which start with 105 and 43. +const INITIALIZE: u8 = 0; + +/// Entrypoint for the program. +pub fn process_instruction( + program_id: &Address, + accounts: &mut [AccountView], + instruction_data: &[u8], +) -> ProgramResult { + // The interface discriminators are matched first: they are eight bytes, so + // a one-byte tag could otherwise shadow them. + if let Some(data) = instruction_data.strip_prefix(&EXECUTE) { + log!("Instruction: Execute"); + return transfer_hook(program_id, accounts, data); + } + + if instruction_data.starts_with(&INITIALIZE_EXTRA_ACCOUNT_META_LIST) { + log!("Instruction: InitializeExtraAccountMetaList"); + return initialize_extra_account_meta_list(program_id, accounts); + } + + match instruction_data { + [INITIALIZE, data @ ..] => { + log!("Instruction: Initialize"); + initialize(program_id, accounts, data) + } + _ => Err(ProgramError::InvalidInstructionData), + } +} diff --git a/tokens/token-2022/transfer-hook/hello-world/pinocchio/program/src/token2022.rs b/tokens/token-2022/transfer-hook/hello-world/pinocchio/program/src/token2022.rs new file mode 100644 index 000000000..8c2704a5b --- /dev/null +++ b/tokens/token-2022/transfer-hook/hello-world/pinocchio/program/src/token2022.rs @@ -0,0 +1,56 @@ +//! A minimal reader for the Token-2022 TLV extension area. +//! +//! There is no pinocchio crate for Token-2022, so rather than pull in +//! `spl-token-2022` this example walks the extension list by hand. Only the two +//! extensions it cares about are named below. + +/// Offset at which the TLV extension list begins. +/// +/// Token-2022 lays out any account carrying extensions as its base data padded +/// to `Account::LEN` (165 bytes), a one-byte account type, then the TLV list. +/// Mints (82 bytes on their own) are padded up to 165 for exactly this reason, +/// so the same offset serves both mints and token accounts. +const TLV_START: usize = 166; + +/// Marks a TLV slot that has never been written; the list ends here. +const UNINITIALIZED: u16 = 0; + +/// `ExtensionType::TransferHook` — on a *mint*, names the hook program. +pub const TRANSFER_HOOK: u16 = 14; + +/// `ExtensionType::TransferHookAccount` — on a *token account*, carries the +/// `transferring` flag Token-2022 raises for the duration of a transfer. +pub const TRANSFER_HOOK_ACCOUNT: u16 = 15; + +/// Returns the value bytes of `extension_type`, or `None` when the account is +/// too short, holds no extensions, or does not carry this one. +/// +/// Each entry is a 2-byte type, a 2-byte little-endian length, then that many +/// value bytes. Every read is bounds-checked: this parses account data that a +/// caller chose, so malformed input must return `None` rather than panic. +pub fn get_extension_data(account_data: &[u8], extension_type: u16) -> Option<&[u8]> { + let tlv = account_data.get(TLV_START..)?; + let mut cursor = 0usize; + + while cursor.checked_add(4)? <= tlv.len() { + let entry_type = u16::from_le_bytes([tlv[cursor], tlv[cursor + 1]]); + if entry_type == UNINITIALIZED { + return None; + } + + let length = u16::from_le_bytes([tlv[cursor + 2], tlv[cursor + 3]]) as usize; + let value_start = cursor + 4; + let value_end = value_start.checked_add(length)?; + if value_end > tlv.len() { + return None; + } + + if entry_type == extension_type { + return Some(&tlv[value_start..value_end]); + } + + cursor = value_end; + } + + None +} diff --git a/tokens/token-2022/transfer-hook/hello-world/pinocchio/tests/test.ts b/tokens/token-2022/transfer-hook/hello-world/pinocchio/tests/test.ts new file mode 100644 index 000000000..9699c753e --- /dev/null +++ b/tokens/token-2022/transfer-hook/hello-world/pinocchio/tests/test.ts @@ -0,0 +1,286 @@ +import * as path from 'node:path'; +import { + AccountRole, + type Address, + type KeyPairSigner, + appendTransactionMessageInstruction, + appendTransactionMessageInstructions, + createTransactionMessage, + generateKeyPairSigner, + getAddressEncoder, + getProgramDerivedAddress, + lamports, + pipe, + setTransactionMessageFeePayerSigner, + signTransactionMessageWithSigners, + unwrapOption, +} from '@solana/kit'; +import { SYSTEM_PROGRAM_ADDRESS } from '@solana-program/system'; +import { + ASSOCIATED_TOKEN_PROGRAM_ADDRESS, + findAssociatedTokenPda, + getCreateAssociatedTokenInstruction, + getMintDecoder, + getMintToInstruction, + getTokenDecoder, + getTransferCheckedInstruction, + TOKEN_2022_PROGRAM_ADDRESS, +} from '@solana-program/token-2022'; +import { assert } from 'chai'; +import { FailedTransactionMetadata, LiteSVM } from 'litesvm'; + +// A Token-2022 mint carrying the TransferHook extension: +// base mint (82) padded to 165 + account-type byte (1) + TLV (2 + 2 + 64) = 234 +const MINT_SIZE_WITH_TRANSFER_HOOK = 234; + +// The serialized empty ExtraAccountMetaList the program writes: the 8-byte +// Execute discriminator, a u32 value length of 4, and a u32 account count of 0. +const EMPTY_EXTRA_ACCOUNT_METAS = Uint8Array.from([105, 37, 101, 197, 75, 251, 102, 26, 4, 0, 0, 0, 0, 0, 0, 0]); + +// spl-transfer-hook-interface discriminators: sha256("spl-transfer-hook-interface:")[0..8]. +const EXECUTE_DISCRIMINATOR = Uint8Array.from([105, 37, 101, 197, 75, 251, 102, 26]); +const INITIALIZE_EXTRA_ACCOUNT_META_LIST_DISCRIMINATOR = Uint8Array.from([43, 34, 13, 49, 167, 88, 235, 235]); + +// This example's own instruction, which is not part of the interface. +const INITIALIZE_DISCRIMINATOR = 0; + +const DECIMALS = 2; +const MINTED_AMOUNT = 100n * 100n; // 100 tokens +const TRANSFER_AMOUNT = 1n * 100n; // 1 token + +const PROGRAM_SO = path.join( + process.cwd(), + 'tests', + 'fixtures', + 'token_2022_transfer_hook_hello_world_pinocchio_program.so', +); +const addressEncoder = getAddressEncoder(); + +function u64(n: bigint): Uint8Array { + const b = new Uint8Array(8); + new DataView(b.buffer).setBigUint64(0, n, true); + return b; +} +function concatBytes(...parts: Uint8Array[]): Uint8Array { + const out = new Uint8Array(parts.reduce((n, p) => n + p.length, 0)); + let offset = 0; + for (const p of parts) { + out.set(p, offset); + offset += p.length; + } + return out; +} + +describe('Token-2022 Transfer Hook — Hello World (Pinocchio)', () => { + let svm: LiteSVM; + let programId: Address; + let payer: KeyPairSigner; + let mint: KeyPairSigner; + let extraAccountMetaList: Address; + let sourceTokenAccount: Address; + let destinationTokenAccount: Address; + let recipient: KeyPairSigner; + + before(async () => { + svm = new LiteSVM(); + // The program derives its PDAs from the id it is invoked with and never + // asserts a hardcoded one, so a generated id keeps the test self-contained. + programId = (await generateKeyPairSigner()).address; + svm.addProgramFromFile(programId, PROGRAM_SO); + + payer = await generateKeyPairSigner(); + svm.airdrop(payer.address, lamports(10_000_000_000n)); + + mint = await generateKeyPairSigner(); + recipient = await generateKeyPairSigner(); + + [extraAccountMetaList] = await getProgramDerivedAddress({ + programAddress: programId, + seeds: ['extra-account-metas', addressEncoder.encode(mint.address)], + }); + [sourceTokenAccount] = await findAssociatedTokenPda({ + owner: payer.address, + mint: mint.address, + tokenProgram: TOKEN_2022_PROGRAM_ADDRESS, + }); + [destinationTokenAccount] = await findAssociatedTokenPda({ + owner: recipient.address, + mint: mint.address, + tokenProgram: TOKEN_2022_PROGRAM_ADDRESS, + }); + }); + + async function tx(instructions: Parameters[0][]) { + return signTransactionMessageWithSigners( + pipe( + createTransactionMessage({ version: 0 }), + m => setTransactionMessageFeePayerSigner(payer, m), + m => svm.setTransactionMessageLifetimeUsingLatestBlockhash(m), + m => appendTransactionMessageInstructions(instructions, m), + ), + ); + } + + function send(signedTx: Parameters[0], label: string) { + const result = svm.sendTransaction(signedTx); + if (result instanceof FailedTransactionMetadata) { + throw new Error(`${label} failed: ${result.err()}`); + } + return result; + } + + function tokenAmount(account: Address): bigint { + const acc = svm.getAccount(account); + if (!acc?.exists) throw new Error('token account not found'); + return getTokenDecoder().decode(acc.data).amount; + } + + it('Creates a mint with the transfer hook extension', async () => { + const ix = { + programAddress: programId, + accounts: [ + { address: payer.address, role: AccountRole.WRITABLE_SIGNER, signer: payer }, + { address: mint.address, role: AccountRole.WRITABLE_SIGNER, signer: mint }, + { address: TOKEN_2022_PROGRAM_ADDRESS, role: AccountRole.READONLY }, + { address: SYSTEM_PROGRAM_ADDRESS, role: AccountRole.READONLY }, + ], + data: Uint8Array.of(INITIALIZE_DISCRIMINATOR, DECIMALS), + }; + send(await tx([ix]), 'initialize'); + + const account = svm.getAccount(mint.address); + if (!account?.exists) throw new Error('mint not found'); + assert.equal(account.programAddress, TOKEN_2022_PROGRAM_ADDRESS, 'mint is owned by Token-2022'); + assert.equal(account.data.length, MINT_SIZE_WITH_TRANSFER_HOOK, 'mint is sized for the TransferHook extension'); + + // Decode with the official Token-2022 codec rather than reading offsets. + const state = getMintDecoder().decode(account.data); + assert.equal(state.decimals, DECIMALS); + + const extensions = unwrapOption(state.extensions) ?? []; + const transferHook = extensions.find(e => e.__kind === 'TransferHook'); + if (transferHook?.__kind !== 'TransferHook') { + throw new Error('TransferHook extension not found on the mint'); + } + assert.equal(transferHook.authority, payer.address, 'payer is the hook authority'); + assert.equal(transferHook.programId, programId, 'the mint points at this program as its hook'); + }); + + it('Creates the ExtraAccountMetaList account', async () => { + const ix = { + programAddress: programId, + accounts: [ + { address: payer.address, role: AccountRole.WRITABLE_SIGNER, signer: payer }, + { address: extraAccountMetaList, role: AccountRole.WRITABLE }, + { address: mint.address, role: AccountRole.READONLY }, + { address: TOKEN_2022_PROGRAM_ADDRESS, role: AccountRole.READONLY }, + { address: ASSOCIATED_TOKEN_PROGRAM_ADDRESS, role: AccountRole.READONLY }, + { address: SYSTEM_PROGRAM_ADDRESS, role: AccountRole.READONLY }, + ], + data: INITIALIZE_EXTRA_ACCOUNT_META_LIST_DISCRIMINATOR, + }; + send(await tx([ix]), 'initialize extra account meta list'); + + const account = svm.getAccount(extraAccountMetaList); + if (!account?.exists) throw new Error('extra account meta list not found'); + assert.equal(account.programAddress, programId, 'the list is owned by the hook program'); + assert.deepEqual( + Array.from(account.data), + Array.from(EMPTY_EXTRA_ACCOUNT_METAS), + 'the list is keyed by the Execute discriminator and holds no extra accounts', + ); + }); + + it('Creates token accounts and mints tokens', async () => { + send( + await tx([ + getCreateAssociatedTokenInstruction({ + payer, + ata: sourceTokenAccount, + owner: payer.address, + mint: mint.address, + tokenProgram: TOKEN_2022_PROGRAM_ADDRESS, + }), + getCreateAssociatedTokenInstruction({ + payer, + ata: destinationTokenAccount, + owner: recipient.address, + mint: mint.address, + tokenProgram: TOKEN_2022_PROGRAM_ADDRESS, + }), + getMintToInstruction( + { + mint: mint.address, + token: sourceTokenAccount, + mintAuthority: payer, + amount: MINTED_AMOUNT, + }, + { programAddress: TOKEN_2022_PROGRAM_ADDRESS }, + ), + ]), + 'create token accounts and mint', + ); + + assert.equal(tokenAmount(sourceTokenAccount), MINTED_AMOUNT, 'source funded'); + }); + + it('Runs the hook on a transfer', async () => { + // Token-2022 resolves the hook's accounts from the ExtraAccountMetaList, + // but the transfer instruction must still carry the hook program and that + // list. With no extra accounts to resolve, those two are all that is added. + const base = getTransferCheckedInstruction( + { + source: sourceTokenAccount, + mint: mint.address, + destination: destinationTokenAccount, + authority: payer, + amount: TRANSFER_AMOUNT, + decimals: DECIMALS, + }, + { programAddress: TOKEN_2022_PROGRAM_ADDRESS }, + ); + const transferIx = { + ...base, + accounts: [ + ...base.accounts, + { address: programId, role: AccountRole.READONLY }, + { address: extraAccountMetaList, role: AccountRole.READONLY }, + ], + }; + + const result = send(await tx([transferIx]), 'transfer with hook'); + + assert.equal(tokenAmount(sourceTokenAccount), MINTED_AMOUNT - TRANSFER_AMOUNT, 'source debited'); + assert.equal(tokenAmount(destinationTokenAccount), TRANSFER_AMOUNT, 'destination credited'); + + // The hook really ran, rather than the transfer simply bypassing it. + const logs = result.logs().join('\n'); + assert.include(logs, 'Hello Transfer Hook!', 'the hook logged from inside the transfer'); + }); + + it('Rejects calling the hook outside a transfer', async () => { + // Same accounts Token-2022 would pass, but invoked directly. The source + // account's `transferring` flag is only set mid-transfer, so this fails. + const ix = { + programAddress: programId, + accounts: [ + { address: sourceTokenAccount, role: AccountRole.READONLY }, + { address: mint.address, role: AccountRole.READONLY }, + { address: destinationTokenAccount, role: AccountRole.READONLY }, + { address: payer.address, role: AccountRole.READONLY }, + { address: extraAccountMetaList, role: AccountRole.READONLY }, + ], + data: concatBytes(EXECUTE_DISCRIMINATOR, u64(TRANSFER_AMOUNT)), + }; + + const result = svm.sendTransaction(await tx([ix])); + assert.instanceOf(result, FailedTransactionMetadata, 'expected the direct hook call to be rejected'); + + // Pin the reason: the hook must reject with IsNotCurrentlyTransferring + // (custom error 0) after entering Execute, not fail for some other cause. + const logs = (result as FailedTransactionMetadata).meta().logs().join('\n'); + assert.include(logs, 'Instruction: Execute', 'the hook was reached'); + assert.include(logs, 'custom program error: 0x0', 'rejected with IsNotCurrentlyTransferring'); + assert.notInclude(logs, 'Hello Transfer Hook!', 'the hook body did not run'); + }); +}); diff --git a/tokens/token-2022/transfer-hook/hello-world/pinocchio/tsconfig.json b/tokens/token-2022/transfer-hook/hello-world/pinocchio/tsconfig.json new file mode 100644 index 000000000..c02443141 --- /dev/null +++ b/tokens/token-2022/transfer-hook/hello-world/pinocchio/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "types": ["mocha", "chai", "node"], + "typeRoots": ["./node_modules/@types"], + "lib": ["esnext"], + "module": "esnext", + "target": "esnext", + "moduleResolution": "bundler", + "esModuleInterop": true, + "resolveJsonModule": true, + "allowImportingTsExtensions": true, + "noEmit": true, + "skipLibCheck": true + } +} From 4b7e8721c05cfb5e0c604caefea98547becadab7 Mon Sep 17 00:00:00 2001 From: MarkFeder Date: Sun, 30 Aug 2026 22:14:16 +0200 Subject: [PATCH 2/5] transfer-hook hello-world: authenticate the source token account MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit check_is_transferring parsed whatever account the caller passed as the source, so the `transferring` flag it relied on was only as trustworthy as that account. Anyone may call Execute directly, and an account built by the caller with the right bytes at the right offsets reads as a type-15 TransferHookAccount extension with transferring = 1 — passing the guard and reaching the hook body outside any transfer. The flag is only meaningful if Token-2022 wrote it, so the source account is now required to be owned by Token-2022 and to name the mint it was invoked with. A Token-2022 account can only reference a real Token-2022 mint, so the pair pins the source to an account Token-2022 itself produced. This is the guarantee the Anchor version gets from InterfaceAccount and its token::mint constraint. Adds a test that forges an account carrying transferring = 1 for the real mint under a non-Token-2022 owner; it is rejected with InvalidSourceAccount. Against the previous program that same transaction succeeds. --- .../pinocchio/program/src/error.rs | 2 + .../program/src/instructions/transfer_hook.rs | 36 +++++++++++--- .../hello-world/pinocchio/tests/test.ts | 48 +++++++++++++++++++ 3 files changed, 79 insertions(+), 7 deletions(-) diff --git a/tokens/token-2022/transfer-hook/hello-world/pinocchio/program/src/error.rs b/tokens/token-2022/transfer-hook/hello-world/pinocchio/program/src/error.rs index 4f5a3daed..f188c616d 100644 --- a/tokens/token-2022/transfer-hook/hello-world/pinocchio/program/src/error.rs +++ b/tokens/token-2022/transfer-hook/hello-world/pinocchio/program/src/error.rs @@ -9,6 +9,8 @@ pub enum TransferHookError { MissingTransferHookExtension = 1, /// The `TransferHook` extension does not name the expected authority and program. UnexpectedTransferHookConfig = 2, + /// The source account is not a Token-2022 account belonging to the given mint. + InvalidSourceAccount = 3, } impl From for ProgramError { diff --git a/tokens/token-2022/transfer-hook/hello-world/pinocchio/program/src/instructions/transfer_hook.rs b/tokens/token-2022/transfer-hook/hello-world/pinocchio/program/src/instructions/transfer_hook.rs index 8b95b3761..ad6109546 100644 --- a/tokens/token-2022/transfer-hook/hello-world/pinocchio/program/src/instructions/transfer_hook.rs +++ b/tokens/token-2022/transfer-hook/hello-world/pinocchio/program/src/instructions/transfer_hook.rs @@ -3,10 +3,13 @@ use pinocchio_log::log; use crate::{ error::TransferHookError, - instructions::EXTRA_ACCOUNT_METAS_SEED, + instructions::{EXTRA_ACCOUNT_METAS_SEED, TOKEN_2022_PROGRAM_ID}, token2022::{get_extension_data, TRANSFER_HOOK_ACCOUNT}, }; +/// A token account stores its mint in the first 32 bytes. +const TOKEN_ACCOUNT_MINT_RANGE: core::ops::Range = 0..32; + /// The `Execute` instruction of the transfer-hook interface: Token-2022 CPIs /// this during every transfer of a mint that names this program as its hook. /// @@ -35,20 +38,39 @@ pub fn transfer_hook(program_id: &Address, accounts: &mut [AccountView], _data: return Err(ProgramError::InvalidSeeds); } - check_is_transferring(source_token)?; + check_is_transferring(source_token, mint)?; log!("Hello Transfer Hook!"); Ok(()) } -/// Fails unless the source account is mid-transfer. +/// Fails unless the source account is a genuine Token-2022 account for `mint` +/// that is mid-transfer. /// /// Token-2022 raises the `TransferHookAccount` extension's `transferring` flag -/// only for the duration of the transfer it is executing. Checking it is what -/// stops the hook from being invoked directly, outside any transfer — a real -/// hook that grants or records something must not be callable on its own. -fn check_is_transferring(source_token: &AccountView) -> ProgramResult { +/// only for the duration of the transfer it is executing, so the flag is what +/// stops the hook being invoked directly, outside any transfer. +/// +/// The flag is only worth anything if Token-2022 is what wrote it, hence the +/// two checks before it. Anyone can call `Execute` directly and hand over an +/// account they built themselves, and bytes at the right offsets would +/// otherwise read as `transferring = 1`. Requiring Token-2022 ownership *and* +/// that the account names this mint pins it to an account only Token-2022 can +/// have produced — the Anchor version of this example gets the same guarantee +/// from its `InterfaceAccount` and `token::mint = mint` +/// constraints. +fn check_is_transferring(source_token: &AccountView, mint: &AccountView) -> ProgramResult { + if !source_token.owned_by(&TOKEN_2022_PROGRAM_ID) { + return Err(TransferHookError::InvalidSourceAccount.into()); + } + let account_data = source_token.try_borrow()?; + + let account_mint = account_data.get(TOKEN_ACCOUNT_MINT_RANGE).ok_or(TransferHookError::InvalidSourceAccount)?; + if account_mint != mint.address().as_ref() { + return Err(TransferHookError::InvalidSourceAccount.into()); + } + let extension = get_extension_data(&account_data, TRANSFER_HOOK_ACCOUNT) .ok_or(TransferHookError::IsNotCurrentlyTransferring)?; diff --git a/tokens/token-2022/transfer-hook/hello-world/pinocchio/tests/test.ts b/tokens/token-2022/transfer-hook/hello-world/pinocchio/tests/test.ts index 9699c753e..4b94e8bb1 100644 --- a/tokens/token-2022/transfer-hook/hello-world/pinocchio/tests/test.ts +++ b/tokens/token-2022/transfer-hook/hello-world/pinocchio/tests/test.ts @@ -283,4 +283,52 @@ describe('Token-2022 Transfer Hook — Hello World (Pinocchio)', () => { assert.include(logs, 'custom program error: 0x0', 'rejected with IsNotCurrentlyTransferring'); assert.notInclude(logs, 'Hello Transfer Hook!', 'the hook body did not run'); }); + + it('Rejects a forged source account claiming to be transferring', async () => { + // The `transferring` flag is only trustworthy because Token-2022 wrote + // it. Hand-build an account that carries the right bytes at the right + // offsets — a TransferHookAccount TLV (type 15) with transferring = 1, + // naming the real mint — but is owned by someone else. + const forged = new Uint8Array(171); + forged.set(addressEncoder.encode(mint.address), 0); // mint + forged.set(addressEncoder.encode(payer.address), 32); // owner + forged[165] = 2; // account type: Account + forged[166] = 15; // TLV type: TransferHookAccount (u16 LE) + forged[167] = 0; + forged[168] = 1; // TLV length: 1 (u16 LE) + forged[169] = 0; + forged[170] = 1; // transferring = true + + const attacker = await generateKeyPairSigner(); + const forgedSource = (await generateKeyPairSigner()).address; + svm.setAccount({ + address: forgedSource, + data: forged, + executable: false, + lamports: svm.minimumBalanceForRentExemption(BigInt(forged.length)), + programAddress: attacker.address, // not Token-2022 + space: BigInt(forged.length), + }); + + const ix = { + programAddress: programId, + accounts: [ + { address: forgedSource, role: AccountRole.READONLY }, + { address: mint.address, role: AccountRole.READONLY }, + { address: destinationTokenAccount, role: AccountRole.READONLY }, + { address: payer.address, role: AccountRole.READONLY }, + { address: extraAccountMetaList, role: AccountRole.READONLY }, + ], + data: concatBytes(EXECUTE_DISCRIMINATOR, u64(TRANSFER_AMOUNT)), + }; + + const result = svm.sendTransaction(await tx([ix])); + assert.instanceOf(result, FailedTransactionMetadata, 'expected the forged source account to be rejected'); + + // Rejected as an invalid source account (custom error 3) — the forged + // transferring flag must never reach the hook body. + const logs = (result as FailedTransactionMetadata).meta().logs().join('\n'); + assert.include(logs, 'custom program error: 0x3', 'rejected with InvalidSourceAccount'); + assert.notInclude(logs, 'Hello Transfer Hook!', 'the hook body did not run'); + }); }); From 506d711bc3afaae28b8c933af01c5ef85936fc1e Mon Sep 17 00:00:00 2001 From: MarkFeder Date: Sun, 30 Aug 2026 22:24:51 +0200 Subject: [PATCH 3/5] transfer-hook hello-world: brand the forged account's lamports as Lamports CI's tsc --noEmit step rejected the raw bigint returned by minimumBalanceForRentExemption where EncodedAccount expects the branded Lamports type. --- .../transfer-hook/hello-world/pinocchio/tests/test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tokens/token-2022/transfer-hook/hello-world/pinocchio/tests/test.ts b/tokens/token-2022/transfer-hook/hello-world/pinocchio/tests/test.ts index 4b94e8bb1..4bb8a7ed7 100644 --- a/tokens/token-2022/transfer-hook/hello-world/pinocchio/tests/test.ts +++ b/tokens/token-2022/transfer-hook/hello-world/pinocchio/tests/test.ts @@ -305,7 +305,7 @@ describe('Token-2022 Transfer Hook — Hello World (Pinocchio)', () => { address: forgedSource, data: forged, executable: false, - lamports: svm.minimumBalanceForRentExemption(BigInt(forged.length)), + lamports: lamports(svm.minimumBalanceForRentExemption(BigInt(forged.length))), programAddress: attacker.address, // not Token-2022 space: BigInt(forged.length), }); From 23ef7c034a5dce7c1cf4c80f341dc3d30e9f4f21 Mon Sep 17 00:00:00 2001 From: MarkFeder Date: Mon, 31 Aug 2026 11:27:41 +0200 Subject: [PATCH 4/5] token-2022 transfer-hook hello-world: verify the mint names this program as its hook Execute only checked that the source account was a genuine Token-2022 account mid-transfer. A mint configured with a *different* hook program is mid-transfer too while that program runs, and that program can CPI here with the genuine source account, passing every check and running the hook body outside its configured path. Read the hook program back off the mint's TransferHook extension and reject anything that is not this program. Covered by a test that is verified to succeed without the check. --- .../program/src/instructions/transfer_hook.rs | 29 ++++- .../hello-world/pinocchio/tests/test.ts | 105 ++++++++++++++++++ 2 files changed, 133 insertions(+), 1 deletion(-) diff --git a/tokens/token-2022/transfer-hook/hello-world/pinocchio/program/src/instructions/transfer_hook.rs b/tokens/token-2022/transfer-hook/hello-world/pinocchio/program/src/instructions/transfer_hook.rs index ad6109546..ea6deaea5 100644 --- a/tokens/token-2022/transfer-hook/hello-world/pinocchio/program/src/instructions/transfer_hook.rs +++ b/tokens/token-2022/transfer-hook/hello-world/pinocchio/program/src/instructions/transfer_hook.rs @@ -4,12 +4,16 @@ use pinocchio_log::log; use crate::{ error::TransferHookError, instructions::{EXTRA_ACCOUNT_METAS_SEED, TOKEN_2022_PROGRAM_ID}, - token2022::{get_extension_data, TRANSFER_HOOK_ACCOUNT}, + token2022::{get_extension_data, TRANSFER_HOOK, TRANSFER_HOOK_ACCOUNT}, }; /// A token account stores its mint in the first 32 bytes. const TOKEN_ACCOUNT_MINT_RANGE: core::ops::Range = 0..32; +/// Within a mint's `TransferHook` extension value, the hook program follows the +/// 32-byte extension authority. +const MINT_HOOK_PROGRAM_RANGE: core::ops::Range = 32..64; + /// The `Execute` instruction of the transfer-hook interface: Token-2022 CPIs /// this during every transfer of a mint that names this program as its hook. /// @@ -38,12 +42,35 @@ pub fn transfer_hook(program_id: &Address, accounts: &mut [AccountView], _data: return Err(ProgramError::InvalidSeeds); } + check_hook_is_self(mint, program_id)?; check_is_transferring(source_token, mint)?; log!("Hello Transfer Hook!"); Ok(()) } +/// Fails unless `mint` actually names this program as its transfer hook. +/// +/// Being mid-transfer is not on its own a reason to run: a mint configured with +/// a *different* hook program is also mid-transfer while that program runs, and +/// that program is free to CPI here with the genuine source account, passing +/// every other check. Reading the hook back off the mint is what keeps this +/// body to the transfers it was actually configured for — the Anchor version +/// gets the same guarantee from its `extra_account_meta_list` seeds being +/// checked against a mint it has already deserialized as its own. +fn check_hook_is_self(mint: &AccountView, program_id: &Address) -> ProgramResult { + let mint_data = mint.try_borrow()?; + let extension = + get_extension_data(&mint_data, TRANSFER_HOOK).ok_or(TransferHookError::MissingTransferHookExtension)?; + + let hook_program = extension.get(MINT_HOOK_PROGRAM_RANGE).ok_or(TransferHookError::UnexpectedTransferHookConfig)?; + if hook_program != program_id.as_ref() { + return Err(TransferHookError::UnexpectedTransferHookConfig.into()); + } + + Ok(()) +} + /// Fails unless the source account is a genuine Token-2022 account for `mint` /// that is mid-transfer. /// diff --git a/tokens/token-2022/transfer-hook/hello-world/pinocchio/tests/test.ts b/tokens/token-2022/transfer-hook/hello-world/pinocchio/tests/test.ts index 4bb8a7ed7..8e18ed236 100644 --- a/tokens/token-2022/transfer-hook/hello-world/pinocchio/tests/test.ts +++ b/tokens/token-2022/transfer-hook/hello-world/pinocchio/tests/test.ts @@ -61,6 +61,21 @@ function u64(n: bigint): Uint8Array { new DataView(b.buffer).setBigUint64(0, n, true); return b; } +// Walks the Token-2022 TLV list (which starts at offset 166 on both mints and +// token accounts) and returns where `type`'s value begins, so tests can patch a +// single extension field without rebuilding the whole account. +function tlvValueOffset(data: Uint8Array, type: number): number { + let cursor = 166; + while (cursor + 4 <= data.length) { + const entryType = data[cursor] | (data[cursor + 1] << 8); + if (entryType === 0) break; + const length = data[cursor + 2] | (data[cursor + 3] << 8); + if (entryType === type) return cursor + 4; + cursor += 4 + length; + } + throw new Error(`extension ${type} not found`); +} + function concatBytes(...parts: Uint8Array[]): Uint8Array { const out = new Uint8Array(parts.reduce((n, p) => n + p.length, 0)); let offset = 0; @@ -129,6 +144,24 @@ describe('Token-2022 Transfer Hook — Hello World (Pinocchio)', () => { return result; } + // Rewrites an existing account's data in place, keeping its owner. Used to + // put a genuine Token-2022 account into a state a test cannot reach on its + // own — a mint pointed at another hook, or an account mid-transfer. + function rewriteAccount(address: Address, mutate: (data: Uint8Array) => void) { + const account = svm.getAccount(address); + if (!account?.exists) throw new Error(`account ${address} not found`); + const data = new Uint8Array(account.data); + mutate(data); + svm.setAccount({ + address, + data, + executable: false, + lamports: account.lamports, + programAddress: account.programAddress, + space: BigInt(data.length), + }); + } + function tokenAmount(account: Address): bigint { const acc = svm.getAccount(account); if (!acc?.exists) throw new Error('token account not found'); @@ -331,4 +364,76 @@ describe('Token-2022 Transfer Hook — Hello World (Pinocchio)', () => { assert.include(logs, 'custom program error: 0x3', 'rejected with InvalidSourceAccount'); assert.notInclude(logs, 'Hello Transfer Hook!', 'the hook body did not run'); }); + + it('Rejects a mint configured with a different hook program', async () => { + // A mint whose hook is some *other* program is mid-transfer too while + // that program runs, and that program can CPI here with the genuine + // source account — passing the ownership, mint and transferring checks. + // Only the mint's own TransferHook config distinguishes the two cases. + const otherMint = await generateKeyPairSigner(); + const otherHookProgram = (await generateKeyPairSigner()).address; + + const initOtherMintIx = { + programAddress: programId, + accounts: [ + { address: payer.address, role: AccountRole.WRITABLE_SIGNER, signer: payer }, + { address: otherMint.address, role: AccountRole.WRITABLE_SIGNER, signer: otherMint }, + { address: TOKEN_2022_PROGRAM_ADDRESS, role: AccountRole.READONLY }, + { address: SYSTEM_PROGRAM_ADDRESS, role: AccountRole.READONLY }, + ], + data: Uint8Array.of(INITIALIZE_DISCRIMINATOR, DECIMALS), + }; + send(await tx([initOtherMintIx]), 'initialize other mint'); + + // Repoint the genuine mint at the other hook program: the extension + // value is `authority (32) || hook program (32)`. + rewriteAccount(otherMint.address, data => { + data.set(addressEncoder.encode(otherHookProgram), tlvValueOffset(data, 14) + 32); + }); + + const [otherSource] = await findAssociatedTokenPda({ + owner: payer.address, + mint: otherMint.address, + tokenProgram: TOKEN_2022_PROGRAM_ADDRESS, + }); + send( + await tx([ + getCreateAssociatedTokenInstruction( + { payer, ata: otherSource, owner: payer.address, mint: otherMint.address }, + { programAddress: ASSOCIATED_TOKEN_PROGRAM_ADDRESS }, + ), + ]), + 'create other source token account', + ); + + // Put it mid-transfer, exactly as Token-2022 would for the other hook. + rewriteAccount(otherSource, data => { + data[tlvValueOffset(data, 15)] = 1; + }); + + const [otherMetaList] = await getProgramDerivedAddress({ + programAddress: programId, + seeds: ['extra-account-metas', addressEncoder.encode(otherMint.address)], + }); + + const ix = { + programAddress: programId, + accounts: [ + { address: otherSource, role: AccountRole.READONLY }, + { address: otherMint.address, role: AccountRole.READONLY }, + { address: otherSource, role: AccountRole.READONLY }, + { address: payer.address, role: AccountRole.READONLY }, + { address: otherMetaList, role: AccountRole.READONLY }, + ], + data: concatBytes(EXECUTE_DISCRIMINATOR, u64(TRANSFER_AMOUNT)), + }; + + const result = svm.sendTransaction(await tx([ix])); + assert.instanceOf(result, FailedTransactionMetadata, 'expected a foreign hook mint to be rejected'); + + // Rejected as an unexpected hook config (custom error 2). + const logs = (result as FailedTransactionMetadata).meta().logs().join('\n'); + assert.include(logs, 'custom program error: 0x2', 'rejected with UnexpectedTransferHookConfig'); + assert.notInclude(logs, 'Hello Transfer Hook!', 'the hook body did not run'); + }); }); From 84725b6278d40f3acfeb3ccf11f68b6bc8883cbd Mon Sep 17 00:00:00 2001 From: MarkFeder Date: Mon, 31 Aug 2026 15:12:29 +0200 Subject: [PATCH 5/5] token-2022 transfer-hook hello-world: create the metas PDA over a pre-funded address --- .../initialize_extra_account_meta_list.rs | 21 ++-------- .../hello-world/pinocchio/program/src/lib.rs | 1 + .../hello-world/pinocchio/program/src/util.rs | 38 +++++++++++++++++++ .../hello-world/pinocchio/tests/test.ts | 13 +++++++ 4 files changed, 55 insertions(+), 18 deletions(-) create mode 100644 tokens/token-2022/transfer-hook/hello-world/pinocchio/program/src/util.rs diff --git a/tokens/token-2022/transfer-hook/hello-world/pinocchio/program/src/instructions/initialize_extra_account_meta_list.rs b/tokens/token-2022/transfer-hook/hello-world/pinocchio/program/src/instructions/initialize_extra_account_meta_list.rs index 44c242b82..17b642062 100644 --- a/tokens/token-2022/transfer-hook/hello-world/pinocchio/program/src/instructions/initialize_extra_account_meta_list.rs +++ b/tokens/token-2022/transfer-hook/hello-world/pinocchio/program/src/instructions/initialize_extra_account_meta_list.rs @@ -1,13 +1,7 @@ -use pinocchio::{ - cpi::{Seed, Signer}, - error::ProgramError, - sysvars::{rent::Rent, Sysvar}, - AccountView, Address, ProgramResult, -}; +use pinocchio::{cpi::Seed, error::ProgramError, AccountView, Address, ProgramResult}; use pinocchio_log::log; -use pinocchio_system::instructions::CreateAccount; -use crate::instructions::EXTRA_ACCOUNT_METAS_SEED; +use crate::{instructions::EXTRA_ACCOUNT_METAS_SEED, util::create_pda_account}; /// A serialized, empty `ExtraAccountMetaList`. /// @@ -61,17 +55,8 @@ pub fn initialize_extra_account_meta_list(program_id: &Address, accounts: &mut [ let bump_bytes = [bump]; let seeds = [Seed::from(EXTRA_ACCOUNT_METAS_SEED), Seed::from(mint.address().as_ref()), Seed::from(&bump_bytes)]; - let lamports = Rent::get()?.try_minimum_balance(EXTRA_ACCOUNT_METAS_DATA.len())?; - log!("Creating extra account meta list"); - CreateAccount { - from: payer, - to: extra_account_meta_list, - lamports, - space: EXTRA_ACCOUNT_METAS_DATA.len() as u64, - owner: program_id, - } - .invoke_signed(&[Signer::from(&seeds)])?; + create_pda_account(payer, extra_account_meta_list, EXTRA_ACCOUNT_METAS_DATA.len(), program_id, &seeds)?; let mut account_data = extra_account_meta_list.try_borrow_mut()?; account_data.copy_from_slice(&EXTRA_ACCOUNT_METAS_DATA); diff --git a/tokens/token-2022/transfer-hook/hello-world/pinocchio/program/src/lib.rs b/tokens/token-2022/transfer-hook/hello-world/pinocchio/program/src/lib.rs index c81917e85..fe27c8444 100644 --- a/tokens/token-2022/transfer-hook/hello-world/pinocchio/program/src/lib.rs +++ b/tokens/token-2022/transfer-hook/hello-world/pinocchio/program/src/lib.rs @@ -9,6 +9,7 @@ pub mod error; pub mod instructions; pub mod processor; pub mod token2022; +pub mod util; use pinocchio::{entrypoint, nostd_panic_handler}; diff --git a/tokens/token-2022/transfer-hook/hello-world/pinocchio/program/src/util.rs b/tokens/token-2022/transfer-hook/hello-world/pinocchio/program/src/util.rs new file mode 100644 index 000000000..94d1dc68e --- /dev/null +++ b/tokens/token-2022/transfer-hook/hello-world/pinocchio/program/src/util.rs @@ -0,0 +1,38 @@ +//! Shared account-creation helper. + +use pinocchio::{ + cpi::{Seed, Signer}, + sysvars::{rent::Rent, Sysvar}, + AccountView, Address, ProgramResult, +}; +use pinocchio_system::instructions::{Allocate, Assign, Transfer}; + +/// Creates `account` at a PDA, tolerating an address that already holds +/// lamports. +/// +/// `CreateAccount` fails outright if the target has a balance, and every PDA +/// here has a publicly derivable address — so anyone could send one lamport to +/// one of these addresses and permanently block the instruction that was +/// meant to create it. Topping the account up and then allocating and assigning +/// it separately sidesteps that; it is the same fallback Anchor's `init` +/// performs. +pub fn create_pda_account( + payer: &AccountView, + account: &mut AccountView, + space: usize, + owner: &Address, + seeds: &[Seed], +) -> ProgramResult { + let required = Rent::get()?.try_minimum_balance(space)?; + let current = account.lamports(); + + if current < required { + Transfer { from: payer, to: account, lamports: required - current }.invoke()?; + } + + let signer = [Signer::from(seeds)]; + Allocate { account, space: space as u64 }.invoke_signed(&signer)?; + Assign { account, owner }.invoke_signed(&signer)?; + + Ok(()) +} diff --git a/tokens/token-2022/transfer-hook/hello-world/pinocchio/tests/test.ts b/tokens/token-2022/transfer-hook/hello-world/pinocchio/tests/test.ts index 8e18ed236..45e94b7fe 100644 --- a/tokens/token-2022/transfer-hook/hello-world/pinocchio/tests/test.ts +++ b/tokens/token-2022/transfer-hook/hello-world/pinocchio/tests/test.ts @@ -200,6 +200,19 @@ describe('Token-2022 Transfer Hook — Hello World (Pinocchio)', () => { }); it('Creates the ExtraAccountMetaList account', async () => { + // The list's address is publicly derivable from the mint, and + // `CreateAccount` refuses to create over an account that already holds + // lamports — so a stray lamport would otherwise block this mint from + // ever being set up. Drop one there first. + svm.setAccount({ + address: extraAccountMetaList, + data: new Uint8Array(0), + executable: false, + lamports: lamports(1n), + programAddress: SYSTEM_PROGRAM_ADDRESS, + space: 0n, + }); + const ix = { programAddress: programId, accounts: [