From 9b6c9697f123dceb11cb30e4aa6c39a5ea2fdb3a Mon Sep 17 00:00:00 2001 From: The Wuh <87859262+thewuhxyz@users.noreply.github.com> Date: Thu, 2 Jan 2025 15:12:53 +0100 Subject: [PATCH] add tokens/token-2022/transfer-hook/transfer-switch/anchor (#317) --- .../transfer-switch/anchor/.gitignore | 8 + .../transfer-switch/anchor/Anchor.toml | 18 + .../transfer-switch/anchor/Cargo.toml | 14 + .../transfer-switch/anchor/package.json | 18 + .../transfer-switch/anchor/pnpm-lock.yaml | 1542 +++++++++++++++++ .../programs/transfer-switch/Cargo.toml | 23 + .../programs/transfer-switch/Xargo.toml | 2 + .../programs/transfer-switch/src/error.rs | 10 + .../src/instructions/configure_admin.rs | 49 + .../initialise_extra_account_metas_list.rs | 83 + .../transfer-switch/src/instructions/mod.rs | 9 + .../src/instructions/switch.rs | 48 + .../src/instructions/transfer_hook.rs | 70 + .../programs/transfer-switch/src/lib.rs | 35 + .../programs/transfer-switch/src/state.rs | 15 + .../anchor/tests/transfer-switch.ts | 268 +++ .../transfer-switch/anchor/tsconfig.json | 10 + 17 files changed, 2222 insertions(+) create mode 100644 tokens/token-2022/transfer-hook/transfer-switch/anchor/.gitignore create mode 100644 tokens/token-2022/transfer-hook/transfer-switch/anchor/Anchor.toml create mode 100644 tokens/token-2022/transfer-hook/transfer-switch/anchor/Cargo.toml create mode 100644 tokens/token-2022/transfer-hook/transfer-switch/anchor/package.json create mode 100644 tokens/token-2022/transfer-hook/transfer-switch/anchor/pnpm-lock.yaml create mode 100644 tokens/token-2022/transfer-hook/transfer-switch/anchor/programs/transfer-switch/Cargo.toml create mode 100644 tokens/token-2022/transfer-hook/transfer-switch/anchor/programs/transfer-switch/Xargo.toml create mode 100644 tokens/token-2022/transfer-hook/transfer-switch/anchor/programs/transfer-switch/src/error.rs create mode 100644 tokens/token-2022/transfer-hook/transfer-switch/anchor/programs/transfer-switch/src/instructions/configure_admin.rs create mode 100644 tokens/token-2022/transfer-hook/transfer-switch/anchor/programs/transfer-switch/src/instructions/initialise_extra_account_metas_list.rs create mode 100644 tokens/token-2022/transfer-hook/transfer-switch/anchor/programs/transfer-switch/src/instructions/mod.rs create mode 100644 tokens/token-2022/transfer-hook/transfer-switch/anchor/programs/transfer-switch/src/instructions/switch.rs create mode 100644 tokens/token-2022/transfer-hook/transfer-switch/anchor/programs/transfer-switch/src/instructions/transfer_hook.rs create mode 100644 tokens/token-2022/transfer-hook/transfer-switch/anchor/programs/transfer-switch/src/lib.rs create mode 100644 tokens/token-2022/transfer-hook/transfer-switch/anchor/programs/transfer-switch/src/state.rs create mode 100644 tokens/token-2022/transfer-hook/transfer-switch/anchor/tests/transfer-switch.ts create mode 100644 tokens/token-2022/transfer-hook/transfer-switch/anchor/tsconfig.json diff --git a/tokens/token-2022/transfer-hook/transfer-switch/anchor/.gitignore b/tokens/token-2022/transfer-hook/transfer-switch/anchor/.gitignore new file mode 100644 index 000000000..8d401163f --- /dev/null +++ b/tokens/token-2022/transfer-hook/transfer-switch/anchor/.gitignore @@ -0,0 +1,8 @@ + +.anchor +.DS_Store +target +**/*.rs.bk +node_modules +test-ledger +.yarn diff --git a/tokens/token-2022/transfer-hook/transfer-switch/anchor/Anchor.toml b/tokens/token-2022/transfer-hook/transfer-switch/anchor/Anchor.toml new file mode 100644 index 000000000..0933e58d9 --- /dev/null +++ b/tokens/token-2022/transfer-hook/transfer-switch/anchor/Anchor.toml @@ -0,0 +1,18 @@ +[toolchain] + +[features] +resolution = true +skip-lint = false + +[programs.localnet] +transfer_switch = "FjcHckEgXcBhFmSGai3FRpDLiT6hbpV893n8iTxVd81g" + +[registry] +url = "https://api.apr.dev" + +[provider] +cluster = "Localnet" +wallet = "~/.config/solana/id.json" + +[scripts] +test = "pnpm ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts" diff --git a/tokens/token-2022/transfer-hook/transfer-switch/anchor/Cargo.toml b/tokens/token-2022/transfer-hook/transfer-switch/anchor/Cargo.toml new file mode 100644 index 000000000..f39770481 --- /dev/null +++ b/tokens/token-2022/transfer-hook/transfer-switch/anchor/Cargo.toml @@ -0,0 +1,14 @@ +[workspace] +members = [ + "programs/*" +] +resolver = "2" + +[profile.release] +overflow-checks = true +lto = "fat" +codegen-units = 1 +[profile.release.build-override] +opt-level = 3 +incremental = false +codegen-units = 1 diff --git a/tokens/token-2022/transfer-hook/transfer-switch/anchor/package.json b/tokens/token-2022/transfer-hook/transfer-switch/anchor/package.json new file mode 100644 index 000000000..3dcb71d5a --- /dev/null +++ b/tokens/token-2022/transfer-hook/transfer-switch/anchor/package.json @@ -0,0 +1,18 @@ +{ + "dependencies": { + "@coral-xyz/anchor": "^0.30.1", + "@solana/spl-token": "^0.4.0" + }, + "devDependencies": { + "anchor-bankrun": "^0.5.0", + "solana-bankrun": "^0.4.0", + "@types/bn.js": "^5.1.0", + "@types/chai": "^4.3.0", + "@types/mocha": "10.0.9", + "chai": "^4.3.4", + "mocha": "^10.8.2", + "prettier": "^2.6.2", + "ts-mocha": "^10.0.0", + "typescript": "^5" + } +} diff --git a/tokens/token-2022/transfer-hook/transfer-switch/anchor/pnpm-lock.yaml b/tokens/token-2022/transfer-hook/transfer-switch/anchor/pnpm-lock.yaml new file mode 100644 index 000000000..56aadc27c --- /dev/null +++ b/tokens/token-2022/transfer-hook/transfer-switch/anchor/pnpm-lock.yaml @@ -0,0 +1,1542 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@coral-xyz/anchor': + specifier: ^0.30.1 + version: 0.30.1(bufferutil@4.0.8)(utf-8-validate@5.0.10) + '@solana/spl-token': + specifier: ^0.4.0 + version: 0.4.6(@solana/web3.js@1.91.8(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(fastestsmallesttextencoderdecoder@1.0.22)(utf-8-validate@5.0.10) + devDependencies: + '@types/bn.js': + specifier: ^5.1.0 + version: 5.1.5 + '@types/chai': + specifier: ^4.3.0 + version: 4.3.16 + '@types/mocha': + specifier: 10.0.9 + version: 10.0.9 + anchor-bankrun: + specifier: ^0.5.0 + version: 0.5.0(@coral-xyz/anchor@0.30.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(@solana/web3.js@1.91.8(bufferutil@4.0.8)(utf-8-validate@5.0.10))(solana-bankrun@0.4.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)) + chai: + specifier: ^4.3.4 + version: 4.4.1 + mocha: + specifier: ^10.8.2 + version: 10.8.2 + prettier: + specifier: ^2.6.2 + version: 2.8.8 + solana-bankrun: + specifier: ^0.4.0 + version: 0.4.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) + ts-mocha: + specifier: ^10.0.0 + version: 10.0.0(mocha@10.8.2) + typescript: + specifier: ^5 + version: 5.6.3 + +packages: + + '@babel/runtime@7.24.5': + resolution: {integrity: sha512-Nms86NXrsaeU9vbBJKni6gXiEXZ4CVpYVzEjDH9Sb8vmZ3UljyA1GSOJl/6LGPO8EHLuSF9H+IxNXHPX8QHJ4g==} + engines: {node: '>=6.9.0'} + + '@coral-xyz/anchor-errors@0.30.1': + resolution: {integrity: sha512-9Mkradf5yS5xiLWrl9WrpjqOrAV+/W2RQHDlbnAZBivoGpOs1ECjoDCkVk4aRG8ZdiFiB8zQEVlxf+8fKkmSfQ==} + engines: {node: '>=10'} + + '@coral-xyz/anchor@0.30.1': + resolution: {integrity: sha512-gDXFoF5oHgpriXAaLpxyWBHdCs8Awgf/gLHIo6crv7Aqm937CNdY+x+6hoj7QR5vaJV7MxWSQ0NGFzL3kPbWEQ==} + engines: {node: '>=11'} + + '@coral-xyz/borsh@0.30.1': + resolution: {integrity: sha512-aaxswpPrCFKl8vZTbxLssA2RvwX2zmKLlRCIktJOwW+VpVwYtXRtlWiIP+c2pPRKneiTiWCN2GEMSH9j1zTlWQ==} + engines: {node: '>=10'} + peerDependencies: + '@solana/web3.js': ^1.68.0 + + '@noble/curves@1.4.0': + resolution: {integrity: sha512-p+4cb332SFCrReJkCYe8Xzm0OWi4Jji5jVdIZRL/PmacmDkFNw6MrrV+gGpiPxLHbV+zKFRywUWbaseT+tZRXg==} + + '@noble/hashes@1.4.0': + resolution: {integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==} + engines: {node: '>= 16'} + + '@solana/buffer-layout-utils@0.2.0': + resolution: {integrity: sha512-szG4sxgJGktbuZYDg2FfNmkMi0DYQoVjN2h7ta1W1hPrwzarcFLBq9UpX1UjNXsNpT9dn+chgprtWGioUAr4/g==} + engines: {node: '>= 10'} + + '@solana/buffer-layout@4.0.1': + resolution: {integrity: sha512-E1ImOIAD1tBZFRdjeM4/pzTiTApC0AOBGwyAMS4fwIodCWArzJ3DWdoh8cKxeFM2fElkxBh2Aqts1BPC373rHA==} + engines: {node: '>=5.10'} + + '@solana/codecs-core@2.0.0-preview.2': + resolution: {integrity: sha512-gLhCJXieSCrAU7acUJjbXl+IbGnqovvxQLlimztPoGgfLQ1wFYu+XJswrEVQqknZYK1pgxpxH3rZ+OKFs0ndQg==} + + '@solana/codecs-data-structures@2.0.0-preview.2': + resolution: {integrity: sha512-Xf5vIfromOZo94Q8HbR04TbgTwzigqrKII0GjYr21K7rb3nba4hUW2ir8kguY7HWFBcjHGlU5x3MevKBOLp3Zg==} + + '@solana/codecs-numbers@2.0.0-preview.2': + resolution: {integrity: sha512-aLZnDTf43z4qOnpTcDsUVy1Ci9im1Md8thWipSWbE+WM9ojZAx528oAql+Cv8M8N+6ALKwgVRhPZkto6E59ARw==} + + '@solana/codecs-strings@2.0.0-preview.2': + resolution: {integrity: sha512-EgBwY+lIaHHgMJIqVOGHfIfpdmmUDNoNO/GAUGeFPf+q0dF+DtwhJPEMShhzh64X2MeCZcmSO6Kinx0Bvmmz2g==} + peerDependencies: + fastestsmallesttextencoderdecoder: ^1.0.22 + + '@solana/codecs@2.0.0-preview.2': + resolution: {integrity: sha512-4HHzCD5+pOSmSB71X6w9ptweV48Zj1Vqhe732+pcAQ2cMNnN0gMPMdDq7j3YwaZDZ7yrILVV/3+HTnfT77t2yA==} + + '@solana/errors@2.0.0-preview.2': + resolution: {integrity: sha512-H2DZ1l3iYF5Rp5pPbJpmmtCauWeQXRJapkDg8epQ8BJ7cA2Ut/QEtC3CMmw/iMTcuS6uemFNLcWvlOfoQhvQuA==} + hasBin: true + + '@solana/options@2.0.0-preview.2': + resolution: {integrity: sha512-FAHqEeH0cVsUOTzjl5OfUBw2cyT8d5Oekx4xcn5hn+NyPAfQJgM3CEThzgRD6Q/4mM5pVUnND3oK/Mt1RzSE/w==} + + '@solana/spl-token-group@0.0.4': + resolution: {integrity: sha512-7+80nrEMdUKlK37V6kOe024+T7J4nNss0F8LQ9OOPYdWCCfJmsGUzVx2W3oeizZR4IHM6N4yC9v1Xqwc3BTPWw==} + engines: {node: '>=16'} + peerDependencies: + '@solana/web3.js': ^1.91.6 + + '@solana/spl-token-metadata@0.1.4': + resolution: {integrity: sha512-N3gZ8DlW6NWDV28+vCCDJoTqaCZiF/jDUnk3o8GRkAFzHObiR60Bs1gXHBa8zCPdvOwiG6Z3dg5pg7+RW6XNsQ==} + engines: {node: '>=16'} + peerDependencies: + '@solana/web3.js': ^1.91.6 + + '@solana/spl-token@0.4.6': + resolution: {integrity: sha512-1nCnUqfHVtdguFciVWaY/RKcQz1IF4b31jnKgAmjU9QVN1q7dRUkTEWJZgTYIEtsULjVnC9jRqlhgGN39WbKKA==} + engines: {node: '>=16'} + peerDependencies: + '@solana/web3.js': ^1.91.6 + + '@solana/spl-type-length-value@0.1.0': + resolution: {integrity: sha512-JBMGB0oR4lPttOZ5XiUGyvylwLQjt1CPJa6qQ5oM+MBCndfjz2TKKkw0eATlLLcYmq1jBVsNlJ2cD6ns2GR7lA==} + engines: {node: '>=16'} + + '@solana/web3.js@1.91.8': + resolution: {integrity: sha512-USa6OS1jbh8zOapRJ/CBZImZ8Xb7AJjROZl5adql9TpOoBN9BUzyyouS5oPuZHft7S7eB8uJPuXWYjMi6BHgOw==} + + '@types/bn.js@5.1.5': + resolution: {integrity: sha512-V46N0zwKRF5Q00AZ6hWtN0T8gGmDUaUzLWQvHFo5yThtVwK/VCenFY3wXVbOvNfajEpsTfQM4IN9k/d6gUVX3A==} + + '@types/chai@4.3.16': + resolution: {integrity: sha512-PatH4iOdyh3MyWtmHVFXLWCCIhUbopaltqddG9BzB+gMIzee2MJrvd+jouii9Z3wzQJruGWAm7WOMjgfG8hQlQ==} + + '@types/connect@3.4.38': + resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} + + '@types/json5@0.0.29': + resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + + '@types/mocha@10.0.9': + resolution: {integrity: sha512-sicdRoWtYevwxjOHNMPTl3vSfJM6oyW8o1wXeI7uww6b6xHg8eBznQDNSGBCDJmsE8UMxP05JgZRtsKbTqt//Q==} + + '@types/node@12.20.55': + resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} + + '@types/node@20.12.11': + resolution: {integrity: sha512-vDg9PZ/zi+Nqp6boSOT7plNuthRugEKixDv5sFTIpkE89MmNtEArAShI4mxuX2+UrLEe9pxC1vm2cjm9YlWbJw==} + + '@types/ws@7.4.7': + resolution: {integrity: sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==} + + JSONStream@1.3.5: + resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==} + hasBin: true + + agentkeepalive@4.5.0: + resolution: {integrity: sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==} + engines: {node: '>= 8.0.0'} + + anchor-bankrun@0.5.0: + resolution: {integrity: sha512-cNTRv7pN9dy+kiyJ3UlNVTg9hAXhY2HtNVNXJbP/2BkS9nOdLV0qKWhgW8UR9Go0gYuEOLKuPzrGL4HFAZPsVw==} + engines: {node: '>= 10'} + peerDependencies: + '@coral-xyz/anchor': ^0.30.0 + '@solana/web3.js': '>1.92.0' + solana-bankrun: '>=0.2.0 <0.5.0' + + ansi-colors@4.1.3: + resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} + engines: {node: '>=6'} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + arrify@1.0.1: + resolution: {integrity: sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==} + engines: {node: '>=0.10.0'} + + assertion-error@1.1.0: + resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + base-x@3.0.9: + resolution: {integrity: sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==} + + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + bigint-buffer@1.1.5: + resolution: {integrity: sha512-trfYco6AoZ+rKhKnxA0hgX0HAbVP/s808/EuDSe2JDzUnCp/xAsli35Orvk67UrTEcwuxZqYZDmfA2RXJgxVvA==} + engines: {node: '>= 10.0.0'} + + bignumber.js@9.1.2: + resolution: {integrity: sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==} + + binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + engines: {node: '>=8'} + + bindings@1.5.0: + resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} + + bn.js@5.2.1: + resolution: {integrity: sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==} + + borsh@0.7.0: + resolution: {integrity: sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA==} + + brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + + braces@3.0.2: + resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} + engines: {node: '>=8'} + + browser-stdout@1.3.1: + resolution: {integrity: sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==} + + bs58@4.0.1: + resolution: {integrity: sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==} + + buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + + buffer-layout@1.2.2: + resolution: {integrity: sha512-kWSuLN694+KTk8SrYvCqwP2WcgQjoRCiF5b4QDvkkz8EmgD+aWAIceGFKMIAdmF/pH+vpgNV3d3kAKorcdAmWA==} + engines: {node: '>=4.5'} + + buffer@6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + + bufferutil@4.0.8: + resolution: {integrity: sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==} + engines: {node: '>=6.14.2'} + + camelcase@6.3.0: + resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} + engines: {node: '>=10'} + + chai@4.4.1: + resolution: {integrity: sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==} + engines: {node: '>=4'} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + chalk@5.3.0: + resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + + check-error@1.0.3: + resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==} + + chokidar@3.5.3: + resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} + engines: {node: '>= 8.10.0'} + + cliui@7.0.4: + resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} + + 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@12.0.0: + resolution: {integrity: sha512-MwVNWlYjDTtOjX5PiD7o5pK0UrFU/OYgcJfjjK4RaHZETNtjJqrZa9Y9ds88+A+f+d5lv+561eZ+yCKoS3gbAA==} + engines: {node: '>=18'} + + commander@2.20.3: + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + + cross-fetch@3.1.8: + resolution: {integrity: sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==} + + crypto-hash@1.3.0: + resolution: {integrity: sha512-lyAZ0EMyjDkVvz8WOeVnuCPvKVBXcMv1l5SVqO1yC7PzTwrD/pPje/BIRbWhMoPe436U+Y2nD7f5bFx0kt+Sbg==} + engines: {node: '>=8'} + + debug@4.3.7: + resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} + 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'} + + deep-eql@4.1.3: + resolution: {integrity: sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==} + engines: {node: '>=6'} + + delay@5.0.0: + resolution: {integrity: sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==} + engines: {node: '>=10'} + + diff@3.5.0: + resolution: {integrity: sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==} + engines: {node: '>=0.3.1'} + + diff@5.2.0: + resolution: {integrity: sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==} + engines: {node: '>=0.3.1'} + + dot-case@3.0.4: + resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + es6-promise@4.2.8: + resolution: {integrity: sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==} + + es6-promisify@5.0.0: + resolution: {integrity: sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==} + + escalade@3.1.2: + resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} + engines: {node: '>=6'} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + eventemitter3@4.0.7: + resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} + + eyes@0.1.8: + resolution: {integrity: sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ==} + engines: {node: '> 0.1.90'} + + fast-stable-stringify@1.0.0: + resolution: {integrity: sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag==} + + fastestsmallesttextencoderdecoder@1.0.22: + resolution: {integrity: sha512-Pb8d48e+oIuY4MaM64Cd7OW1gt4nxCHs7/ddPPZ/Ic3sg8yVGM7O9wDvZ7us6ScaUupzM+pfBolwtYhN1IxBIw==} + + file-uri-to-path@1.0.0: + resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} + + fill-range@7.0.1: + resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} + engines: {node: '>=8'} + + 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 + + fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + + 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.*} + + get-func-name@2.0.2: + resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob@8.1.0: + resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} + engines: {node: '>=12'} + deprecated: Glob versions prior to v9 are no longer supported + + 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 + + humanize-ms@1.2.1: + resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==} + + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + + inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + 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'} + + isomorphic-ws@4.0.1: + resolution: {integrity: sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==} + peerDependencies: + ws: '*' + + jayson@4.1.0: + resolution: {integrity: sha512-R6JlbyLN53Mjku329XoRT2zJAE6ZgOQ8f91ucYdMCD4nkGCF9kZSrcGXpHIU4jeKj58zUZke2p+cdQchU7Ly7A==} + engines: {node: '>=8'} + hasBin: true + + js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + + json-stringify-safe@5.0.1: + resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} + + json5@1.0.2: + resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} + hasBin: true + + jsonparse@1.3.1: + resolution: {integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==} + engines: {'0': node >= 0.2.0} + + 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'} + + loupe@2.3.7: + resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==} + + lower-case@2.0.2: + resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} + + make-error@1.3.6: + resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + + minimatch@5.1.6: + resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} + engines: {node: '>=10'} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + mkdirp@0.5.6: + resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} + hasBin: true + + mocha@10.8.2: + resolution: {integrity: sha512-VZlYo/WE8t1tstuRmqgeyBgCbJc/lEdopaa+axcKzTBJ+UIdlAB9XnmvTCAH4pwR4ElNInaedhEBmZD8iCSVEg==} + engines: {node: '>= 14.0.0'} + hasBin: true + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + no-case@3.0.4: + resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} + + node-fetch@2.7.0: + resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + + node-gyp-build@4.8.1: + resolution: {integrity: sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==} + hasBin: true + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + 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'} + + pako@2.1.0: + resolution: {integrity: sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + pathval@1.1.1: + resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + prettier@2.8.8: + resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} + engines: {node: '>=10.13.0'} + hasBin: true + + randombytes@2.1.0: + resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} + + readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + + regenerator-runtime@0.14.1: + resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} + + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + rpc-websockets@7.11.0: + resolution: {integrity: sha512-IkLYjayPv6Io8C/TdCL5gwgzd1hFz2vmBZrjMw/SPEXo51ETOhnzgS4Qy5GWi2JQN7HKHa66J3+2mv0fgNh/7w==} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + serialize-javascript@6.0.2: + resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} + + snake-case@3.0.4: + resolution: {integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==} + + solana-bankrun-darwin-arm64@0.4.0: + resolution: {integrity: sha512-6dz78Teoz7ez/3lpRLDjktYLJb79FcmJk2me4/YaB8WiO6W43OdExU4h+d2FyuAryO2DgBPXaBoBNY/8J1HJmw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + solana-bankrun-darwin-universal@0.4.0: + resolution: {integrity: sha512-zSSw/Jx3KNU42pPMmrEWABd0nOwGJfsj7nm9chVZ3ae7WQg3Uty0hHAkn5NSDCj3OOiN0py9Dr1l9vmRJpOOxg==} + engines: {node: '>= 10'} + os: [darwin] + + solana-bankrun-darwin-x64@0.4.0: + resolution: {integrity: sha512-LWjs5fsgHFtyr7YdJR6r0Ho5zrtzI6CY4wvwPXr8H2m3b4pZe6RLIZjQtabCav4cguc14G0K8yQB2PTMuGub8w==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + solana-bankrun-linux-x64-gnu@0.4.0: + resolution: {integrity: sha512-SrlVrb82UIxt21Zr/XZFHVV/h9zd2/nP25PMpLJVLD7Pgl2yhkhfi82xj3OjxoQqWe+zkBJ+uszA0EEKr67yNw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + solana-bankrun-linux-x64-musl@0.4.0: + resolution: {integrity: sha512-Nv328ZanmURdYfcLL+jwB1oMzX4ZzK57NwIcuJjGlf0XSNLq96EoaO5buEiUTo4Ls7MqqMyLbClHcrPE7/aKyA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + solana-bankrun@0.4.0: + resolution: {integrity: sha512-NMmXUipPBkt8NgnyNO3SCnPERP6xT/AMNMBooljGA3+rG6NN8lmXJsKeLqQTiFsDeWD74U++QM/DgcueSWvrIg==} + engines: {node: '>= 10'} + + source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + superstruct@0.14.2: + resolution: {integrity: sha512-nPewA6m9mR3d6k7WkZ8N8zpTWfenFH3q9pA2PkuiZxINr9DKB2+40wEQf0ixn8VaGuJ78AB6iWOtStI+/4FKZQ==} + + superstruct@0.15.5: + resolution: {integrity: sha512-4AOeU+P5UuE/4nOUkmcQdW5y7i9ndt1cQd/3iUe+LTz3RxESf/W/5lg4B74HbDMMv8PHnPnGCQFH45kBcrQYoQ==} + + 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'} + + text-encoding-utf-8@1.0.2: + resolution: {integrity: sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg==} + + through@2.3.8: + resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + toml@3.0.0: + resolution: {integrity: sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==} + + tr46@0.0.3: + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + + ts-mocha@10.0.0: + resolution: {integrity: sha512-VRfgDO+iiuJFlNB18tzOfypJ21xn2xbuZyDvJvqpTbWgkAgD17ONGr8t+Tl8rcBtOBdjXp5e/Rk+d39f7XBHRw==} + engines: {node: '>= 6.X.X'} + hasBin: true + peerDependencies: + mocha: ^3.X.X || ^4.X.X || ^5.X.X || ^6.X.X || ^7.X.X || ^8.X.X || ^9.X.X || ^10.X.X + + ts-node@7.0.1: + resolution: {integrity: sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw==} + engines: {node: '>=4.2.0'} + hasBin: true + + tsconfig-paths@3.15.0: + resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} + + tslib@2.6.2: + resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} + + type-detect@4.0.8: + resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} + engines: {node: '>=4'} + + typescript@5.6.3: + resolution: {integrity: sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==} + engines: {node: '>=14.17'} + hasBin: true + + undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + + utf-8-validate@5.0.10: + resolution: {integrity: sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==} + engines: {node: '>=6.14.2'} + + uuid@8.3.2: + resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} + hasBin: true + + webidl-conversions@3.0.1: + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + + whatwg-url@5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + + workerpool@6.5.1: + resolution: {integrity: sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==} + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + ws@7.5.9: + resolution: {integrity: sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==} + engines: {node: '>=8.3.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + ws@8.17.0: + resolution: {integrity: sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow==} + 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@20.2.9: + resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} + engines: {node: '>=10'} + + yargs-unparser@2.0.0: + resolution: {integrity: sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==} + engines: {node: '>=10'} + + yargs@16.2.0: + resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} + engines: {node: '>=10'} + + yn@2.0.0: + resolution: {integrity: sha512-uTv8J/wiWTgUTg+9vLTi//leUl5vDQS6uii/emeTb2ssY7vl6QWf2fFbIIGjnhjvbdKlU0ed7QPgY1htTC86jQ==} + engines: {node: '>=4'} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + +snapshots: + + '@babel/runtime@7.24.5': + dependencies: + regenerator-runtime: 0.14.1 + + '@coral-xyz/anchor-errors@0.30.1': {} + + '@coral-xyz/anchor@0.30.1(bufferutil@4.0.8)(utf-8-validate@5.0.10)': + dependencies: + '@coral-xyz/anchor-errors': 0.30.1 + '@coral-xyz/borsh': 0.30.1(@solana/web3.js@1.91.8(bufferutil@4.0.8)(utf-8-validate@5.0.10)) + '@noble/hashes': 1.4.0 + '@solana/web3.js': 1.91.8(bufferutil@4.0.8)(utf-8-validate@5.0.10) + bn.js: 5.2.1 + bs58: 4.0.1 + buffer-layout: 1.2.2 + camelcase: 6.3.0 + cross-fetch: 3.1.8 + crypto-hash: 1.3.0 + eventemitter3: 4.0.7 + pako: 2.1.0 + snake-case: 3.0.4 + superstruct: 0.15.5 + toml: 3.0.0 + transitivePeerDependencies: + - bufferutil + - encoding + - utf-8-validate + + '@coral-xyz/borsh@0.30.1(@solana/web3.js@1.91.8(bufferutil@4.0.8)(utf-8-validate@5.0.10))': + dependencies: + '@solana/web3.js': 1.91.8(bufferutil@4.0.8)(utf-8-validate@5.0.10) + bn.js: 5.2.1 + buffer-layout: 1.2.2 + + '@noble/curves@1.4.0': + dependencies: + '@noble/hashes': 1.4.0 + + '@noble/hashes@1.4.0': {} + + '@solana/buffer-layout-utils@0.2.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)': + dependencies: + '@solana/buffer-layout': 4.0.1 + '@solana/web3.js': 1.91.8(bufferutil@4.0.8)(utf-8-validate@5.0.10) + bigint-buffer: 1.1.5 + bignumber.js: 9.1.2 + transitivePeerDependencies: + - bufferutil + - encoding + - utf-8-validate + + '@solana/buffer-layout@4.0.1': + dependencies: + buffer: 6.0.3 + + '@solana/codecs-core@2.0.0-preview.2': + dependencies: + '@solana/errors': 2.0.0-preview.2 + + '@solana/codecs-data-structures@2.0.0-preview.2': + dependencies: + '@solana/codecs-core': 2.0.0-preview.2 + '@solana/codecs-numbers': 2.0.0-preview.2 + '@solana/errors': 2.0.0-preview.2 + + '@solana/codecs-numbers@2.0.0-preview.2': + dependencies: + '@solana/codecs-core': 2.0.0-preview.2 + '@solana/errors': 2.0.0-preview.2 + + '@solana/codecs-strings@2.0.0-preview.2(fastestsmallesttextencoderdecoder@1.0.22)': + dependencies: + '@solana/codecs-core': 2.0.0-preview.2 + '@solana/codecs-numbers': 2.0.0-preview.2 + '@solana/errors': 2.0.0-preview.2 + fastestsmallesttextencoderdecoder: 1.0.22 + + '@solana/codecs@2.0.0-preview.2(fastestsmallesttextencoderdecoder@1.0.22)': + dependencies: + '@solana/codecs-core': 2.0.0-preview.2 + '@solana/codecs-data-structures': 2.0.0-preview.2 + '@solana/codecs-numbers': 2.0.0-preview.2 + '@solana/codecs-strings': 2.0.0-preview.2(fastestsmallesttextencoderdecoder@1.0.22) + '@solana/options': 2.0.0-preview.2 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/errors@2.0.0-preview.2': + dependencies: + chalk: 5.3.0 + commander: 12.0.0 + + '@solana/options@2.0.0-preview.2': + dependencies: + '@solana/codecs-core': 2.0.0-preview.2 + '@solana/codecs-numbers': 2.0.0-preview.2 + + '@solana/spl-token-group@0.0.4(@solana/web3.js@1.91.8(bufferutil@4.0.8)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)': + dependencies: + '@solana/codecs': 2.0.0-preview.2(fastestsmallesttextencoderdecoder@1.0.22) + '@solana/spl-type-length-value': 0.1.0 + '@solana/web3.js': 1.91.8(bufferutil@4.0.8)(utf-8-validate@5.0.10) + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/spl-token-metadata@0.1.4(@solana/web3.js@1.91.8(bufferutil@4.0.8)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)': + dependencies: + '@solana/codecs': 2.0.0-preview.2(fastestsmallesttextencoderdecoder@1.0.22) + '@solana/spl-type-length-value': 0.1.0 + '@solana/web3.js': 1.91.8(bufferutil@4.0.8)(utf-8-validate@5.0.10) + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/spl-token@0.4.6(@solana/web3.js@1.91.8(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(fastestsmallesttextencoderdecoder@1.0.22)(utf-8-validate@5.0.10)': + dependencies: + '@solana/buffer-layout': 4.0.1 + '@solana/buffer-layout-utils': 0.2.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) + '@solana/spl-token-group': 0.0.4(@solana/web3.js@1.91.8(bufferutil@4.0.8)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22) + '@solana/spl-token-metadata': 0.1.4(@solana/web3.js@1.91.8(bufferutil@4.0.8)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22) + '@solana/web3.js': 1.91.8(bufferutil@4.0.8)(utf-8-validate@5.0.10) + buffer: 6.0.3 + transitivePeerDependencies: + - bufferutil + - encoding + - fastestsmallesttextencoderdecoder + - utf-8-validate + + '@solana/spl-type-length-value@0.1.0': + dependencies: + buffer: 6.0.3 + + '@solana/web3.js@1.91.8(bufferutil@4.0.8)(utf-8-validate@5.0.10)': + dependencies: + '@babel/runtime': 7.24.5 + '@noble/curves': 1.4.0 + '@noble/hashes': 1.4.0 + '@solana/buffer-layout': 4.0.1 + agentkeepalive: 4.5.0 + bigint-buffer: 1.1.5 + bn.js: 5.2.1 + borsh: 0.7.0 + bs58: 4.0.1 + buffer: 6.0.3 + fast-stable-stringify: 1.0.0 + jayson: 4.1.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) + node-fetch: 2.7.0 + rpc-websockets: 7.11.0 + superstruct: 0.14.2 + transitivePeerDependencies: + - bufferutil + - encoding + - utf-8-validate + + '@types/bn.js@5.1.5': + dependencies: + '@types/node': 20.12.11 + + '@types/chai@4.3.16': {} + + '@types/connect@3.4.38': + dependencies: + '@types/node': 12.20.55 + + '@types/json5@0.0.29': + optional: true + + '@types/mocha@10.0.9': {} + + '@types/node@12.20.55': {} + + '@types/node@20.12.11': + dependencies: + undici-types: 5.26.5 + + '@types/ws@7.4.7': + dependencies: + '@types/node': 12.20.55 + + JSONStream@1.3.5: + dependencies: + jsonparse: 1.3.1 + through: 2.3.8 + + agentkeepalive@4.5.0: + dependencies: + humanize-ms: 1.2.1 + + anchor-bankrun@0.5.0(@coral-xyz/anchor@0.30.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(@solana/web3.js@1.91.8(bufferutil@4.0.8)(utf-8-validate@5.0.10))(solana-bankrun@0.4.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)): + dependencies: + '@coral-xyz/anchor': 0.30.1(bufferutil@4.0.8)(utf-8-validate@5.0.10) + '@solana/web3.js': 1.91.8(bufferutil@4.0.8)(utf-8-validate@5.0.10) + solana-bankrun: 0.4.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) + + ansi-colors@4.1.3: {} + + ansi-regex@5.0.1: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + + argparse@2.0.1: {} + + arrify@1.0.1: {} + + assertion-error@1.1.0: {} + + balanced-match@1.0.2: {} + + base-x@3.0.9: + dependencies: + safe-buffer: 5.2.1 + + base64-js@1.5.1: {} + + bigint-buffer@1.1.5: + dependencies: + bindings: 1.5.0 + + bignumber.js@9.1.2: {} + + binary-extensions@2.3.0: {} + + bindings@1.5.0: + dependencies: + file-uri-to-path: 1.0.0 + + bn.js@5.2.1: {} + + borsh@0.7.0: + dependencies: + bn.js: 5.2.1 + bs58: 4.0.1 + text-encoding-utf-8: 1.0.2 + + brace-expansion@2.0.1: + dependencies: + balanced-match: 1.0.2 + + braces@3.0.2: + dependencies: + fill-range: 7.0.1 + + browser-stdout@1.3.1: {} + + bs58@4.0.1: + dependencies: + base-x: 3.0.9 + + buffer-from@1.1.2: {} + + buffer-layout@1.2.2: {} + + buffer@6.0.3: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + + bufferutil@4.0.8: + dependencies: + node-gyp-build: 4.8.1 + optional: true + + camelcase@6.3.0: {} + + chai@4.4.1: + dependencies: + assertion-error: 1.1.0 + check-error: 1.0.3 + deep-eql: 4.1.3 + get-func-name: 2.0.2 + loupe: 2.3.7 + pathval: 1.1.1 + type-detect: 4.0.8 + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + chalk@5.3.0: {} + + check-error@1.0.3: + dependencies: + get-func-name: 2.0.2 + + chokidar@3.5.3: + dependencies: + anymatch: 3.1.3 + braces: 3.0.2 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + + cliui@7.0.4: + 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@12.0.0: {} + + commander@2.20.3: {} + + cross-fetch@3.1.8: + dependencies: + node-fetch: 2.7.0 + transitivePeerDependencies: + - encoding + + crypto-hash@1.3.0: {} + + debug@4.3.7(supports-color@8.1.1): + dependencies: + ms: 2.1.3 + optionalDependencies: + supports-color: 8.1.1 + + decamelize@4.0.0: {} + + deep-eql@4.1.3: + dependencies: + type-detect: 4.0.8 + + delay@5.0.0: {} + + diff@3.5.0: {} + + diff@5.2.0: {} + + dot-case@3.0.4: + dependencies: + no-case: 3.0.4 + tslib: 2.6.2 + + emoji-regex@8.0.0: {} + + es6-promise@4.2.8: {} + + es6-promisify@5.0.0: + dependencies: + es6-promise: 4.2.8 + + escalade@3.1.2: {} + + escape-string-regexp@4.0.0: {} + + eventemitter3@4.0.7: {} + + eyes@0.1.8: {} + + fast-stable-stringify@1.0.0: {} + + fastestsmallesttextencoderdecoder@1.0.22: {} + + file-uri-to-path@1.0.0: {} + + fill-range@7.0.1: + dependencies: + to-regex-range: 5.0.1 + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + flat@5.0.2: {} + + fs.realpath@1.0.0: {} + + fsevents@2.3.3: + optional: true + + get-caller-file@2.0.5: {} + + get-func-name@2.0.2: {} + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob@8.1.0: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 5.1.6 + once: 1.4.0 + + has-flag@4.0.0: {} + + he@1.2.0: {} + + humanize-ms@1.2.1: + dependencies: + ms: 2.1.3 + + ieee754@1.2.1: {} + + inflight@1.0.6: + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + + inherits@2.0.4: {} + + is-binary-path@2.1.0: + dependencies: + binary-extensions: 2.3.0 + + is-extglob@2.1.1: {} + + is-fullwidth-code-point@3.0.0: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-number@7.0.0: {} + + is-plain-obj@2.1.0: {} + + is-unicode-supported@0.1.0: {} + + isomorphic-ws@4.0.1(ws@7.5.9(bufferutil@4.0.8)(utf-8-validate@5.0.10)): + dependencies: + ws: 7.5.9(bufferutil@4.0.8)(utf-8-validate@5.0.10) + + jayson@4.1.0(bufferutil@4.0.8)(utf-8-validate@5.0.10): + dependencies: + '@types/connect': 3.4.38 + '@types/node': 12.20.55 + '@types/ws': 7.4.7 + JSONStream: 1.3.5 + commander: 2.20.3 + delay: 5.0.0 + es6-promisify: 5.0.0 + eyes: 0.1.8 + isomorphic-ws: 4.0.1(ws@7.5.9(bufferutil@4.0.8)(utf-8-validate@5.0.10)) + json-stringify-safe: 5.0.1 + uuid: 8.3.2 + ws: 7.5.9(bufferutil@4.0.8)(utf-8-validate@5.0.10) + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + js-yaml@4.1.0: + dependencies: + argparse: 2.0.1 + + json-stringify-safe@5.0.1: {} + + json5@1.0.2: + dependencies: + minimist: 1.2.8 + optional: true + + jsonparse@1.3.1: {} + + 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 + + loupe@2.3.7: + dependencies: + get-func-name: 2.0.2 + + lower-case@2.0.2: + dependencies: + tslib: 2.6.2 + + make-error@1.3.6: {} + + minimatch@5.1.6: + dependencies: + brace-expansion: 2.0.1 + + minimist@1.2.8: {} + + mkdirp@0.5.6: + dependencies: + minimist: 1.2.8 + + mocha@10.8.2: + dependencies: + ansi-colors: 4.1.3 + browser-stdout: 1.3.1 + chokidar: 3.5.3 + debug: 4.3.7(supports-color@8.1.1) + diff: 5.2.0 + escape-string-regexp: 4.0.0 + find-up: 5.0.0 + glob: 8.1.0 + he: 1.2.0 + js-yaml: 4.1.0 + log-symbols: 4.1.0 + minimatch: 5.1.6 + ms: 2.1.3 + serialize-javascript: 6.0.2 + strip-json-comments: 3.1.1 + supports-color: 8.1.1 + workerpool: 6.5.1 + yargs: 16.2.0 + yargs-parser: 20.2.9 + yargs-unparser: 2.0.0 + + ms@2.1.3: {} + + no-case@3.0.4: + dependencies: + lower-case: 2.0.2 + tslib: 2.6.2 + + node-fetch@2.7.0: + dependencies: + whatwg-url: 5.0.0 + + node-gyp-build@4.8.1: + optional: true + + normalize-path@3.0.0: {} + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + pako@2.1.0: {} + + path-exists@4.0.0: {} + + pathval@1.1.1: {} + + picomatch@2.3.1: {} + + prettier@2.8.8: {} + + randombytes@2.1.0: + dependencies: + safe-buffer: 5.2.1 + + readdirp@3.6.0: + dependencies: + picomatch: 2.3.1 + + regenerator-runtime@0.14.1: {} + + require-directory@2.1.1: {} + + rpc-websockets@7.11.0: + dependencies: + eventemitter3: 4.0.7 + uuid: 8.3.2 + ws: 8.17.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) + optionalDependencies: + bufferutil: 4.0.8 + utf-8-validate: 5.0.10 + + safe-buffer@5.2.1: {} + + serialize-javascript@6.0.2: + dependencies: + randombytes: 2.1.0 + + snake-case@3.0.4: + dependencies: + dot-case: 3.0.4 + tslib: 2.6.2 + + solana-bankrun-darwin-arm64@0.4.0: + optional: true + + solana-bankrun-darwin-universal@0.4.0: + optional: true + + solana-bankrun-darwin-x64@0.4.0: + optional: true + + solana-bankrun-linux-x64-gnu@0.4.0: + optional: true + + solana-bankrun-linux-x64-musl@0.4.0: + optional: true + + solana-bankrun@0.4.0(bufferutil@4.0.8)(utf-8-validate@5.0.10): + dependencies: + '@solana/web3.js': 1.91.8(bufferutil@4.0.8)(utf-8-validate@5.0.10) + bs58: 4.0.1 + optionalDependencies: + solana-bankrun-darwin-arm64: 0.4.0 + solana-bankrun-darwin-universal: 0.4.0 + solana-bankrun-darwin-x64: 0.4.0 + solana-bankrun-linux-x64-gnu: 0.4.0 + solana-bankrun-linux-x64-musl: 0.4.0 + transitivePeerDependencies: + - bufferutil + - encoding + - utf-8-validate + + source-map-support@0.5.21: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + + source-map@0.6.1: {} + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-bom@3.0.0: + optional: true + + strip-json-comments@3.1.1: {} + + superstruct@0.14.2: {} + + superstruct@0.15.5: {} + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-color@8.1.1: + dependencies: + has-flag: 4.0.0 + + text-encoding-utf-8@1.0.2: {} + + through@2.3.8: {} + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + toml@3.0.0: {} + + tr46@0.0.3: {} + + ts-mocha@10.0.0(mocha@10.8.2): + dependencies: + mocha: 10.8.2 + ts-node: 7.0.1 + optionalDependencies: + tsconfig-paths: 3.15.0 + + ts-node@7.0.1: + dependencies: + arrify: 1.0.1 + buffer-from: 1.1.2 + diff: 3.5.0 + make-error: 1.3.6 + minimist: 1.2.8 + mkdirp: 0.5.6 + source-map-support: 0.5.21 + yn: 2.0.0 + + tsconfig-paths@3.15.0: + dependencies: + '@types/json5': 0.0.29 + json5: 1.0.2 + minimist: 1.2.8 + strip-bom: 3.0.0 + optional: true + + tslib@2.6.2: {} + + type-detect@4.0.8: {} + + typescript@5.6.3: {} + + undici-types@5.26.5: {} + + utf-8-validate@5.0.10: + dependencies: + node-gyp-build: 4.8.1 + optional: true + + uuid@8.3.2: {} + + webidl-conversions@3.0.1: {} + + whatwg-url@5.0.0: + dependencies: + tr46: 0.0.3 + webidl-conversions: 3.0.1 + + workerpool@6.5.1: {} + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrappy@1.0.2: {} + + ws@7.5.9(bufferutil@4.0.8)(utf-8-validate@5.0.10): + optionalDependencies: + bufferutil: 4.0.8 + utf-8-validate: 5.0.10 + + ws@8.17.0(bufferutil@4.0.8)(utf-8-validate@5.0.10): + optionalDependencies: + bufferutil: 4.0.8 + utf-8-validate: 5.0.10 + + y18n@5.0.8: {} + + yargs-parser@20.2.9: {} + + 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@16.2.0: + dependencies: + cliui: 7.0.4 + escalade: 3.1.2 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 20.2.9 + + yn@2.0.0: {} + + yocto-queue@0.1.0: {} diff --git a/tokens/token-2022/transfer-hook/transfer-switch/anchor/programs/transfer-switch/Cargo.toml b/tokens/token-2022/transfer-hook/transfer-switch/anchor/programs/transfer-switch/Cargo.toml new file mode 100644 index 000000000..0ac14914b --- /dev/null +++ b/tokens/token-2022/transfer-hook/transfer-switch/anchor/programs/transfer-switch/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "transfer-switch" +version = "0.1.0" +description = "Created with Anchor" +edition = "2021" + +[lib] +crate-type = ["cdylib", "lib"] +name = "transfer_switch" + +[features] +default = [] +cpi = ["no-entrypoint"] +no-entrypoint = [] +no-idl = [] +no-log-ix-name = [] +idl-build = ["anchor-lang/idl-build", "anchor-spl/idl-build"] + +[dependencies] +anchor-lang = {version="0.30.1", features=["init-if-needed", "interface-instructions"]} +anchor-spl = {version="0.30.1"} +spl-tlv-account-resolution = "0.6.3" +spl-transfer-hook-interface = "0.6.3" \ No newline at end of file diff --git a/tokens/token-2022/transfer-hook/transfer-switch/anchor/programs/transfer-switch/Xargo.toml b/tokens/token-2022/transfer-hook/transfer-switch/anchor/programs/transfer-switch/Xargo.toml new file mode 100644 index 000000000..475fb71ed --- /dev/null +++ b/tokens/token-2022/transfer-hook/transfer-switch/anchor/programs/transfer-switch/Xargo.toml @@ -0,0 +1,2 @@ +[target.bpfel-unknown-unknown.dependencies.std] +features = [] diff --git a/tokens/token-2022/transfer-hook/transfer-switch/anchor/programs/transfer-switch/src/error.rs b/tokens/token-2022/transfer-hook/transfer-switch/anchor/programs/transfer-switch/src/error.rs new file mode 100644 index 000000000..444f8ab1b --- /dev/null +++ b/tokens/token-2022/transfer-hook/transfer-switch/anchor/programs/transfer-switch/src/error.rs @@ -0,0 +1,10 @@ +use anchor_lang::prelude::*; + +#[error_code] +pub enum TransferError { + #[msg("The token is not currently transferring")] + IsNotCurrentlyTransferring, + + #[msg("The transfer switch is currently not on")] + SwitchNotOn, +} diff --git a/tokens/token-2022/transfer-hook/transfer-switch/anchor/programs/transfer-switch/src/instructions/configure_admin.rs b/tokens/token-2022/transfer-hook/transfer-switch/anchor/programs/transfer-switch/src/instructions/configure_admin.rs new file mode 100644 index 000000000..da6873e5c --- /dev/null +++ b/tokens/token-2022/transfer-hook/transfer-switch/anchor/programs/transfer-switch/src/instructions/configure_admin.rs @@ -0,0 +1,49 @@ +use {crate::state::AdminConfig, anchor_lang::prelude::*}; + +#[derive(Accounts)] +pub struct ConfigureAdmin<'info> { + #[account(mut)] + pub admin: Signer<'info>, + + /// CHECK: the new admin + #[account(mut)] + pub new_admin: UncheckedAccount<'info>, + + /// To hold the address of the admin that controls switches + #[account( + init_if_needed, + payer=admin, + space=8+AdminConfig::INIT_SPACE, + seeds=[b"admin-config"], + bump + )] + pub admin_config: Account<'info, AdminConfig>, + + pub system_program: Program<'info, System>, +} + +impl<'info> ConfigureAdmin<'info> { + pub fn is_admin(&self) -> Result<()> { + // check if we are not creating the account for the first time, + // ensure it's the admin that is making the change + // + if self.admin_config.is_initialised { + // make sure it's the admin + // + require_keys_eq!(self.admin.key(), self.admin_config.admin,); + + // make sure the admin is not reentering their key + // + require_keys_neq!(self.admin.key(), self.new_admin.key()); + } + Ok(()) + } + + pub fn configure_admin(&mut self) -> Result<()> { + self.admin_config.set_inner(AdminConfig { + admin: self.new_admin.key(), // set the admin pubkey that can switch transfers on/off + is_initialised: true, // let us know an admin has been set + }); + Ok(()) + } +} diff --git a/tokens/token-2022/transfer-hook/transfer-switch/anchor/programs/transfer-switch/src/instructions/initialise_extra_account_metas_list.rs b/tokens/token-2022/transfer-hook/transfer-switch/anchor/programs/transfer-switch/src/instructions/initialise_extra_account_metas_list.rs new file mode 100644 index 000000000..c4a20f139 --- /dev/null +++ b/tokens/token-2022/transfer-hook/transfer-switch/anchor/programs/transfer-switch/src/instructions/initialise_extra_account_metas_list.rs @@ -0,0 +1,83 @@ +use { + anchor_lang::{ + prelude::*, + system_program::{create_account, CreateAccount}, + }, + anchor_spl::token_interface::Mint, + spl_tlv_account_resolution::{ + account::ExtraAccountMeta, seeds::Seed, state::ExtraAccountMetaList, + }, + spl_transfer_hook_interface::instruction::ExecuteInstruction, +}; + +#[derive(Accounts)] +pub struct InitializeExtraAccountMetas<'info> { + #[account(mut)] + pub payer: Signer<'info>, + + #[account()] + pub token_mint: InterfaceAccount<'info, Mint>, + + /// CHECK: extra accoumt metas list + #[account( + mut, + seeds = [b"extra-account-metas", token_mint.key().as_ref()], + bump, + )] + pub extra_account_metas_list: UncheckedAccount<'info>, + + pub system_program: Program<'info, System>, +} + +impl<'info> InitializeExtraAccountMetas<'info> { + pub fn initialize_extra_account_metas_list( + &self, + bumps: InitializeExtraAccountMetasBumps, + ) -> Result<()> { + let account_metas = vec![ + // 5 - wallet (sender) config account + ExtraAccountMeta::new_with_seeds( + &[ + Seed::AccountKey { index: 3 }, // sender index + ], + false, // is_signer + false, // is_writable + )?, + ]; + + // calculate account size + let account_size = ExtraAccountMetaList::size_of(account_metas.len())? as u64; + + // calculate minimum required lamports + let lamports = Rent::get()?.minimum_balance(account_size as usize); + + let mint = self.token_mint.key(); + let signer_seeds: &[&[&[u8]]] = &[&[ + b"extra-account-metas", + mint.as_ref(), + &[bumps.extra_account_metas_list], + ]]; + + create_account( + CpiContext::new( + self.system_program.to_account_info(), + CreateAccount { + from: self.payer.to_account_info(), + to: self.extra_account_metas_list.to_account_info(), + }, + ) + .with_signer(signer_seeds), + lamports, + account_size, + &crate::ID, + )?; + + // Initialize the account data to store the list of ExtraAccountMetas + ExtraAccountMetaList::init::( + &mut self.extra_account_metas_list.try_borrow_mut_data()?, + &account_metas, + )?; + + Ok(()) + } +} diff --git a/tokens/token-2022/transfer-hook/transfer-switch/anchor/programs/transfer-switch/src/instructions/mod.rs b/tokens/token-2022/transfer-hook/transfer-switch/anchor/programs/transfer-switch/src/instructions/mod.rs new file mode 100644 index 000000000..39a3f9363 --- /dev/null +++ b/tokens/token-2022/transfer-hook/transfer-switch/anchor/programs/transfer-switch/src/instructions/mod.rs @@ -0,0 +1,9 @@ +pub mod configure_admin; +pub mod initialise_extra_account_metas_list; +pub mod switch; +pub mod transfer_hook; + +pub use configure_admin::*; +pub use initialise_extra_account_metas_list::*; +pub use switch::*; +pub use transfer_hook::*; diff --git a/tokens/token-2022/transfer-hook/transfer-switch/anchor/programs/transfer-switch/src/instructions/switch.rs b/tokens/token-2022/transfer-hook/transfer-switch/anchor/programs/transfer-switch/src/instructions/switch.rs new file mode 100644 index 000000000..ad264e70e --- /dev/null +++ b/tokens/token-2022/transfer-hook/transfer-switch/anchor/programs/transfer-switch/src/instructions/switch.rs @@ -0,0 +1,48 @@ +use { + crate::state::{AdminConfig, TransferSwitch}, + anchor_lang::prelude::*, +}; + +#[derive(Accounts)] +#[instruction(decimals: u8)] +pub struct Switch<'info> { + /// admin that controls the switch + #[account(mut)] + pub admin: Signer<'info>, + + /// CHECK: wallet - transfer sender + #[account(mut)] + pub wallet: UncheckedAccount<'info>, + + /// admin config + #[account( + has_one=admin, + seeds=[b"admin-config"], + bump, + )] + pub admin_config: Account<'info, AdminConfig>, + + /// the wallet (sender) transfer switch + #[account( + init_if_needed, + payer=admin, + space=8+TransferSwitch::INIT_SPACE, + seeds=[wallet.key().as_ref()], + bump, + )] + pub wallet_switch: Account<'info, TransferSwitch>, + + pub system_program: Program<'info, System>, +} + +impl<'info> Switch<'info> { + pub fn switch(&mut self, on: bool) -> Result<()> { + // toggle switch on/off for the given wallet + // + self.wallet_switch.set_inner(TransferSwitch { + wallet: self.wallet.key(), + on, + }); + Ok(()) + } +} diff --git a/tokens/token-2022/transfer-hook/transfer-switch/anchor/programs/transfer-switch/src/instructions/transfer_hook.rs b/tokens/token-2022/transfer-hook/transfer-switch/anchor/programs/transfer-switch/src/instructions/transfer_hook.rs new file mode 100644 index 000000000..c79e9cbb7 --- /dev/null +++ b/tokens/token-2022/transfer-hook/transfer-switch/anchor/programs/transfer-switch/src/instructions/transfer_hook.rs @@ -0,0 +1,70 @@ +use { + crate::{error::TransferError, state::TransferSwitch}, + anchor_lang::prelude::*, + anchor_spl::{ + token_2022::spl_token_2022::{ + extension::{ + transfer_hook::TransferHookAccount, BaseStateWithExtensionsMut, + PodStateWithExtensionsMut, + }, + pod::PodAccount, + }, + token_interface::Mint, + }, +}; + +#[derive(Accounts)] +#[instruction(decimals: u8)] +pub struct TransferHook<'info> { + /// CHECK: Sender token account + #[account()] + pub source_token_account: UncheckedAccount<'info>, + + /// The mint of the token transferring + #[account()] + pub token_mint: InterfaceAccount<'info, Mint>, + + /// CHECK: Recipient token account + #[account()] + pub receiver_token_account: UncheckedAccount<'info>, + + /// CHECK: the transfer sender + #[account()] + pub wallet: UncheckedAccount<'info>, + + /// CHECK: extra account metas + #[account( + seeds = [b"extra-account-metas", token_mint.key().as_ref()], + bump, + )] + pub extra_account_metas_list: UncheckedAccount<'info>, + + /// sender transfer switch + #[account( + seeds=[wallet.key().as_ref()], + bump, + )] + pub wallet_switch: Account<'info, TransferSwitch>, +} + +impl<'info> TransferHook<'info> { + pub fn assert_switch_is_on(&mut self) -> Result<()> { + if !self.wallet_switch.on { + return err!(TransferError::SwitchNotOn); + } + Ok(()) + } + + pub fn assert_is_transferring(&self) -> Result<()> { + let source_token_info = self.source_token_account.to_account_info(); + let mut account_data_ref = source_token_info.try_borrow_mut_data()?; + let mut account = PodStateWithExtensionsMut::::unpack(*account_data_ref)?; + let account_extension = account.get_extension_mut::()?; + + if !bool::from(account_extension.transferring) { + return err!(TransferError::IsNotCurrentlyTransferring); + } + + Ok(()) + } +} diff --git a/tokens/token-2022/transfer-hook/transfer-switch/anchor/programs/transfer-switch/src/lib.rs b/tokens/token-2022/transfer-hook/transfer-switch/anchor/programs/transfer-switch/src/lib.rs new file mode 100644 index 000000000..efaf216da --- /dev/null +++ b/tokens/token-2022/transfer-hook/transfer-switch/anchor/programs/transfer-switch/src/lib.rs @@ -0,0 +1,35 @@ +mod error; +mod instructions; +mod state; + +use anchor_lang::prelude::*; +use instructions::*; + +declare_id!("FjcHckEgXcBhFmSGai3FRpDLiT6hbpV893n8iTxVd81g"); + +#[program] +pub mod transfer_switch { + use super::*; + + pub fn configure_admin(ctx: Context) -> Result<()> { + ctx.accounts.is_admin()?; + ctx.accounts.configure_admin() + } + + #[interface(spl_transfer_hook_interface::initialize_extra_account_meta_list)] + pub fn initialize_extra_account_metas_list( + ctx: Context, + ) -> Result<()> { + ctx.accounts.initialize_extra_account_metas_list(ctx.bumps) + } + + pub fn switch(ctx: Context, on: bool) -> Result<()> { + ctx.accounts.switch(on) + } + + #[interface(spl_transfer_hook_interface::execute)] + pub fn transfer_hook(ctx: Context) -> Result<()> { + ctx.accounts.assert_is_transferring()?; + ctx.accounts.assert_switch_is_on() + } +} diff --git a/tokens/token-2022/transfer-hook/transfer-switch/anchor/programs/transfer-switch/src/state.rs b/tokens/token-2022/transfer-hook/transfer-switch/anchor/programs/transfer-switch/src/state.rs new file mode 100644 index 000000000..8130c7118 --- /dev/null +++ b/tokens/token-2022/transfer-hook/transfer-switch/anchor/programs/transfer-switch/src/state.rs @@ -0,0 +1,15 @@ +use anchor_lang::prelude::*; + +#[account] +#[derive(InitSpace)] +pub struct TransferSwitch { + pub wallet: Pubkey, + pub on: bool, +} + +#[account] +#[derive(InitSpace)] +pub struct AdminConfig { + pub is_initialised: bool, + pub admin: Pubkey, +} diff --git a/tokens/token-2022/transfer-hook/transfer-switch/anchor/tests/transfer-switch.ts b/tokens/token-2022/transfer-hook/transfer-switch/anchor/tests/transfer-switch.ts new file mode 100644 index 000000000..9db80fd77 --- /dev/null +++ b/tokens/token-2022/transfer-hook/transfer-switch/anchor/tests/transfer-switch.ts @@ -0,0 +1,268 @@ +import { describe, it } from 'node:test'; +import * as anchor from '@coral-xyz/anchor'; +import { + ASSOCIATED_TOKEN_PROGRAM_ID, + AccountLayout, + ExtensionType, + TOKEN_2022_PROGRAM_ID, + createAssociatedTokenAccountInstruction, + createInitializeMintInstruction, + createInitializeTransferHookInstruction, + createMintToInstruction, + createTransferCheckedWithTransferHookInstruction, + getAssociatedTokenAddressSync, + getMintLen, +} from '@solana/spl-token'; +import { PublicKey } from '@solana/web3.js'; +import { Keypair, SystemProgram } from '@solana/web3.js'; +import { Transaction } from '@solana/web3.js'; +import { TransactionInstruction } from '@solana/web3.js'; +import { BankrunProvider } from 'anchor-bankrun'; +import { assert } from 'chai'; +import { startAnchor } from 'solana-bankrun'; +import type { TransferSwitch } from '../target/types/transfer_switch'; + +const IDL = require('../target/idl/transfer_switch.json'); +const PROGRAM_ID = new PublicKey(IDL.address); + +const expectRevert = async (promise: Promise) => { + try { + await promise; + throw new Error('Expected a revert'); + } catch { + return; + } +}; + +describe('Transfer switch', async () => { + const context = await startAnchor('', [{ name: 'transfer_switch', programId: PROGRAM_ID }], []); + const provider = new BankrunProvider(context); + + const wallet = provider.wallet as anchor.Wallet; + const program = new anchor.Program(IDL, provider); + const connection = provider.connection; + + const payer = provider.context.payer; + const client = provider.context.banksClient; + + // Generate keypair to use as address for the transfer-hook enabled mint + const mint = Keypair.generate(); + const decimals = 9; + + function newUser(): [Keypair, PublicKey, TransactionInstruction] { + const user = Keypair.generate(); + const userTokenAccount = getAssociatedTokenAddressSync(mint.publicKey, user.publicKey, false, TOKEN_2022_PROGRAM_ID); + const createUserTokenAccountIx = createAssociatedTokenAccountInstruction( + payer.publicKey, + userTokenAccount, + user.publicKey, + mint.publicKey, + TOKEN_2022_PROGRAM_ID, + ASSOCIATED_TOKEN_PROGRAM_ID, + ); + + return [user, userTokenAccount, createUserTokenAccountIx]; + } + + // admin config address + const adminConfigAddress = PublicKey.findProgramAddressSync([Buffer.from('admin-config')], PROGRAM_ID)[0]; + + // helper for getting wallet switch + const walletTransferSwitchAddress = (wallet: PublicKey) => PublicKey.findProgramAddressSync([wallet.toBuffer()], PROGRAM_ID)[0]; + + // sender + const [sender, senderTokenAccount, senderTokenAccountCreateIx] = newUser(); + + it('Create Mint Account with Transfer Hook Extension', async () => { + const extensions = [ExtensionType.TransferHook]; + const mintLen = getMintLen(extensions); + const lamports = await provider.connection.getMinimumBalanceForRentExemption(mintLen); + + const transaction = new Transaction().add( + SystemProgram.createAccount({ + fromPubkey: payer.publicKey, + newAccountPubkey: mint.publicKey, + space: mintLen, + lamports: lamports, + programId: TOKEN_2022_PROGRAM_ID, + }), + createInitializeTransferHookInstruction( + mint.publicKey, + payer.publicKey, + program.programId, // Transfer Hook Program ID + TOKEN_2022_PROGRAM_ID, + ), + createInitializeMintInstruction(mint.publicKey, decimals, payer.publicKey, null, TOKEN_2022_PROGRAM_ID), + ); + + transaction.recentBlockhash = context.lastBlockhash; + transaction.sign(payer, mint); + + await client.processTransaction(transaction); + }); + + // Create the two token accounts for the transfer-hook enabled mint + // Fund the sender token account with 100 tokens + it('Create Token Accounts and Mint Tokens', async () => { + // 100 tokens + const amount = 100 * 10 ** decimals; + + const transaction = new Transaction().add( + senderTokenAccountCreateIx, // create sender token account + createMintToInstruction(mint.publicKey, senderTokenAccount, payer.publicKey, amount, [], TOKEN_2022_PROGRAM_ID), + ); + + transaction.recentBlockhash = context.lastBlockhash; + transaction.sign(payer); + + await client.processTransaction(transaction); + }); + + // Account to store extra accounts required by the transfer hook instruction + // This will be called for every mint + // + it('Create ExtraAccountMetaList Account', async () => { + await program.methods + .initializeExtraAccountMetasList() + .accounts({ + payer: payer.publicKey, + tokenMint: mint.publicKey, + }) + .signers([payer]) + .rpc(); + }); + + // Set the account that controls the switches for the wallet + it('Configure an admin', async () => { + await program.methods + .configureAdmin() + .accounts({ + admin: payer.publicKey, + newAdmin: payer.publicKey, + }) + .signers([payer]) + .rpc(); + + const adminConfig = await program.account.adminConfig.fetch(adminConfigAddress); + assert(adminConfig.isInitialised === true, 'admin config not initialised'); + assert(adminConfig.admin.toBase58() === payer.publicKey.toBase58(), 'admin does not match'); + }); + + // Account to store extra accounts required by the transfer hook instruction + it('turn transfers off for sender', async () => { + await program.methods + .switch(false) + .accountsPartial({ + wallet: sender.publicKey, + admin: payer.publicKey, + }) + .signers([payer]) + .rpc(); + + const walletSwitch = await program.account.transferSwitch.fetch(walletTransferSwitchAddress(sender.publicKey)); + + assert(walletSwitch.wallet.toBase58() === sender.publicKey.toBase58(), 'wallet key does not match'); + assert(!walletSwitch.on, 'wallet switch not set to false'); + }); + + it('Try transfer, should fail!', async () => { + // 1 tokens + const amount = 1 * 10 ** decimals; + const bigIntAmount = BigInt(amount); + + const [recipient, recipientTokenAccount, recipientTokenAccountCreateIx] = newUser(); + + // create the recipient token account ahead of the transfer, + // + let transaction = new Transaction().add( + recipientTokenAccountCreateIx, // create recipient token account + ); + + transaction.recentBlockhash = context.lastBlockhash; + transaction.sign(payer, recipient); + + client.processTransaction(transaction); + + // Standard token transfer instruction + const transferInstruction = await createTransferCheckedWithTransferHookInstruction( + connection, + senderTokenAccount, + mint.publicKey, + recipientTokenAccount, + sender.publicKey, + bigIntAmount, + decimals, + [], + 'confirmed', + TOKEN_2022_PROGRAM_ID, + ); + + transaction = new Transaction().add( + transferInstruction, // transfer instruction + ); + + transaction.recentBlockhash = context.lastBlockhash; + transaction.sign(payer, sender); + + // expect the transaction to fail + // + expectRevert(client.processTransaction(transaction)); + + const recipientTokenAccountData = (await client.getAccount(recipientTokenAccount)).data; + const recipientBalance = AccountLayout.decode(recipientTokenAccountData).amount; + + assert(recipientBalance === BigInt(0), 'transfer was successful'); + }); + + // Account to store extra accounts required by the transfer hook instruction + it('turn on for sender!', async () => { + await program.methods + .switch(true) + .accountsPartial({ + wallet: sender.publicKey, + admin: payer.publicKey, + }) + .signers([payer]) + .rpc(); + + const walletSwitch = await program.account.transferSwitch.fetch(walletTransferSwitchAddress(sender.publicKey)); + + assert(walletSwitch.wallet.toBase58() === sender.publicKey.toBase58(), 'wallet key does not match'); + assert(walletSwitch.on, 'wallet switch not set to true'); + }); + + it('Send successfully', async () => { + // 1 tokens + const amount = 1 * 10 ** decimals; + const bigIntAmount = BigInt(amount); + + const [recipient, recipientTokenAccount, recipientTokenAccountCreateIx] = newUser(); + + // Standard token transfer instruction + const transferInstruction = await createTransferCheckedWithTransferHookInstruction( + connection, + senderTokenAccount, + mint.publicKey, + recipientTokenAccount, + sender.publicKey, + bigIntAmount, + decimals, + [], + 'confirmed', + TOKEN_2022_PROGRAM_ID, + ); + + const transaction = new Transaction().add(recipientTokenAccountCreateIx, transferInstruction); + + transaction.recentBlockhash = context.lastBlockhash; + transaction.sign(payer, sender); + + await client.processTransaction(transaction); + + const recipientTokenAccountData = (await client.getAccount(recipientTokenAccount)).data; + + const recipientBalance = AccountLayout.decode(recipientTokenAccountData).amount; + + assert(recipientBalance === bigIntAmount, 'transfer was not successful'); + }); +}); diff --git a/tokens/token-2022/transfer-hook/transfer-switch/anchor/tsconfig.json b/tokens/token-2022/transfer-hook/transfer-switch/anchor/tsconfig.json new file mode 100644 index 000000000..cd5d2e3d0 --- /dev/null +++ b/tokens/token-2022/transfer-hook/transfer-switch/anchor/tsconfig.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "types": ["mocha", "chai"], + "typeRoots": ["./node_modules/@types"], + "lib": ["es2015"], + "module": "commonjs", + "target": "es6", + "esModuleInterop": true + } +}