diff --git a/Cargo.lock b/Cargo.lock index 2a87face1..561e962ac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1670,6 +1670,18 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "fundraiser-pinocchio-program" +version = "0.1.0" +dependencies = [ + "pinocchio", + "pinocchio-associated-token-account", + "pinocchio-log", + "pinocchio-system", + "pinocchio-token", + "solana-address 2.6.1", +] + [[package]] name = "funty" version = "2.0.0" diff --git a/Cargo.toml b/Cargo.toml index f703dde94..28e77cbf0 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-fundraiser/pinocchio/program", ] resolver = "2" diff --git a/tokens/token-fundraiser/pinocchio/cicd.sh b/tokens/token-fundraiser/pinocchio/cicd.sh new file mode 100644 index 000000000..e41db2140 --- /dev/null +++ b/tokens/token-fundraiser/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-fundraiser/pinocchio/package.json b/tokens/token-fundraiser/pinocchio/package.json new file mode 100644 index 000000000..dc8beffad --- /dev/null +++ b/tokens/token-fundraiser/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": "^0.15.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-fundraiser/pinocchio/pnpm-lock.yaml b/tokens/token-fundraiser/pinocchio/pnpm-lock.yaml new file mode 100644 index 000000000..1cbdeb21f --- /dev/null +++ b/tokens/token-fundraiser/pinocchio/pnpm-lock.yaml @@ -0,0 +1,2892 @@ +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': + specifier: ^0.15.0 + version: 0.15.0(@solana/kit@7.1.1(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.12 + 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'} + + '@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.13.0': + resolution: {integrity: sha512-Id6QQxCG7ByImXPD5X/c3Ag2kySD+49aJ9waIkfxyUFyokhMQgxYQAx2rKuaygaBlaBQY6VVfBS46pqxZV+99A==} + peerDependencies: + '@solana/kit': ^7.0.0 + + '@solana-program/system@0.14.0': + resolution: {integrity: sha512-Pjs2RINZHYmk/pqWNBCuQmfNjZT9woPJ/w7QkzzCSwcqcokbARtxsnIdgj4lJVxvr1DuxG8JGIbKnq6z1QRY6Q==} + peerDependencies: + '@solana/kit': ^8.0.0 + + '@solana-program/token@0.15.0': + resolution: {integrity: sha512-SeLm08EYIfT453I6lo7wTGgfMbz1s7bJ1jSHFHBFebSJHD3xF46zRgMxq3YKRlr/RM8jN0cG8SjZVu+IDvMxEA==} + engines: {node: '>=24.0.0'} + peerDependencies: + '@solana/kit': ^7.0.0 + + '@solana-program/token@0.16.0': + resolution: {integrity: sha512-VuFIu5vXsw1zwqls4/sGB88234oucmpuig553A33UnrbYnPZ8yXmqLYULBD92/k1pCGnMK+NMLWvsKzlZQ/1Kw==} + engines: {node: '>=24.0.0'} + peerDependencies: + '@solana/kit': ^8.0.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.1.0': + resolution: {integrity: sha512-28u6+aw2pc1pL9ZHtrHVLy/vzaORFcVDR+lZy24uy6Z2N/LLsVbaGOLihKD2ksNmu9y2xOn7deqsG9SSFXwKvg==} + 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.1.0': + resolution: {integrity: sha512-oqoiiNMjcf2mY1lnDE3SXDeifilUytNXxTK38DfSEbPYf+KSO7p+fsEcjC7/EuONo+swMIQfE9WtXdMRu3l/9g==} + 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.1.0': + resolution: {integrity: sha512-D3fFyyAFBVFoOICW8AtVMg7CK5+SdGcICHIQ/DJ/4cxypmsJOO8U9gaxU67/zMmuGAlnGNsUxdYCzDxoFC+iVg==} + 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.1.0': + resolution: {integrity: sha512-ClBbCrHbxgibtSZp3G+3S2PYFaw2Slx229KbFAXcZ52TAXgVRnXgNOY7HpURbmxnBFzEHSMu9u1zR7Ap8Tfk+g==} + 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.1.0': + resolution: {integrity: sha512-XmHx2kt5ni/mukLMHQRNobrzEIXKu9EmDqVO8qJU7NGkxtWYgUxETB7NfpoBXY2YSdWNfnuG+4FAi+V2cxcDKA==} + 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.1.0': + resolution: {integrity: sha512-3qVIu0Fqx5dgBri+bE65d02dA7wvGdg4t9t8PJl4vvdUu/d531YhqAIqTLMSGuC+TeemAZa5FRsT5okuvqrb/g==} + 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.1.0': + resolution: {integrity: sha512-Mhq97DN2y7KFTRuxrEEyXvVuYrPLn1VZKv0h8D0yvK0RMdWmEBRUC2kucc9cVlV53Z+RrS4ovGICtnf+ZkFoYw==} + 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.1.0': + resolution: {integrity: sha512-hjxbwWVjEcBVF7AWgsZWftPK/d3Xqj43ed9gV3X00zYNXFXvobEgZEjtu9NCOUb85LFUaRam99Mub/vqSlWrjQ==} + 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.1.0': + resolution: {integrity: sha512-dCuQR9nSVp4GBESLpOOIH84px5REySC4V5TMbR1PvkI09DU1BV8Pi/4W466enijO8NXCKwkL5YLNHdn97KBPDA==} + 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.1.0': + resolution: {integrity: sha512-BdiWGZRGwb4ExG/EQq9mAqhQI0weJZ3ikDQuI10IvOrhm1ukkZ2OhM0UXhKgRbnX3mjkmm6Iufyn9cTTZzWgRg==} + 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.1.0': + resolution: {integrity: sha512-WAHdYPKBk3hXvpYyJkUPzFTnpQAeGzDlIjskPXdCfPTT15o8+dSlN6nfPWz+EVZ33+8REkXyvuyQ7eW99j7iMg==} + 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.1.0': + resolution: {integrity: sha512-x1qTNhYttsiqyuhsWOJyVfZIrKlf666hi+P2+NnkxxDFUm3RTDS9czIUVUQ9gdnLpJ73dGkYZkfEIDRx6zTRdw==} + 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.1.0': + resolution: {integrity: sha512-GLSCWzIf080Uej6wQF/QIgSMFgJ3ZbUZ29jdUhcThypxyLlQnxIaD7iwPLwuPnW7jNN9q/4xTcpvHlfsvfXxRA==} + 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.1.0': + resolution: {integrity: sha512-uHq7EzR+0aGXH/lYiHS5QgDh8KWdJ7OiKzijqcYznTfpyM0bX15JtNhwL8BzMmQInlI2LOYwoe6tFCpP4GsDQw==} + 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.1.0': + resolution: {integrity: sha512-L6Sx0yY4PAjGuzHtzq8r20Yacvv48c16CXFeZV5Neci1SC7pJq1wRiOmdEtTzZ1Cghilfm6IQwMnRo1B4Q6ajw==} + 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.1.0': + resolution: {integrity: sha512-TLbHYh5SWe2e4xSYHhWT3oFub2guMVyJcGurUtQ0ij2u0lH80IkqeWUsDUWdroKF1AAYkXbZPuWdRO51IuY4gg==} + 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.1.0': + resolution: {integrity: sha512-FRdH8A1FU6glQohUZhGPoRREFDp5kDA98M5veCrL+MP2rm37Ws4JPY/yJZ0mpcu0kmEJTrT0x5wiNJtRUQbQhA==} + 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.1.0': + resolution: {integrity: sha512-IdpxHMlOuONS0vVxZViDRhhqaShG++hO4/wRlp5NMb/0WODSTTRTIIrDOmhiioTmOKJ9PIM6gAxtRys5/5uNHA==} + 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.1.0': + resolution: {integrity: sha512-8DcPRNlH91OHpxql22lLdagMI+FRb4MDKwPntvQhNAeLaGck70xVqmgR2E+oZj7w2whzRXpKRWy+uRLPhy3R/Q==} + 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.1.0': + resolution: {integrity: sha512-xrfErUO9WaUhxfmyMjVxoWHEVF1yxWQEAF491ur4CgDpfL8UnhV0tiWp1+6duOplgRkEIEnARuS83S4YZjSgOg==} + 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.1.0': + resolution: {integrity: sha512-4Ck5NnwCI/LKFlFvDzbycIXk38ZcHHup9SIcXs0ixmjngRRqvToXHoSJMeKcrmbc9jvg71IDVDav+ibm/68t3w==} + 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.1.0': + resolution: {integrity: sha512-R1qsD89GhW8xdfekk8ph7C2KK8aeYhhz5Z5nLJy9DZMDFFsWP7tj0tZW/sY0yFVqKsIsIBzdthiOC3npktNH4A==} + 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.1.0': + resolution: {integrity: sha512-wDRP/tZuqzjQAuX+Ce5ZbWlFrdtX5qZSC3VvKJAGqe4XaxHiREOCZ78+N+0IWJYsyvK1FEzzaJAGVQ6RsovMRQ==} + 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.1.0': + resolution: {integrity: sha512-tx904NuIXOi/SUqxBQb53yIa7/iYM9QdwUX96IPhnzJrkmnW28/k2rZ+4fTzIaaY/ATouoE9zUJH0vm5v6R08A==} + 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.1.0': + resolution: {integrity: sha512-vMhz0bKCol7DTDoevWLCKXmIUQqhDonB8660rT2SNuo6ETSm+pHmUdsbkif4fpOeBS/YKDcr47Sy8zDXLPiutQ==} + 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.1.0': + resolution: {integrity: sha512-3tPIXReVJQ6e4zZnMAkX/qSg35YeZ8n2OqbmXOolNj6tVeOUWY4jBM1XFOw8AZZ54qShAwMckBokyGiJoEx9Zg==} + 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.1.0': + resolution: {integrity: sha512-t/hkyeA2dMxQoRrFTfut5Mm6IJeQm/xaHXlmznivgfZFYfdVInQLwSnNsj3aaQRdTpuFnLDFViM+1VtqDAV/qw==} + 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.1.0': + resolution: {integrity: sha512-IduXbEBtRtHP+UWe5FJZwfX24o7aiw1IuIDhDktfOduo26Meo7rml+qvxusSehaRK7lLXHAl52L9np5K91MveQ==} + 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.1.0': + resolution: {integrity: sha512-P5kdtzM48/quxGy+IWkcpDtX7+akFafb+ckBORdKFnXntuwtjI+bMvT86rjMjtsBIza0ytdKgE786tQtrLQxdA==} + 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.1.0': + resolution: {integrity: sha512-LI7kxSez9ev0p5w5oQQW+Z//Niu2wRkoiGIeC5C0DhBwYbaCNyXGxYYCrGbJfTYJyaa9H/BpXUOncQSeDpLoYQ==} + 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.1.0': + resolution: {integrity: sha512-VqLBOXFqxeyGMcOuJBX8EKdksy9dooZz74oU7w6fG636W+Du2oFsp/hVd2rsXbCK/8PVAthP3DkKjDkMSjNMow==} + 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.1.0': + resolution: {integrity: sha512-GiFe3oFuzZs3S/oeVDumzQc/+3lCc3k/9/T43Bhdi8f9ctsAN2S9X5tADAgh6ZngP9p0BT5yecNEBny+jL/7Yg==} + 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.1.0': + resolution: {integrity: sha512-axr/EZ4CKKPW2rzSkNpC9rG5H5I93sQdJFs60SMXMUMnlzc9FdxTTBldlbNntEroKu3ff6ghXkL9o/2SIW6erw==} + 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.1.0': + resolution: {integrity: sha512-lIW66Ly9yOa6SXCAAw07N99miqkEpRQoOYgyVEjMVX2Us+g1+UdnCOJ5DKkpkE1q68RY9C1qcZHnw54yTSjWWw==} + 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.1.0': + resolution: {integrity: sha512-/R84MZZwW6U3a13QNt2uHDyir26r/ETAa3xuj4XWsQ9Y9GyxwIYQmOerrEQWzLruXhuP9sSomRWRmzON3QIxVw==} + 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.1.0': + resolution: {integrity: sha512-Hc8cKx5ZHiz2cW/OlfpCSVUNS7kH9oxcOmVfdWZWeF8L/1QM7pYAcq29WyC9X2jrX5TvHqB0jqouOBNElrSbTA==} + 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.1.0': + resolution: {integrity: sha512-6975HRg5RBFZrnaYqJxSZ861CSTorogq4pBZ6NfrjPFzQdo8nlmA0Fpbc9aYk4uV0l3o70ZPyVtr5w6/fazTwg==} + 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.1.0': + resolution: {integrity: sha512-XOqc8y4WK2Kg/so7LfNWEy6eQ7DE8nGKxvh9ouVeayo3QcggGgFkWpBiw3fx2l6otFDTXFKkT3v7J/yT8rm/Ng==} + 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.1.0': + resolution: {integrity: sha512-YXaws30Q0gMTu/4h0y/T+MYtQr8MS/XQo4PTQts4TAmCVaxU2+yZra+kNO9Yj7DEcir9vDnb18Hb95/hnErDfg==} + 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.1.0': + resolution: {integrity: sha512-VLVXn+QVhb58bCxBvEBSvxSapEOKMJ71rMG5RSRza8JyV6fgZSxMme34M7SJYB5s2OMcyRg91FiIaae+nKIgOg==} + 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.1.0': + resolution: {integrity: sha512-bUYCr2pm/F3M7mTmnVZ/R7XjAmDd0fxO5bGVlryJ4ZGOAQI65y003nEwlSaNGDx3g/ZkjzpshchJHhaeMlYM/Q==} + 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.1.0': + resolution: {integrity: sha512-AbZYIxPbosnM3rFUwntvMLOZex8syNaU+StvlriB74XZyLt3mjC/V5aA1/Gv6XmS/aaJ74OqQ5QjS2ui1VCgBQ==} + 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.1.0': + resolution: {integrity: sha512-fH29RT9c0VwgS1rca9doPAalXJ0YAzvnpuy3VoOEqMCr9NvgLMpP6k9EuJAfBBNpek9u0uErTz72qIPbObHNwA==} + 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.12: + resolution: {integrity: sha512-FDf4L4sYzKtzWYhU/Xm0AQFdTjdIxNo9ElTf2mxXM6k8YMHXzYUe4yODVaXP4V9uMFbVg8c0qyBccK2OOxb45Q==} + 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 + + '@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.13.0(@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.1.0(typescript@5.9.3))': + dependencies: + '@solana/kit': 8.1.0(typescript@5.9.3) + + '@solana-program/token@0.15.0(@solana/kit@7.1.1(typescript@5.9.3))': + dependencies: + '@solana-program/system': 0.13.0(@solana/kit@7.1.1(typescript@5.9.3)) + '@solana/kit': 7.1.1(typescript@5.9.3) + + '@solana-program/token@0.16.0(@solana/kit@8.1.0(typescript@5.9.3))': + dependencies: + '@solana-program/system': 0.14.0(@solana/kit@8.1.0(typescript@5.9.3)) + '@solana/kit': 8.1.0(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.1.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.1.0(typescript@5.9.3) + '@solana/codecs-core': 8.1.0(typescript@5.9.3) + '@solana/codecs-strings': 8.1.0(typescript@5.9.3) + '@solana/errors': 8.1.0(typescript@5.9.3) + '@solana/rpc-spec': 8.1.0(typescript@5.9.3) + '@solana/rpc-types': 8.1.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.1.0(typescript@5.9.3)': + dependencies: + '@solana/assertions': 8.1.0(typescript@5.9.3) + '@solana/codecs-core': 8.1.0(typescript@5.9.3) + '@solana/codecs-strings': 8.1.0(typescript@5.9.3) + '@solana/errors': 8.1.0(typescript@5.9.3) + '@solana/nominal-types': 8.1.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.1.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.1.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.1.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.1.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.1.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 8.1.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.1.0(typescript@5.9.3) + '@solana/errors': 8.1.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.1.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 8.1.0(typescript@5.9.3) + '@solana/errors': 8.1.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.1.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 8.1.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.1.0(typescript@5.9.3) + '@solana/errors': 8.1.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.1.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 8.1.0(typescript@5.9.3) + '@solana/codecs-data-structures': 8.1.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.1.0(typescript@5.9.3) + '@solana/codecs-strings': 8.1.0(typescript@5.9.3) + '@solana/fixed-points': 8.1.0(typescript@5.9.3) + '@solana/options': 8.1.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.1.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.1.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.1.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 8.1.0(typescript@5.9.3) + '@solana/errors': 8.1.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.1.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.1.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.1.0(typescript@5.9.3) + '@solana/instructions': 8.1.0(typescript@5.9.3) + '@solana/keys': 8.1.0(typescript@5.9.3) + '@solana/promises': 8.1.0(typescript@5.9.3) + '@solana/transaction-messages': 8.1.0(typescript@5.9.3) + '@solana/transactions': 8.1.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.1.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 8.1.0(typescript@5.9.3) + '@solana/errors': 8.1.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.1.0(typescript@5.9.3)': + dependencies: + '@solana/assertions': 8.1.0(typescript@5.9.3) + '@solana/codecs-core': 8.1.0(typescript@5.9.3) + '@solana/codecs-strings': 8.1.0(typescript@5.9.3) + '@solana/errors': 8.1.0(typescript@5.9.3) + '@solana/nominal-types': 8.1.0(typescript@5.9.3) + '@solana/promises': 8.1.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.1.0(typescript@5.9.3)': + dependencies: + '@solana/accounts': 8.1.0(typescript@5.9.3) + '@solana/addresses': 8.1.0(typescript@5.9.3) + '@solana/codecs': 8.1.0(typescript@5.9.3) + '@solana/errors': 8.1.0(typescript@5.9.3) + '@solana/functional': 8.1.0(typescript@5.9.3) + '@solana/instruction-plans': 8.1.0(typescript@5.9.3) + '@solana/instructions': 8.1.0(typescript@5.9.3) + '@solana/keys': 8.1.0(typescript@5.9.3) + '@solana/offchain-messages': 8.1.0(typescript@5.9.3) + '@solana/plugin-core': 8.1.0(typescript@5.9.3) + '@solana/plugin-interfaces': 8.1.0(typescript@5.9.3) + '@solana/program-client-core': 8.1.0(typescript@5.9.3) + '@solana/programs': 8.1.0(typescript@5.9.3) + '@solana/promises': 8.1.0(typescript@5.9.3) + '@solana/rpc': 8.1.0(typescript@5.9.3) + '@solana/rpc-api': 8.1.0(typescript@5.9.3) + '@solana/rpc-parsed-types': 8.1.0(typescript@5.9.3) + '@solana/rpc-spec-types': 8.1.0(typescript@5.9.3) + '@solana/rpc-subscriptions': 8.1.0(typescript@5.9.3) + '@solana/rpc-types': 8.1.0(typescript@5.9.3) + '@solana/signers': 8.1.0(typescript@5.9.3) + '@solana/subscribable': 8.1.0(typescript@5.9.3) + '@solana/sysvars': 8.1.0(typescript@5.9.3) + '@solana/transaction-confirmation': 8.1.0(typescript@5.9.3) + '@solana/transaction-introspection': 8.1.0(typescript@5.9.3) + '@solana/transaction-messages': 8.1.0(typescript@5.9.3) + '@solana/transactions': 8.1.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.1.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.1.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.1.0(typescript@5.9.3) + '@solana/codecs-core': 8.1.0(typescript@5.9.3) + '@solana/codecs-data-structures': 8.1.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.1.0(typescript@5.9.3) + '@solana/codecs-strings': 8.1.0(typescript@5.9.3) + '@solana/errors': 8.1.0(typescript@5.9.3) + '@solana/keys': 8.1.0(typescript@5.9.3) + '@solana/nominal-types': 8.1.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.1.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 8.1.0(typescript@5.9.3) + '@solana/codecs-data-structures': 8.1.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.1.0(typescript@5.9.3) + '@solana/codecs-strings': 8.1.0(typescript@5.9.3) + '@solana/errors': 8.1.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.1.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.1.0(typescript@5.9.3)': + dependencies: + '@solana/accounts': 8.1.0(typescript@5.9.3) + '@solana/addresses': 8.1.0(typescript@5.9.3) + '@solana/instruction-plans': 8.1.0(typescript@5.9.3) + '@solana/keys': 8.1.0(typescript@5.9.3) + '@solana/rpc-spec': 8.1.0(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 8.1.0(typescript@5.9.3) + '@solana/rpc-types': 8.1.0(typescript@5.9.3) + '@solana/signers': 8.1.0(typescript@5.9.3) + '@solana/transactions': 8.1.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.1.0(typescript@5.9.3)': + dependencies: + '@solana/accounts': 8.1.0(typescript@5.9.3) + '@solana/addresses': 8.1.0(typescript@5.9.3) + '@solana/codecs-core': 8.1.0(typescript@5.9.3) + '@solana/errors': 8.1.0(typescript@5.9.3) + '@solana/instruction-plans': 8.1.0(typescript@5.9.3) + '@solana/instructions': 8.1.0(typescript@5.9.3) + '@solana/plugin-interfaces': 8.1.0(typescript@5.9.3) + '@solana/rpc-api': 8.1.0(typescript@5.9.3) + '@solana/signers': 8.1.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.1.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.1.0(typescript@5.9.3) + '@solana/errors': 8.1.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.1.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.1.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.1.0(typescript@5.9.3) + '@solana/codecs-core': 8.1.0(typescript@5.9.3) + '@solana/codecs-strings': 8.1.0(typescript@5.9.3) + '@solana/errors': 8.1.0(typescript@5.9.3) + '@solana/keys': 8.1.0(typescript@5.9.3) + '@solana/rpc-parsed-types': 8.1.0(typescript@5.9.3) + '@solana/rpc-spec': 8.1.0(typescript@5.9.3) + '@solana/rpc-transformers': 8.1.0(typescript@5.9.3) + '@solana/rpc-types': 8.1.0(typescript@5.9.3) + '@solana/transaction-messages': 8.1.0(typescript@5.9.3) + '@solana/transactions': 8.1.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.1.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.1.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.1.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.1.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.1.0(typescript@5.9.3) + '@solana/rpc-spec-types': 8.1.0(typescript@5.9.3) + '@solana/subscribable': 8.1.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.1.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.1.0(typescript@5.9.3) + '@solana/keys': 8.1.0(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 8.1.0(typescript@5.9.3) + '@solana/rpc-transformers': 8.1.0(typescript@5.9.3) + '@solana/rpc-types': 8.1.0(typescript@5.9.3) + '@solana/transaction-messages': 8.1.0(typescript@5.9.3) + '@solana/transactions': 8.1.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.1.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.1.0(typescript@5.9.3) + '@solana/functional': 8.1.0(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 8.1.0(typescript@5.9.3) + '@solana/subscribable': 8.1.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.1.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.1.0(typescript@5.9.3) + '@solana/promises': 8.1.0(typescript@5.9.3) + '@solana/rpc-spec-types': 8.1.0(typescript@5.9.3) + '@solana/subscribable': 8.1.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.1.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.1.0(typescript@5.9.3) + '@solana/fast-stable-stringify': 8.1.0(typescript@5.9.3) + '@solana/functional': 8.1.0(typescript@5.9.3) + '@solana/promises': 8.1.0(typescript@5.9.3) + '@solana/rpc-spec-types': 8.1.0(typescript@5.9.3) + '@solana/rpc-subscriptions-api': 8.1.0(typescript@5.9.3) + '@solana/rpc-subscriptions-channel-websocket': 8.1.0(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 8.1.0(typescript@5.9.3) + '@solana/rpc-transformers': 8.1.0(typescript@5.9.3) + '@solana/rpc-types': 8.1.0(typescript@5.9.3) + '@solana/subscribable': 8.1.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.1.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.1.0(typescript@5.9.3) + '@solana/functional': 8.1.0(typescript@5.9.3) + '@solana/nominal-types': 8.1.0(typescript@5.9.3) + '@solana/rpc-spec-types': 8.1.0(typescript@5.9.3) + '@solana/rpc-types': 8.1.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.1.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.1.0(typescript@5.9.3) + '@solana/rpc-spec': 8.1.0(typescript@5.9.3) + '@solana/rpc-spec-types': 8.1.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.1.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.1.0(typescript@5.9.3) + '@solana/codecs-core': 8.1.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.1.0(typescript@5.9.3) + '@solana/codecs-strings': 8.1.0(typescript@5.9.3) + '@solana/errors': 8.1.0(typescript@5.9.3) + '@solana/fixed-points': 8.1.0(typescript@5.9.3) + '@solana/nominal-types': 8.1.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.1.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.1.0(typescript@5.9.3) + '@solana/fast-stable-stringify': 8.1.0(typescript@5.9.3) + '@solana/functional': 8.1.0(typescript@5.9.3) + '@solana/rpc-api': 8.1.0(typescript@5.9.3) + '@solana/rpc-spec': 8.1.0(typescript@5.9.3) + '@solana/rpc-spec-types': 8.1.0(typescript@5.9.3) + '@solana/rpc-transformers': 8.1.0(typescript@5.9.3) + '@solana/rpc-transport-http': 8.1.0(typescript@5.9.3) + '@solana/rpc-types': 8.1.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.1.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.1.0(typescript@5.9.3) + '@solana/codecs-core': 8.1.0(typescript@5.9.3) + '@solana/errors': 8.1.0(typescript@5.9.3) + '@solana/instructions': 8.1.0(typescript@5.9.3) + '@solana/keys': 8.1.0(typescript@5.9.3) + '@solana/nominal-types': 8.1.0(typescript@5.9.3) + '@solana/offchain-messages': 8.1.0(typescript@5.9.3) + '@solana/transaction-messages': 8.1.0(typescript@5.9.3) + '@solana/transactions': 8.1.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.1.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 8.1.0(typescript@5.9.3) + '@solana/promises': 8.1.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.1.0(typescript@5.9.3)': + dependencies: + '@solana/accounts': 8.1.0(typescript@5.9.3) + '@solana/codecs-core': 8.1.0(typescript@5.9.3) + '@solana/codecs-data-structures': 8.1.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.1.0(typescript@5.9.3) + '@solana/errors': 8.1.0(typescript@5.9.3) + '@solana/rpc-types': 8.1.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.1.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.1.0(typescript@5.9.3) + '@solana/codecs-strings': 8.1.0(typescript@5.9.3) + '@solana/errors': 8.1.0(typescript@5.9.3) + '@solana/keys': 8.1.0(typescript@5.9.3) + '@solana/promises': 8.1.0(typescript@5.9.3) + '@solana/rpc': 8.1.0(typescript@5.9.3) + '@solana/rpc-subscriptions': 8.1.0(typescript@5.9.3) + '@solana/rpc-types': 8.1.0(typescript@5.9.3) + '@solana/transaction-messages': 8.1.0(typescript@5.9.3) + '@solana/transactions': 8.1.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.1.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.1.0(typescript@5.9.3) + '@solana/codecs-core': 8.1.0(typescript@5.9.3) + '@solana/codecs-strings': 8.1.0(typescript@5.9.3) + '@solana/errors': 8.1.0(typescript@5.9.3) + '@solana/instructions': 8.1.0(typescript@5.9.3) + '@solana/rpc-types': 8.1.0(typescript@5.9.3) + '@solana/transaction-messages': 8.1.0(typescript@5.9.3) + '@solana/transactions': 8.1.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.1.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.1.0(typescript@5.9.3) + '@solana/codecs-core': 8.1.0(typescript@5.9.3) + '@solana/codecs-data-structures': 8.1.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.1.0(typescript@5.9.3) + '@solana/errors': 8.1.0(typescript@5.9.3) + '@solana/functional': 8.1.0(typescript@5.9.3) + '@solana/instructions': 8.1.0(typescript@5.9.3) + '@solana/nominal-types': 8.1.0(typescript@5.9.3) + '@solana/rpc-types': 8.1.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.1.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 8.1.0(typescript@5.9.3) + '@solana/codecs-core': 8.1.0(typescript@5.9.3) + '@solana/codecs-data-structures': 8.1.0(typescript@5.9.3) + '@solana/codecs-numbers': 8.1.0(typescript@5.9.3) + '@solana/codecs-strings': 8.1.0(typescript@5.9.3) + '@solana/errors': 8.1.0(typescript@5.9.3) + '@solana/functional': 8.1.0(typescript@5.9.3) + '@solana/instructions': 8.1.0(typescript@5.9.3) + '@solana/keys': 8.1.0(typescript@5.9.3) + '@solana/nominal-types': 8.1.0(typescript@5.9.3) + '@solana/rpc-types': 8.1.0(typescript@5.9.3) + '@solana/transaction-messages': 8.1.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.1.0(typescript@5.9.3)) + '@solana-program/token': 0.16.0(@solana/kit@8.1.0(typescript@5.9.3)) + '@solana/kit': 8.1.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.12: + 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-fundraiser/pinocchio/program/Cargo.toml b/tokens/token-fundraiser/pinocchio/program/Cargo.toml new file mode 100644 index 000000000..c7d3e3134 --- /dev/null +++ b/tokens/token-fundraiser/pinocchio/program/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "fundraiser-pinocchio-program" +version = "0.1.0" +edition = "2021" + +[dependencies] +pinocchio.workspace = true +solana-address.workspace = true +pinocchio-log.workspace = true +pinocchio-system.workspace = true +pinocchio-token.workspace = true +pinocchio-associated-token-account.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-fundraiser/pinocchio/program/src/error.rs b/tokens/token-fundraiser/pinocchio/program/src/error.rs new file mode 100644 index 000000000..542c89212 --- /dev/null +++ b/tokens/token-fundraiser/pinocchio/program/src/error.rs @@ -0,0 +1,29 @@ +use pinocchio::error::ProgramError; + +/// Domain errors returned by the fundraiser program, surfaced to clients as +/// `ProgramError::Custom(code)`. +#[repr(u32)] +pub enum FundraiserError { + /// The target amount is below the minimum allowed. + InvalidAmount, + /// The contribution is below the minimum allowed. + ContributionTooSmall, + /// The contribution exceeds the per-contributor maximum. + ContributionTooBig, + /// The fundraiser's duration has already elapsed. + FundraiserEnded, + /// This contributor has reached the per-contributor maximum. + MaximumContributionsReached, + /// The target amount has not been reached yet. + TargetNotMet, + /// The target amount has already been reached. + TargetMet, + /// The fundraiser's duration has not elapsed yet. + FundraiserNotEnded, +} + +impl From for ProgramError { + fn from(error: FundraiserError) -> Self { + ProgramError::Custom(error as u32) + } +} diff --git a/tokens/token-fundraiser/pinocchio/program/src/instructions/check_contributions.rs b/tokens/token-fundraiser/pinocchio/program/src/instructions/check_contributions.rs new file mode 100644 index 000000000..d8a813d2c --- /dev/null +++ b/tokens/token-fundraiser/pinocchio/program/src/instructions/check_contributions.rs @@ -0,0 +1,112 @@ +use pinocchio::{ + cpi::{Seed, Signer}, + error::ProgramError, + AccountView, Address, ProgramResult, +}; +use pinocchio_associated_token_account::instructions::CreateIdempotent; +use pinocchio_log::log; +use pinocchio_token::{ + instructions::{CloseAccount, Transfer}, + state::Account as TokenAccount, +}; + +use crate::{error::FundraiserError, state::Fundraiser}; + +/// Releases the raised funds to the maker once the target is met, then closes +/// the vault and fundraiser accounts. Only the maker may call this. +/// +/// Accounts: +/// 0. `[signer, writable]` maker (receives the funds and reclaimed rent) +/// 1. `[]` mint to raise +/// 2. `[writable]` fundraiser account (PDA `[b"fundraiser", maker]`, closed here) +/// 3. `[writable]` vault (fundraiser PDA's token account, drained and closed) +/// 4. `[writable]` maker's token account (destination, created if needed) +/// 5. `[]` token program +/// 6. `[]` associated token program +/// 7. `[]` system program +/// +/// Instruction data: none. +pub fn check_contributions(program_id: &Address, accounts: &mut [AccountView], _data: &[u8]) -> ProgramResult { + let [maker, mint_to_raise, fundraiser, vault, maker_ata, token_program, _associated_token_program, system_program] = + accounts + else { + return Err(ProgramError::NotEnoughAccountKeys); + }; + + if !maker.is_signer() { + return Err(ProgramError::MissingRequiredSignature); + } + + let state = Fundraiser::deserialize(&fundraiser.try_borrow()?)?; + + // Only the maker who created this fundraiser may release the funds. + if &state.maker != maker.address().as_array() || &state.mint_to_raise != mint_to_raise.address().as_array() { + return Err(ProgramError::InvalidAccountData); + } + let bump_bytes = [state.bump]; + let fundraiser_pda = + Address::create_program_address(&[Fundraiser::SEED_PREFIX, maker.address().as_ref(), &bump_bytes], program_id) + .map_err(|_| ProgramError::InvalidSeeds)?; + if fundraiser.address() != &fundraiser_pda { + return Err(ProgramError::InvalidSeeds); + } + let (expected_vault, _) = Address::find_program_address( + &[fundraiser.address().as_ref(), pinocchio_token::ID.as_ref(), mint_to_raise.address().as_ref()], + &pinocchio_associated_token_account::ID, + ); + if vault.address() != &expected_vault { + return Err(ProgramError::InvalidAccountData); + } + + // The target must have been reached by recorded contributions. The vault + // balance itself is not the gate: anyone can transfer into a standard ATA, + // and such unrecorded deposits must not release the fundraiser. + let vault_amount = TokenAccount::from_account_view(vault)?.amount(); + if state.current_amount < state.amount_to_raise { + return Err(FundraiserError::TargetNotMet.into()); + } + + // Ensure the maker has a token account to receive into. + log!("Ensuring maker token account exists"); + CreateIdempotent { + funding_account: maker, + account: maker_ata, + wallet: maker, + mint: mint_to_raise, + system_program, + token_program, + } + .invoke()?; + + // Release the funds and tear down the vault, both signed by the fundraiser PDA. + let seeds = [Seed::from(Fundraiser::SEED_PREFIX), Seed::from(maker.address().as_ref()), Seed::from(&bump_bytes)]; + let signers = [Signer::from(&seeds)]; + + log!("Releasing funds to maker"); + Transfer { + from: vault, + to: maker_ata, + authority: fundraiser, + multisig_signers: &[] as &[&AccountView], + amount: vault_amount, + } + .invoke_signed(&signers)?; + + log!("Closing vault"); + CloseAccount { + account: vault, + destination: maker, + authority: fundraiser, + multisig_signers: &[] as &[&AccountView], + } + .invoke_signed(&signers)?; + + // Close the fundraiser account, returning its rent to the maker. + log!("Closing fundraiser account"); + let new_maker_lamports = maker.lamports() + fundraiser.lamports(); + maker.set_lamports(new_maker_lamports); + fundraiser.close()?; + + log!("Funds released"); + Ok(()) +} diff --git a/tokens/token-fundraiser/pinocchio/program/src/instructions/contribute.rs b/tokens/token-fundraiser/pinocchio/program/src/instructions/contribute.rs new file mode 100644 index 000000000..ddfaa89e2 --- /dev/null +++ b/tokens/token-fundraiser/pinocchio/program/src/instructions/contribute.rs @@ -0,0 +1,140 @@ +use pinocchio::{ + cpi::{Seed, Signer}, + error::ProgramError, + sysvars::{rent::Rent, Sysvar}, + AccountView, Address, ProgramResult, +}; +use pinocchio_log::log; +use pinocchio_system::instructions::CreateAccount; +use pinocchio_token::instructions::Transfer; + +use crate::{ + error::FundraiserError, + instructions::{days_elapsed, max_contribution, read_u64}, + state::{Contributor, Fundraiser}, +}; + +/// Contributes `amount` of the raised token into the fundraiser's vault, up to a +/// per-contributor cap, while the fundraiser is still running. +/// +/// Accounts: +/// 0. `[signer, writable]` contributor (funds the contributor account; source authority) +/// 1. `[]` mint to raise +/// 2. `[writable]` fundraiser account (PDA `[b"fundraiser", maker]`) +/// 3. `[writable]` contributor account (PDA `[b"contributor", fundraiser, contributor]`, created if needed) +/// 4. `[writable]` contributor's token account (source) +/// 5. `[writable]` vault (fundraiser PDA's token account) +/// 6. `[]` token program +/// 7. `[]` system program +/// +/// Instruction data: `[amount: u64 (LE)]` +pub fn contribute(program_id: &Address, accounts: &mut [AccountView], data: &[u8]) -> ProgramResult { + let [contributor, mint_to_raise, fundraiser, contributor_account, contributor_ata, vault, _token_program, _system_program] = + accounts + else { + return Err(ProgramError::NotEnoughAccountKeys); + }; + + if !contributor.is_signer() { + return Err(ProgramError::MissingRequiredSignature); + } + + let amount = read_u64(data, 0)?; + + let mut state = Fundraiser::deserialize(&fundraiser.try_borrow()?)?; + + // Confirm the fundraiser PDA and that the vault is its associated token account. + let fundraiser_bump = [state.bump]; + let fundraiser_pda = + Address::create_program_address(&[Fundraiser::SEED_PREFIX, state.maker.as_ref(), &fundraiser_bump], program_id) + .map_err(|_| ProgramError::InvalidSeeds)?; + if fundraiser.address() != &fundraiser_pda || &state.mint_to_raise != mint_to_raise.address().as_array() { + return Err(ProgramError::InvalidAccountData); + } + let (expected_vault, _) = Address::find_program_address( + &[fundraiser.address().as_ref(), pinocchio_token::ID.as_ref(), mint_to_raise.address().as_ref()], + &pinocchio_associated_token_account::ID, + ); + if vault.address() != &expected_vault { + return Err(ProgramError::InvalidAccountData); + } + + // Contribution bounds: at least one base unit, at most the per-contributor cap. + if amount == 0 { + return Err(FundraiserError::ContributionTooSmall.into()); + } + let cap = max_contribution(state.amount_to_raise); + if amount > cap { + return Err(FundraiserError::ContributionTooBig.into()); + } + + // The fundraiser must still be running. + if days_elapsed(state.time_started)? >= state.duration as i64 { + return Err(FundraiserError::FundraiserEnded.into()); + } + + // Bind the contributor record to this signer before trusting it, whether it + // already exists or is about to be created. + // + // The bump is derived here rather than taken from the caller: several bumps + // can yield a valid address for the same seeds, so accepting one would let a + // contributor open a second, non-canonical record and be metered against the + // cap separately on each. `refund` only ever derives the canonical address, + // so those extra records would also be unrefundable. + let (contributor_pda, contributor_bump) = Address::find_program_address( + &[Contributor::SEED_PREFIX, fundraiser.address().as_ref(), contributor.address().as_ref()], + program_id, + ); + let bump_bytes = [contributor_bump]; + let seeds = [ + Seed::from(Contributor::SEED_PREFIX), + Seed::from(fundraiser.address().as_ref()), + Seed::from(contributor.address().as_ref()), + Seed::from(&bump_bytes), + ]; + if contributor_account.address() != &contributor_pda { + return Err(ProgramError::InvalidSeeds); + } + + // Create the per-contributor record on first contribution; otherwise load it. + let already_contributed = if contributor_account.owner() == program_id { + Contributor::deserialize(&contributor_account.try_borrow()?)?.amount + } else { + log!("Creating contributor account"); + let lamports = Rent::get()?.try_minimum_balance(Contributor::LEN)?; + CreateAccount { + from: contributor, + to: contributor_account, + lamports, + space: Contributor::LEN as u64, + owner: program_id, + } + .invoke_signed(&[Signer::from(&seeds)])?; + 0 + }; + + // Enforce the per-contributor cap across this contributor's total. + let new_total = already_contributed.checked_add(amount).ok_or(FundraiserError::ContributionTooBig)?; + if new_total > cap { + return Err(FundraiserError::MaximumContributionsReached.into()); + } + + // Move the tokens into the vault, then record the contribution. + log!("Transferring contribution to vault"); + Transfer { + from: contributor_ata, + to: vault, + authority: contributor, + multisig_signers: &[] as &[&AccountView], + amount, + } + .invoke()?; + + state.current_amount = state.current_amount.checked_add(amount).ok_or(ProgramError::ArithmeticOverflow)?; + state.serialize(&mut fundraiser.try_borrow_mut()?)?; + + Contributor { amount: new_total }.serialize(&mut contributor_account.try_borrow_mut()?)?; + + log!("Contribution recorded"); + Ok(()) +} diff --git a/tokens/token-fundraiser/pinocchio/program/src/instructions/initialize.rs b/tokens/token-fundraiser/pinocchio/program/src/instructions/initialize.rs new file mode 100644 index 000000000..99e0658c1 --- /dev/null +++ b/tokens/token-fundraiser/pinocchio/program/src/instructions/initialize.rs @@ -0,0 +1,94 @@ +use pinocchio::{ + cpi::{Seed, Signer}, + error::ProgramError, + sysvars::{clock::Clock, rent::Rent, Sysvar}, + AccountView, Address, ProgramResult, +}; +use pinocchio_associated_token_account::instructions::CreateIdempotent; +use pinocchio_log::log; +use pinocchio_system::instructions::CreateAccount; + +use crate::{ + error::FundraiserError, + instructions::{mint_decimals, read_u16, read_u64, MIN_AMOUNT_TO_RAISE}, + state::Fundraiser, +}; + +/// Starts a fundraiser: creates the fundraiser PDA state account and its vault +/// token account, which will hold contributed tokens until the target is met. +/// +/// Accounts: +/// 0. `[writable]` fundraiser account (PDA `[b"fundraiser", maker]`, created here) +/// 1. `[]` mint to raise +/// 2. `[writable]` vault (fundraiser PDA's associated token account, created here) +/// 3. `[signer, writable]` maker (funds the accounts; receives the funds) +/// 4. `[]` token program +/// 5. `[]` associated token program +/// 6. `[]` system program +/// +/// Instruction data: `[amount: u64 (LE), duration: u16 (LE), bump: u8]` +pub fn initialize(program_id: &Address, accounts: &mut [AccountView], data: &[u8]) -> ProgramResult { + let [fundraiser, mint_to_raise, vault, maker, token_program, _associated_token_program, system_program] = accounts + else { + return Err(ProgramError::NotEnoughAccountKeys); + }; + + if !maker.is_signer() { + return Err(ProgramError::MissingRequiredSignature); + } + + let amount = read_u64(data, 0)?; + let duration = read_u16(data, 8)?; + let bump = *data.get(10).ok_or(ProgramError::InvalidInstructionData)?; + + // The target must clear the minimum, scaled by the mint's decimals. + let decimals = mint_decimals(mint_to_raise)?; + let minimum = MIN_AMOUNT_TO_RAISE.checked_pow(decimals as u32).ok_or(FundraiserError::InvalidAmount)?; + if amount < minimum { + return Err(FundraiserError::InvalidAmount.into()); + } + + // Confirm the supplied account is the canonical fundraiser PDA. + let bump_bytes = [bump]; + let seeds = [Seed::from(Fundraiser::SEED_PREFIX), Seed::from(maker.address().as_ref()), Seed::from(&bump_bytes)]; + let fundraiser_pda = + Address::create_program_address(&[Fundraiser::SEED_PREFIX, maker.address().as_ref(), &bump_bytes], program_id) + .map_err(|_| ProgramError::InvalidSeeds)?; + if fundraiser.address() != &fundraiser_pda { + return Err(ProgramError::InvalidSeeds); + } + + // Create the fundraiser state account, signed by the PDA itself. + log!("Creating fundraiser account"); + let lamports = Rent::get()?.try_minimum_balance(Fundraiser::LEN)?; + let signers = [Signer::from(&seeds)]; + CreateAccount { from: maker, to: fundraiser, lamports, space: Fundraiser::LEN as u64, owner: program_id } + .invoke_signed(&signers)?; + + // Create the vault: the fundraiser PDA's associated token account. + log!("Creating vault"); + CreateIdempotent { + funding_account: maker, + account: vault, + wallet: fundraiser, + mint: mint_to_raise, + system_program, + token_program, + } + .invoke()?; + + // Persist the fundraiser state. + let state = Fundraiser { + maker: *maker.address().as_array(), + mint_to_raise: *mint_to_raise.address().as_array(), + amount_to_raise: amount, + current_amount: 0, + time_started: Clock::get()?.unix_timestamp, + duration, + bump, + }; + state.serialize(&mut fundraiser.try_borrow_mut()?)?; + + log!("Fundraiser created"); + Ok(()) +} diff --git a/tokens/token-fundraiser/pinocchio/program/src/instructions/mod.rs b/tokens/token-fundraiser/pinocchio/program/src/instructions/mod.rs new file mode 100644 index 000000000..07cae1c04 --- /dev/null +++ b/tokens/token-fundraiser/pinocchio/program/src/instructions/mod.rs @@ -0,0 +1,57 @@ +use pinocchio::error::ProgramError; + +mod check_contributions; +mod contribute; +mod initialize; +mod refund; + +pub use check_contributions::*; +pub use contribute::*; +pub use initialize::*; +pub use refund::*; + +/// Minimum target (before scaling by the mint's decimals) a fundraiser may set. +pub const MIN_AMOUNT_TO_RAISE: u64 = 3; +/// Seconds in a day; the fundraiser duration is expressed in days. +pub const SECONDS_TO_DAYS: i64 = 86_400; +/// A single contributor may contribute at most this percentage of the target. +pub const MAX_CONTRIBUTION_PERCENTAGE: u64 = 10; +/// Denominator for the percentage above. +pub const PERCENTAGE_SCALER: u64 = 100; +/// The mint's `decimals` field sits at byte offset 44 of the base mint layout. +pub const MINT_DECIMALS_OFFSET: usize = 44; + +/// Reads a little-endian `u64` starting at `offset` within `data`. +pub(crate) fn read_u64(data: &[u8], offset: usize) -> Result { + data.get(offset..offset + 8) + .and_then(|slice| slice.try_into().ok()) + .map(u64::from_le_bytes) + .ok_or(ProgramError::InvalidInstructionData) +} + +/// Reads a little-endian `u16` starting at `offset` within `data`. +pub(crate) fn read_u16(data: &[u8], offset: usize) -> Result { + data.get(offset..offset + 2) + .and_then(|slice| slice.try_into().ok()) + .map(u16::from_le_bytes) + .ok_or(ProgramError::InvalidInstructionData) +} + +/// Reads the `decimals` field from a base SPL mint account. +pub(crate) fn mint_decimals(mint: &pinocchio::AccountView) -> Result { + let data = mint.try_borrow()?; + data.get(MINT_DECIMALS_OFFSET).copied().ok_or(ProgramError::InvalidAccountData) +} + +/// The maximum a single contributor may contribute: `MAX_CONTRIBUTION_PERCENTAGE` +/// percent of the target. +pub(crate) fn max_contribution(amount_to_raise: u64) -> u64 { + amount_to_raise.saturating_mul(MAX_CONTRIBUTION_PERCENTAGE) / PERCENTAGE_SCALER +} + +/// Number of whole days elapsed since `time_started`, using the Clock sysvar. +pub(crate) fn days_elapsed(time_started: i64) -> Result { + use pinocchio::sysvars::{clock::Clock, Sysvar}; + let now = Clock::get()?.unix_timestamp; + Ok((now - time_started) / SECONDS_TO_DAYS) +} diff --git a/tokens/token-fundraiser/pinocchio/program/src/instructions/refund.rs b/tokens/token-fundraiser/pinocchio/program/src/instructions/refund.rs new file mode 100644 index 000000000..6adfac8bf --- /dev/null +++ b/tokens/token-fundraiser/pinocchio/program/src/instructions/refund.rs @@ -0,0 +1,104 @@ +use pinocchio::{ + cpi::{Seed, Signer}, + error::ProgramError, + AccountView, Address, ProgramResult, +}; +use pinocchio_log::log; +use pinocchio_token::instructions::Transfer; + +use crate::{ + error::FundraiserError, + instructions::days_elapsed, + state::{Contributor, Fundraiser}, +}; + +/// Refunds a contributor once the fundraiser has ended without meeting its +/// target, returning their contribution and closing their contributor account. +/// +/// Accounts: +/// 0. `[signer, writable]` contributor (receives the refund and reclaimed rent) +/// 1. `[]` maker (part of the fundraiser PDA seeds) +/// 2. `[]` mint to raise +/// 3. `[writable]` fundraiser account (PDA `[b"fundraiser", maker]`) +/// 4. `[writable]` contributor account (PDA, closed here) +/// 5. `[writable]` contributor's token account (destination) +/// 6. `[writable]` vault (fundraiser PDA's token account) +/// 7. `[]` token program +/// +/// Instruction data: none. +pub fn refund(program_id: &Address, accounts: &mut [AccountView], _data: &[u8]) -> ProgramResult { + let [contributor, maker, mint_to_raise, fundraiser, contributor_account, contributor_ata, vault, _token_program] = + accounts + else { + return Err(ProgramError::NotEnoughAccountKeys); + }; + + if !contributor.is_signer() { + return Err(ProgramError::MissingRequiredSignature); + } + + let mut state = Fundraiser::deserialize(&fundraiser.try_borrow()?)?; + + // The fundraiser PDA is derived from the maker; confirm both, and the vault. + if &state.maker != maker.address().as_array() || &state.mint_to_raise != mint_to_raise.address().as_array() { + return Err(ProgramError::InvalidAccountData); + } + let bump_bytes = [state.bump]; + let fundraiser_pda = + Address::create_program_address(&[Fundraiser::SEED_PREFIX, maker.address().as_ref(), &bump_bytes], program_id) + .map_err(|_| ProgramError::InvalidSeeds)?; + if fundraiser.address() != &fundraiser_pda { + return Err(ProgramError::InvalidSeeds); + } + let (expected_vault, _) = Address::find_program_address( + &[fundraiser.address().as_ref(), pinocchio_token::ID.as_ref(), mint_to_raise.address().as_ref()], + &pinocchio_associated_token_account::ID, + ); + if vault.address() != &expected_vault { + return Err(ProgramError::InvalidAccountData); + } + + // Refunds are only allowed once the fundraiser has ended without meeting its target. + if days_elapsed(state.time_started)? < state.duration as i64 { + return Err(FundraiserError::FundraiserNotEnded.into()); + } + // Eligibility reads the recorded total, not the vault balance, so an + // unrecorded direct transfer into the vault cannot block legitimate refunds. + if state.current_amount >= state.amount_to_raise { + return Err(FundraiserError::TargetMet.into()); + } + + // Confirm the contributor account is the canonical PDA before trusting it. + let contributor_state = Contributor::deserialize(&contributor_account.try_borrow()?)?; + let (contributor_pda, _) = Address::find_program_address( + &[Contributor::SEED_PREFIX, fundraiser.address().as_ref(), contributor.address().as_ref()], + program_id, + ); + if contributor_account.address() != &contributor_pda { + return Err(ProgramError::InvalidSeeds); + } + + // Return the contribution, signed by the fundraiser PDA. + let seeds = [Seed::from(Fundraiser::SEED_PREFIX), Seed::from(maker.address().as_ref()), Seed::from(&bump_bytes)]; + log!("Refunding contributor"); + Transfer { + from: vault, + to: contributor_ata, + authority: fundraiser, + multisig_signers: &[] as &[&AccountView], + amount: contributor_state.amount, + } + .invoke_signed(&[Signer::from(&seeds)])?; + + // Reduce the recorded total and close the contributor account. + state.current_amount = state.current_amount.saturating_sub(contributor_state.amount); + state.serialize(&mut fundraiser.try_borrow_mut()?)?; + + log!("Closing contributor account"); + let new_contributor_lamports = contributor.lamports() + contributor_account.lamports(); + contributor.set_lamports(new_contributor_lamports); + contributor_account.close()?; + + log!("Refund complete"); + Ok(()) +} diff --git a/tokens/token-fundraiser/pinocchio/program/src/lib.rs b/tokens/token-fundraiser/pinocchio/program/src/lib.rs new file mode 100644 index 000000000..1e5b927ea --- /dev/null +++ b/tokens/token-fundraiser/pinocchio/program/src/lib.rs @@ -0,0 +1,11 @@ +#![no_std] + +pub mod error; +pub mod instructions; +pub mod processor; +pub mod state; + +use pinocchio::{entrypoint, nostd_panic_handler}; + +entrypoint!(processor::process_instruction); +nostd_panic_handler!(); diff --git a/tokens/token-fundraiser/pinocchio/program/src/processor.rs b/tokens/token-fundraiser/pinocchio/program/src/processor.rs new file mode 100644 index 000000000..dfa21a63f --- /dev/null +++ b/tokens/token-fundraiser/pinocchio/program/src/processor.rs @@ -0,0 +1,39 @@ +use pinocchio::{error::ProgramError, AccountView, Address, ProgramResult}; +use pinocchio_log::log; + +use crate::instructions::{check_contributions, contribute, initialize, refund}; + +/// Dispatches an instruction based on its leading discriminator byte. +/// +/// Instruction data layout: `[discriminator: u8, ..args]` +/// - `0` -> Initialize (args: `[amount: u64 (LE), duration: u16 (LE), bump: u8]`) +/// - `1` -> Contribute (args: `[amount: u64 (LE), contributor_bump: u8]`) +/// - `2` -> CheckContributions (no args) +/// - `3` -> Refund (no args) +pub fn process_instruction( + program_id: &Address, + accounts: &mut [AccountView], + instruction_data: &[u8], +) -> ProgramResult { + let (discriminator, args) = instruction_data.split_first().ok_or(ProgramError::InvalidInstructionData)?; + + match *discriminator { + 0 => { + log!("Instruction: Initialize"); + initialize(program_id, accounts, args) + } + 1 => { + log!("Instruction: Contribute"); + contribute(program_id, accounts, args) + } + 2 => { + log!("Instruction: CheckContributions"); + check_contributions(program_id, accounts, args) + } + 3 => { + log!("Instruction: Refund"); + refund(program_id, accounts, args) + } + _ => Err(ProgramError::InvalidInstructionData), + } +} diff --git a/tokens/token-fundraiser/pinocchio/program/src/state.rs b/tokens/token-fundraiser/pinocchio/program/src/state.rs new file mode 100644 index 000000000..0872d5e45 --- /dev/null +++ b/tokens/token-fundraiser/pinocchio/program/src/state.rs @@ -0,0 +1,88 @@ +use pinocchio::error::ProgramError; + +/// Persistent state of a fundraiser, stored in the fundraiser PDA. +/// +/// The fundraiser PDA is derived from `[b"fundraiser", maker]` and is the +/// authority of the vault token account that holds contributed tokens. +/// +/// Serialized byte layout (little-endian), matching the field order below: +/// `[maker: 32][mint_to_raise: 32][amount_to_raise: u64][current_amount: u64] +/// [time_started: i64][duration: u16][bump: u8]` +pub struct Fundraiser { + /// The wallet that created the fundraiser and receives the funds. + pub maker: [u8; 32], + /// Mint of the token being raised. + pub mint_to_raise: [u8; 32], + /// Target amount to raise before the funds can be released. + pub amount_to_raise: u64, + /// Amount contributed so far. + pub current_amount: u64, + /// Unix timestamp when the fundraiser started. + pub time_started: i64, + /// Fundraiser duration, in days. + pub duration: u16, + /// Canonical bump for the fundraiser PDA. + pub bump: u8, +} + +impl Fundraiser { + /// Seed prefix for the fundraiser PDA: `[SEED_PREFIX, maker]`. + pub const SEED_PREFIX: &'static [u8] = b"fundraiser"; + + /// Serialized size in bytes. + pub const LEN: usize = 32 + 32 + 8 + 8 + 8 + 2 + 1; + + pub fn serialize(&self, dst: &mut [u8]) -> Result<(), ProgramError> { + let dst = dst.get_mut(..Self::LEN).ok_or(ProgramError::AccountDataTooSmall)?; + dst[0..32].copy_from_slice(&self.maker); + dst[32..64].copy_from_slice(&self.mint_to_raise); + dst[64..72].copy_from_slice(&self.amount_to_raise.to_le_bytes()); + dst[72..80].copy_from_slice(&self.current_amount.to_le_bytes()); + dst[80..88].copy_from_slice(&self.time_started.to_le_bytes()); + dst[88..90].copy_from_slice(&self.duration.to_le_bytes()); + dst[90] = self.bump; + Ok(()) + } + + pub fn deserialize(src: &[u8]) -> Result { + let src: &[u8; Self::LEN] = + src.get(..Self::LEN).and_then(|s| s.try_into().ok()).ok_or(ProgramError::InvalidAccountData)?; + Ok(Self { + maker: src[0..32].try_into().unwrap(), + mint_to_raise: src[32..64].try_into().unwrap(), + amount_to_raise: u64::from_le_bytes(src[64..72].try_into().unwrap()), + current_amount: u64::from_le_bytes(src[72..80].try_into().unwrap()), + time_started: i64::from_le_bytes(src[80..88].try_into().unwrap()), + duration: u16::from_le_bytes(src[88..90].try_into().unwrap()), + bump: src[90], + }) + } +} + +/// Per-contributor record of how much a wallet has contributed, stored in the +/// contributor PDA derived from `[b"contributor", fundraiser, contributor]`. +/// +/// Serialized byte layout: `[amount: u64]` (little-endian). +pub struct Contributor { + pub amount: u64, +} + +impl Contributor { + /// Seed prefix for the contributor PDA: `[SEED_PREFIX, fundraiser, contributor]`. + pub const SEED_PREFIX: &'static [u8] = b"contributor"; + + /// Serialized size in bytes. + pub const LEN: usize = 8; + + pub fn serialize(&self, dst: &mut [u8]) -> Result<(), ProgramError> { + let dst = dst.get_mut(..Self::LEN).ok_or(ProgramError::AccountDataTooSmall)?; + dst[0..8].copy_from_slice(&self.amount.to_le_bytes()); + Ok(()) + } + + pub fn deserialize(src: &[u8]) -> Result { + let src: &[u8; Self::LEN] = + src.get(..Self::LEN).and_then(|s| s.try_into().ok()).ok_or(ProgramError::InvalidAccountData)?; + Ok(Self { amount: u64::from_le_bytes(*src) }) + } +} diff --git a/tokens/token-fundraiser/pinocchio/tests/test.ts b/tokens/token-fundraiser/pinocchio/tests/test.ts new file mode 100644 index 000000000..c114b9067 --- /dev/null +++ b/tokens/token-fundraiser/pinocchio/tests/test.ts @@ -0,0 +1,478 @@ +import * as path from 'node:path'; +import { + AccountRole, + type Address, + type KeyPairSigner, + appendTransactionMessageInstruction, + appendTransactionMessageInstructions, + createTransactionMessage, + generateKeyPairSigner, + getAddressEncoder, + getProgramDerivedAddress, + lamports, + pipe, + setTransactionMessageFeePayerSigner, + signTransactionMessageWithSigners, +} from '@solana/kit'; +import { getCreateAccountInstruction, SYSTEM_PROGRAM_ADDRESS } from '@solana-program/system'; +import { + ASSOCIATED_TOKEN_PROGRAM_ADDRESS, + findAssociatedTokenPda, + getCreateAssociatedTokenInstruction, + getInitializeMint2Instruction, + getMintToInstruction, + getTokenDecoder, + getTransferInstruction, + TOKEN_PROGRAM_ADDRESS, +} from '@solana-program/token'; +import { assert } from 'chai'; +import { FailedTransactionMetadata, LiteSVM } from 'litesvm'; + +const MINT_SIZE = 82n; +const SECONDS_PER_DAY = 86_400n; + +const PROGRAM_SO = path.join(process.cwd(), 'tests', 'fixtures', 'fundraiser_pinocchio_program.so'); +const addressEncoder = getAddressEncoder(); + +// Little-endian encoders for the raw instruction data the program expects. +function u64(n: bigint): Uint8Array { + const b = new Uint8Array(8); + new DataView(b.buffer).setBigUint64(0, n, true); + return b; +} +function u16(n: number): Uint8Array { + const b = new Uint8Array(2); + new DataView(b.buffer).setUint16(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 Fundraiser (Pinocchio)', () => { + let svm: LiteSVM; + let programId: Address; + + before(async () => { + svm = new LiteSVM(); + programId = (await generateKeyPairSigner()).address; + svm.addProgramFromFile(programId, PROGRAM_SO); + }); + + function send(signedTx: Parameters[0], label: string) { + const result = svm.sendTransaction(signedTx); + if (result instanceof FailedTransactionMetadata) { + throw new Error(`${label} failed: ${result.err()}`); + } + } + + // Asserts a transaction is rejected on-chain rather than succeeding. + function sendExpectingFailure(signedTx: Parameters[0], label: string) { + const result = svm.sendTransaction(signedTx); + assert.instanceOf(result, FailedTransactionMetadata, `${label} should have been rejected`); + } + + async function tx(payer: KeyPairSigner, instructions: Parameters[0][]) { + return signTransactionMessageWithSigners( + pipe( + createTransactionMessage({ version: 0 }), + m => setTransactionMessageFeePayerSigner(payer, m), + m => svm.setTransactionMessageLifetimeUsingLatestBlockhash(m), + m => appendTransactionMessageInstructions(instructions, m), + ), + ); + } + + // Creates a plain SPL mint with the given decimals and authority. + async function createMint(payer: KeyPairSigner, decimals: number, mintAuthority: Address): Promise { + const mint = await generateKeyPairSigner(); + send( + await tx(payer, [ + getCreateAccountInstruction({ + payer, + newAccount: mint, + lamports: svm.minimumBalanceForRentExemption(MINT_SIZE), + space: MINT_SIZE, + programAddress: TOKEN_PROGRAM_ADDRESS, + }), + getInitializeMint2Instruction({ mint: mint.address, decimals, mintAuthority, freezeAuthority: null }), + ]), + 'create mint', + ); + return mint; + } + + // Creates `owner`'s associated token account and mints `amount` into it. + async function fundAta( + payer: KeyPairSigner, + mintAuthority: KeyPairSigner, + owner: Address, + mint: Address, + amount: bigint, + ): Promise
{ + const [ata] = await findAssociatedTokenPda({ owner, mint, tokenProgram: TOKEN_PROGRAM_ADDRESS }); + send( + await tx(payer, [ + getCreateAssociatedTokenInstruction({ payer, ata, owner, mint }), + getMintToInstruction({ mint, token: ata, mintAuthority, amount }), + ]), + 'fund ata', + ); + return ata; + } + + function fundraiserPda(maker: Address) { + return getProgramDerivedAddress({ + programAddress: programId, + seeds: ['fundraiser', addressEncoder.encode(maker)], + }); + } + function contributorPda(fundraiser: Address, contributor: Address) { + return getProgramDerivedAddress({ + programAddress: programId, + seeds: ['contributor', addressEncoder.encode(fundraiser), addressEncoder.encode(contributor)], + }); + } + 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; + } + + function initializeIx( + maker: KeyPairSigner, + mint: Address, + fundraiser: Address, + vault: Address, + bump: number, + amount: bigint, + duration: number, + ) { + return { + programAddress: programId, + accounts: [ + { address: fundraiser, role: AccountRole.WRITABLE }, + { address: mint, role: AccountRole.READONLY }, + { address: vault, role: AccountRole.WRITABLE }, + { address: maker.address, role: AccountRole.WRITABLE_SIGNER, signer: maker }, + { address: TOKEN_PROGRAM_ADDRESS, role: AccountRole.READONLY }, + { address: ASSOCIATED_TOKEN_PROGRAM_ADDRESS, role: AccountRole.READONLY }, + { address: SYSTEM_PROGRAM_ADDRESS, role: AccountRole.READONLY }, + ], + data: concatBytes(Uint8Array.of(0), u64(amount), u16(duration), Uint8Array.of(bump)), + }; + } + + function contributeIx( + contributor: KeyPairSigner, + mint: Address, + fundraiser: Address, + contributorAccount: Address, + contributorAta: Address, + vault: Address, + amount: bigint, + ) { + return { + programAddress: programId, + accounts: [ + { address: contributor.address, role: AccountRole.WRITABLE_SIGNER, signer: contributor }, + { address: mint, role: AccountRole.READONLY }, + { address: fundraiser, role: AccountRole.WRITABLE }, + { address: contributorAccount, role: AccountRole.WRITABLE }, + { address: contributorAta, role: AccountRole.WRITABLE }, + { address: vault, role: AccountRole.WRITABLE }, + { address: TOKEN_PROGRAM_ADDRESS, role: AccountRole.READONLY }, + { address: SYSTEM_PROGRAM_ADDRESS, role: AccountRole.READONLY }, + ], + // The contributor PDA bump is derived on-chain, not supplied here. + data: concatBytes(Uint8Array.of(1), u64(amount)), + }; + } + + function refundIx( + contributor: KeyPairSigner, + maker: Address, + mint: Address, + fundraiser: Address, + contributorAccount: Address, + contributorAta: Address, + vault: Address, + ) { + return { + programAddress: programId, + accounts: [ + { address: contributor.address, role: AccountRole.WRITABLE_SIGNER, signer: contributor }, + { address: maker, role: AccountRole.READONLY }, + { address: mint, role: AccountRole.READONLY }, + { address: fundraiser, role: AccountRole.WRITABLE }, + { address: contributorAccount, role: AccountRole.WRITABLE }, + { address: contributorAta, role: AccountRole.WRITABLE }, + { address: vault, role: AccountRole.WRITABLE }, + { address: TOKEN_PROGRAM_ADDRESS, role: AccountRole.READONLY }, + ], + data: Uint8Array.of(3), + }; + } + + function checkIx(maker: KeyPairSigner, mint: Address, fundraiser: Address, vault: Address, makerAta: Address) { + return { + programAddress: programId, + accounts: [ + { address: maker.address, role: AccountRole.WRITABLE_SIGNER, signer: maker }, + { address: mint, role: AccountRole.READONLY }, + { address: fundraiser, role: AccountRole.WRITABLE }, + { address: vault, role: AccountRole.WRITABLE }, + { address: makerAta, role: AccountRole.WRITABLE }, + { address: TOKEN_PROGRAM_ADDRESS, role: AccountRole.READONLY }, + { address: ASSOCIATED_TOKEN_PROGRAM_ADDRESS, role: AccountRole.READONLY }, + { address: SYSTEM_PROGRAM_ADDRESS, role: AccountRole.READONLY }, + ], + data: Uint8Array.of(2), + }; + } + + function warpDays(days: number) { + const clock = svm.getClock(); + clock.unixTimestamp += BigInt(days) * SECONDS_PER_DAY; + svm.setClock(clock); + } + + it('Refunds a contributor after the fundraiser ends without meeting its target', async () => { + const maker = await generateKeyPairSigner(); + svm.airdrop(maker.address, lamports(1_000_000_000n)); + const mint = await createMint(maker, 0, maker.address); + + const [fundraiser, bump] = await fundraiserPda(maker.address); + const [vault] = await findAssociatedTokenPda({ + owner: fundraiser, + mint: mint.address, + tokenProgram: TOKEN_PROGRAM_ADDRESS, + }); + + // Goal of 100 over 1 day; a single contributor gives the 10% max (10). + send(await tx(maker, [initializeIx(maker, mint.address, fundraiser, vault, bump, 100n, 1)]), 'initialize'); + + const contributor = await generateKeyPairSigner(); + svm.airdrop(contributor.address, lamports(1_000_000_000n)); + const contributorAta = await fundAta(maker, maker, contributor.address, mint.address, 10n); + const [contributorAccount] = await contributorPda(fundraiser, contributor.address); + + send( + await tx(contributor, [ + contributeIx(contributor, mint.address, fundraiser, contributorAccount, contributorAta, vault, 10n), + ]), + 'contribute', + ); + + assert.equal(tokenAmount(vault), 10n, 'vault holds the contribution'); + assert.equal(tokenAmount(contributorAta), 0n, 'contributor spent their tokens'); + + // The fundraiser ends without meeting the 100 target; the contributor refunds. + warpDays(2); + send( + await tx(contributor, [ + refundIx( + contributor, + maker.address, + mint.address, + fundraiser, + contributorAccount, + contributorAta, + vault, + ), + ]), + 'refund', + ); + + assert.equal(tokenAmount(contributorAta), 10n, 'contributor got their tokens back'); + assert.equal(tokenAmount(vault), 0n, 'vault is empty after the refund'); + assert.isNotOk(svm.getAccount(contributorAccount)?.exists, 'contributor account was closed'); + }); + + it('Releases the funds to the maker once the target is met', async () => { + const maker = await generateKeyPairSigner(); + svm.airdrop(maker.address, lamports(1_000_000_000n)); + const mint = await createMint(maker, 0, maker.address); + + const [fundraiser, bump] = await fundraiserPda(maker.address); + const [vault] = await findAssociatedTokenPda({ + owner: fundraiser, + mint: mint.address, + tokenProgram: TOKEN_PROGRAM_ADDRESS, + }); + + // Goal of 100 over 30 days; the 10% cap means it takes ten contributors. + send(await tx(maker, [initializeIx(maker, mint.address, fundraiser, vault, bump, 100n, 30)]), 'initialize'); + + for (let i = 0; i < 10; i++) { + const contributor = await generateKeyPairSigner(); + svm.airdrop(contributor.address, lamports(1_000_000_000n)); + const contributorAta = await fundAta(maker, maker, contributor.address, mint.address, 10n); + const [contributorAccount] = await contributorPda(fundraiser, contributor.address); + send( + await tx(contributor, [ + contributeIx(contributor, mint.address, fundraiser, contributorAccount, contributorAta, vault, 10n), + ]), + `contribute ${i}`, + ); + } + + assert.equal(tokenAmount(vault), 100n, 'vault reached the target'); + + const [makerAta] = await findAssociatedTokenPda({ + owner: maker.address, + mint: mint.address, + tokenProgram: TOKEN_PROGRAM_ADDRESS, + }); + send(await tx(maker, [checkIx(maker, mint.address, fundraiser, vault, makerAta)]), 'check contributions'); + + assert.equal(tokenAmount(makerAta), 100n, 'maker received the raised funds'); + assert.isNotOk(svm.getAccount(fundraiser)?.exists, 'fundraiser account was closed'); + }); + + it("Rejects a contribution credited to another contributor's record", async () => { + const maker = await generateKeyPairSigner(); + svm.airdrop(maker.address, lamports(1_000_000_000n)); + const mint = await createMint(maker, 0, maker.address); + + const [fundraiser, bump] = await fundraiserPda(maker.address); + const [vault] = await findAssociatedTokenPda({ + owner: fundraiser, + mint: mint.address, + tokenProgram: TOKEN_PROGRAM_ADDRESS, + }); + send(await tx(maker, [initializeIx(maker, mint.address, fundraiser, vault, bump, 100n, 30)]), 'initialize'); + + // Victim contributes first, which creates their program-owned record. + // Amounts stay well under the 10% cap so that the substituted-record + // rejection cannot be attributed to the per-contributor limit. + const victim = await generateKeyPairSigner(); + svm.airdrop(victim.address, lamports(1_000_000_000n)); + const victimAta = await fundAta(maker, maker, victim.address, mint.address, 1n); + const [victimAccount] = await contributorPda(fundraiser, victim.address); + send( + await tx(victim, [contributeIx(victim, mint.address, fundraiser, victimAccount, victimAta, vault, 1n)]), + 'victim contribute', + ); + + // The attacker signs their own transfer but points at the victim's record. + const attacker = await generateKeyPairSigner(); + svm.airdrop(attacker.address, lamports(1_000_000_000n)); + const attackerAta = await fundAta(maker, maker, attacker.address, mint.address, 1n); + sendExpectingFailure( + await tx(attacker, [ + contributeIx(attacker, mint.address, fundraiser, victimAccount, attackerAta, vault, 1n), + ]), + 'contribution into a substituted record', + ); + + assert.equal(tokenAmount(attackerAta), 1n, 'attacker kept their tokens'); + assert.equal(tokenAmount(vault), 1n, 'vault only holds the recorded contribution'); + }); + + it('Rejects a contributor record that is not the canonical PDA', async () => { + const maker = await generateKeyPairSigner(); + svm.airdrop(maker.address, lamports(1_000_000_000n)); + const mint = await createMint(maker, 0, maker.address); + + const [fundraiser, bump] = await fundraiserPda(maker.address); + const [vault] = await findAssociatedTokenPda({ + owner: fundraiser, + mint: mint.address, + tokenProgram: TOKEN_PROGRAM_ADDRESS, + }); + send(await tx(maker, [initializeIx(maker, mint.address, fundraiser, vault, bump, 100n, 30)]), 'initialize'); + + // The record address is derived on-chain, so a contributor cannot open a + // second record for themselves at any other address — including one + // derived from a non-canonical bump. A record that is not the canonical + // PDA is refused before it can be created, which also keeps every record + // reachable by `refund` (which only ever derives the canonical address). + const contributor = await generateKeyPairSigner(); + svm.airdrop(contributor.address, lamports(1_000_000_000n)); + const contributorAta = await fundAta(maker, maker, contributor.address, mint.address, 5n); + const notTheCanonicalPda = (await generateKeyPairSigner()).address; + + sendExpectingFailure( + await tx(contributor, [ + contributeIx(contributor, mint.address, fundraiser, notTheCanonicalPda, contributorAta, vault, 5n), + ]), + 'contribution into a non-canonical record', + ); + + assert.equal(tokenAmount(contributorAta), 5n, 'contributor kept their tokens'); + assert.isNotOk(svm.getAccount(notTheCanonicalPda)?.exists, 'no second record was created'); + }); + + it('Ignores unrecorded direct transfers into the vault', async () => { + const maker = await generateKeyPairSigner(); + svm.airdrop(maker.address, lamports(1_000_000_000n)); + const mint = await createMint(maker, 0, maker.address); + + const [fundraiser, bump] = await fundraiserPda(maker.address); + const [vault] = await findAssociatedTokenPda({ + owner: fundraiser, + mint: mint.address, + tokenProgram: TOKEN_PROGRAM_ADDRESS, + }); + + // Goal of 100 over 1 day; a single contributor gives the 10% max (10). + send(await tx(maker, [initializeIx(maker, mint.address, fundraiser, vault, bump, 100n, 1)]), 'initialize'); + + const contributor = await generateKeyPairSigner(); + svm.airdrop(contributor.address, lamports(1_000_000_000n)); + const contributorAta = await fundAta(maker, maker, contributor.address, mint.address, 10n); + const [contributorAccount] = await contributorPda(fundraiser, contributor.address); + send( + await tx(contributor, [ + contributeIx(contributor, mint.address, fundraiser, contributorAccount, contributorAta, vault, 10n), + ]), + 'contribute', + ); + + // Anyone can transfer straight into the vault's standard ATA. That must + // neither release the fundraiser nor lock the contributor out of a refund. + const outsiderAta = await fundAta(maker, maker, maker.address, mint.address, 90n); + send( + await tx(maker, [ + getTransferInstruction({ source: outsiderAta, destination: vault, authority: maker, amount: 90n }), + ]), + 'direct vault transfer', + ); + assert.equal(tokenAmount(vault), 100n, 'vault balance now looks like the target was met'); + + const [makerAta] = await findAssociatedTokenPda({ + owner: maker.address, + mint: mint.address, + tokenProgram: TOKEN_PROGRAM_ADDRESS, + }); + sendExpectingFailure( + await tx(maker, [checkIx(maker, mint.address, fundraiser, vault, makerAta)]), + 'release on an unrecorded deposit', + ); + + // The contributor is still refundable once the fundraiser ends. + warpDays(2); + send( + await tx(contributor, [ + refundIx( + contributor, + maker.address, + mint.address, + fundraiser, + contributorAccount, + contributorAta, + vault, + ), + ]), + 'refund', + ); + assert.equal(tokenAmount(contributorAta), 10n, 'contributor got their tokens back'); + }); +}); diff --git a/tokens/token-fundraiser/pinocchio/tsconfig.json b/tokens/token-fundraiser/pinocchio/tsconfig.json new file mode 100644 index 000000000..c02443141 --- /dev/null +++ b/tokens/token-fundraiser/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 + } +}