From 09c4c7031146b2871fe8b3607f9210f77e7851e1 Mon Sep 17 00:00:00 2001 From: Noah Prince <83885631+ChewingGlass@users.noreply.github.com> Date: Thu, 22 Feb 2024 14:48:53 -0600 Subject: [PATCH] feat(#644): Add helium/sus package to preview transactions --- .github/workflows/tests.yaml | 1 + packages/sus/.gitignore | 4 + packages/sus/README.md | 462 ++++ packages/sus/package.json | 48 + packages/sus/src/index.ts | 997 +++++++++ packages/sus/tsconfig.cjs.json | 7 + packages/sus/tsconfig.esm.json | 8 + packages/sus/tsconfig.json | 11 + packages/sus/yarn.deploy.lock | 1973 +++++++++++++++++ .../instructions/initialize_position_v0.rs | 1 - tests/sus.ts | 430 ++++ tsconfig.json | 9 +- yarn.lock | 38 + 13 files changed, 3986 insertions(+), 3 deletions(-) create mode 100644 packages/sus/.gitignore create mode 100644 packages/sus/README.md create mode 100644 packages/sus/package.json create mode 100644 packages/sus/src/index.ts create mode 100644 packages/sus/tsconfig.cjs.json create mode 100644 packages/sus/tsconfig.esm.json create mode 100644 packages/sus/tsconfig.json create mode 100644 packages/sus/yarn.deploy.lock create mode 100644 tests/sus.ts diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 52eaa4432..84bfdfb90 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -148,6 +148,7 @@ jobs: - tests/price-oracle.ts - tests/voter-stake-registry.ts - tests/fanout.ts + - tests/sus.ts steps: - uses: actions/checkout@v3 - uses: ./.github/actions/build-anchor/ diff --git a/packages/sus/.gitignore b/packages/sus/.gitignore new file mode 100644 index 000000000..445f244bc --- /dev/null +++ b/packages/sus/.gitignore @@ -0,0 +1,4 @@ +npm-debug.log +dist/ +tmp/ +./node_modules \ No newline at end of file diff --git a/packages/sus/README.md b/packages/sus/README.md new file mode 100644 index 000000000..f5f4e06d5 --- /dev/null +++ b/packages/sus/README.md @@ -0,0 +1,462 @@ +# Sus + +Ever wonder if a given transaction in Sus? Have difficulty parsing the cryptic return of a transaction simulation? This repo is for you! + +Solana transactions are notoriously hard to parse, but it is extremely important that users understand what they are approving. This library is an attempt to bridge that gap as best we can. + +Features: + + * List human-readable forms of writable accounts + * Parse all anchor instructions and accounts on programs with published IDLs + * Create warnings around suspicious activity + * Human-readable balance changes with token tickers + * Detect balance changes on cNFTs + * Explorer link to simulated transaction + * Parse out base and priority fees + * Flag writable accounts that did not change in simulation + * Batch as many fetches as possible into getMultipleAccounts to reduce load on RPC + +## Usage + +```javascript +import { sus } from "@helium/sus" + +const result = await sus({ + connection, + wallet, + serializedTransactions: [transaction.serialize({ + verifySignatures: false, + requireAllSignatures: false, + })], + // Check for cNFT changes, this only works if you have an RPC with DAS support + checkCNfts: true, + // Necessary for explorer link + cluster: "devnet" +}) +console.log(result) +``` + +## Human-readable Writable Accounts (and changes) + +On Solana, every transaciton must declare which accounts can be changed over the course of a transaction. This is an important way to detect bad behavior. If a transaction is meant to swap SOL for HNT and it labels your USDC account as writable, this is a problem! + +Transaction simulation is not a silver bullet, it can be tricked. We cannot rely on simulated balance changes to reflect what _can_ happen in a transaction. As such, we should flag which important accounts are at risk. + +This feature also allows us to show a detailed diff on fields that change on anchor accounts. For example, we may see a helium `IotHotspotInfoV0.location` changed from one value to another in simulation. + +```javascript +const result = await sus({ + connection, + wallet, + serializedTransactions: [transaction.serialize({ + verifySignatures: false, + requireAllSignatures: false, + })], + // Check for cNFT changes, this only works if you have an RPC with DAS support + checkCNfts: true, + // Necessary for explorer link + cluster: "devnet" +}) +console.log(result[0].writableAccounts) +``` + +Consider a transaction that mints helium data credits by burning HNT. This will return something like this. Note the owner field is best-effort but allows a UI to display which accounts may be owned by the user.: + +```javascript +[ + { + address: sustWW3deA7acADNGJnkYj2EAf65EmqUNLxKekDpu6w, + name: 'Native SOL Account', + owner: sustWW3deA7acADNGJnkYj2EAf65EmqUNLxKekDpu6w + pre: { type: 'NativeAccount', account: [Object], parsed: null }, + post: { type: 'NativeAccount', account: [Object], parsed: null }, + changedInSimulation: true, + metadata: undefined + }, + { + address: 7KjyaNK3qRAsA4WHGzyJGDJQAJKeQmnujKbPmP3sVpzT, + name: 'DelegatedDataCreditsV0', + owner: undefined, + pre: { + type: 'DelegatedDataCreditsV0', + account: null, + parsed: undefined + }, + post: { + type: 'DelegatedDataCreditsV0', + account: [Object], + parsed: [Object] + }, + changedInSimulation: true, + metadata: undefined + }, + { + address: dcuc8Amr83Wz27ZkQ2K9NS6r8zRpf1J6cvArEBDZDmm, + name: 'DC Mint', + owner: undefined, + pre: { type: 'Mint', account: [Object], parsed: [Object] }, + post: { type: 'Mint', account: [Object], parsed: [Object] }, + changedInSimulation: true, + metadata: { + name: 'Helium Data Credit', + symbol: 'DC', + uri: 'https://shdw-drive.genesysgo.net/CsDkETHRRR1EcueeN346MJoqzymkkr7RFjMqGpZMzAib/dc.json', + decimals: 0, + mint: dcuc8Amr83Wz27ZkQ2K9NS6r8zRpf1J6cvArEBDZDmm + } + }, + { + address: EP1jYSgzfaMWr8z4gceoEdh3agfTyV2wL8Br1dHhzRVC,, + name: 'DC Token Account', + owner: sustWW3deA7acADNGJnkYj2EAf65EmqUNLxKekDpu6w, + pre: { type: 'TokenAccount', account: null, parsed: undefined }, + post: { type: 'TokenAccount', account: [Object], parsed: [Object] }, + changedInSimulation: true, + metadata: { + name: 'Helium Data Credit', + symbol: 'DC', + uri: 'https://shdw-drive.genesysgo.net/CsDkETHRRR1EcueeN346MJoqzymkkr7RFjMqGpZMzAib/dc.json', + decimals: 0, + mint: dcuc8Amr83Wz27ZkQ2K9NS6r8zRpf1J6cvArEBDZDmm + } + }, + { + address: FzLQKNNe67QgPJnUJyZ2zrNBqmjYaBYgoaYh69Yitn8Q. + name: 'HNT Token Account', + owner: sustWW3deA7acADNGJnkYj2EAf65EmqUNLxKekDpu6w, + pre: { type: 'TokenAccount', account: [Object], parsed: [Object] }, + post: { type: 'TokenAccount', account: [Object], parsed: [Object] }, + changedInSimulation: true, + metadata: { + name: 'Helium Network Token', + symbol: 'HNT', + uri: 'https://shdw-drive.genesysgo.net/CsDkETHRRR1EcueeN346MJoqzymkkr7RFjMqGpZMzAib/hnt.json', + decimals: 8, + mint: hntyVP6YFm1Hg25TN9WGLqM12b8TQmcknKrdu1oxWux + } + }, + { + address: hntyVP6YFm1Hg25TN9WGLqM12b8TQmcknKrdu1oxWux, + name: 'HNT Mint', + owner: undefined, + pre: { type: 'Mint', account: [Object], parsed: [Object] }, + post: { type: 'Mint', account: [Object], parsed: [Object] }, + changedInSimulation: true, + metadata: { + name: 'Helium Network Token', + symbol: 'HNT', + uri: 'https://shdw-drive.genesysgo.net/CsDkETHRRR1EcueeN346MJoqzymkkr7RFjMqGpZMzAib/hnt.json', + decimals: 8, + mint: [PublicKey [PublicKey(hntyVP6YFm1Hg25TN9WGLqM12b8TQmcknKrdu1oxWux)]] + } + }, + { + address: kM5w7CoX6NNZZuV3D17FUfjktMQ8tsU542giQx214QB, + name: 'DC Token Account', + owner: 7KjyaNK3qRAsA4WHGzyJGDJQAJKeQmnujKbPmP3sVpzT, + pre: { type: 'TokenAccount', account: null, parsed: undefined }, + post: { type: 'TokenAccount', account: [Object], parsed: [Object] }, + changedInSimulation: true, + metadata: { + name: 'Helium Data Credit', + symbol: 'DC', + uri: 'https://shdw-drive.genesysgo.net/CsDkETHRRR1EcueeN346MJoqzymkkr7RFjMqGpZMzAib/dc.json', + decimals: 0, + mint: [PublicKey [PublicKey(dcuc8Amr83Wz27ZkQ2K9NS6r8zRpf1J6cvArEBDZDmm)]] + } + }, + { + address: sZgXQVqAv9atfSuwNJnHgSf4tqsos6kRajANmBaBmSx, + name: 'MintWindowedCircuitBreakerV0', + owner: undefined, + pre: { + type: 'MintWindowedCircuitBreakerV0', + account: [Object], + parsed: [Object] + }, + post: { + type: 'MintWindowedCircuitBreakerV0', + account: [Object], + parsed: [Object] + }, + changedInSimulation: true, + metadata: undefined + } +] +``` + +The `parsed` field in the pre-transaction and post-transaction changes will contain the anchor deserialized accounts as an object. + +## Parsed Anchor instructions + +An important part of understanding what a transaction does is seeing a human-readable form of what actions are being taken and their argument. + +Sus attempts to parse the instructions of any program with an anchor-compliant IDL. This allows you to display the actions, their arguments, and the accounts being used: + + +```javascript +const result = await sus({ + connection, + wallet, + serializedTransaction: [transaction.serialize({ + verifySignatures: false, + requireAllSignatures: false, + })], + // Check for cNFT changes, this only works if you have an RPC with DAS support + checkCNfts: true, + // Necessary for explorer link + cluster: "devnet" +}) +console.log(result[0].instructions) +``` + +Parsing results in the following data: + +```javascript +[ + { + parsed: { + name: 'mintDataCreditsV0', + data: { args: { hntAmount: null, dcAmount: } }, + accounts: [ + { + name: 'Data Credits', + pubkey: [PublicKey [PublicKey(D1LbvrJQ9K2WbGPMbM3Fnrf5PSsDH1TDpjqJdHuvs81n)]], + isSigner: false, + isWritable: false + }, + { + name: 'Hnt Price Oracle', + pubkey: [PublicKey [PublicKey(6Eg8YdfFJQF2HHonzPUBSCCmyUEhrStg9VBLK957sBe6)]], + isSigner: false, + isWritable: false + }, + { + name: 'Burner', + pubkey: [PublicKey [PublicKey(FzLQKNNe67QgPJnUJyZ2zrNBqmjYaBYgoaYh69Yitn8Q)]], + isSigner: false, + isWritable: true + }, + { + name: 'Recipient Token Account', + pubkey: [PublicKey [PublicKey(EP1jYSgzfaMWr8z4gceoEdh3agfTyV2wL8Br1dHhzRVC)]], + isSigner: false, + isWritable: true + }, + { + name: 'Recipient', + pubkey: [PublicKey [PublicKey(sustWW3deA7acADNGJnkYj2EAf65EmqUNLxKekDpu6w)]], + isSigner: true, + isWritable: true + }, + { + name: 'Owner', + pubkey: [PublicKey [PublicKey(sustWW3deA7acADNGJnkYj2EAf65EmqUNLxKekDpu6w)]], + isSigner: true, + isWritable: true + }, + { + name: 'Hnt Mint', + pubkey: [PublicKey [PublicKey(hntyVP6YFm1Hg25TN9WGLqM12b8TQmcknKrdu1oxWux)]], + isSigner: false, + isWritable: true + }, + { + name: 'Dc Mint', + pubkey: [PublicKey [PublicKey(dcuc8Amr83Wz27ZkQ2K9NS6r8zRpf1J6cvArEBDZDmm)]], + isSigner: false, + isWritable: true + }, + { + name: 'Circuit Breaker', + pubkey: [PublicKey [PublicKey(sZgXQVqAv9atfSuwNJnHgSf4tqsos6kRajANmBaBmSx)]], + isSigner: false, + isWritable: true + }, + { + name: 'Circuit Breaker Program', + pubkey: [PublicKey [PublicKey(circAbx64bbsscPbQzZAUvuXpHqrCe6fLMzc2uKXz9g)]], + isSigner: false, + isWritable: false + }, + { + name: 'Token Program', + pubkey: [PublicKey [PublicKey(TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA)]], + isSigner: false, + isWritable: false + }, + { + name: 'System Program', + pubkey: [PublicKey [PublicKey(11111111111111111111111111111111)]], + isSigner: false, + isWritable: false + }, + { + name: 'Associated Token Program', + pubkey: [PublicKey [PublicKey(ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL)]], + isSigner: false, + isWritable: false + } + ] + }, + raw: { + data: , + programId: credMBJhYFzfn7NxBMdU4aUqFggAjgztaCcv2Fo6fPT, + accounts: [Array] + } + }, + { + parsed: { + name: 'delegateDataCreditsV0', + data: [Object], + accounts: [Array] + }, + raw: { + data: , + programId: [PublicKey [PublicKey(credMBJhYFzfn7NxBMdU4aUqFggAjgztaCcv2Fo6fPT)]], + accounts: [Array] + } + } +] +``` + +## Warnings + +Sus attempts to warn for various suspicious transactions. One example is a transaction that sets more than 2 token accounts to writable. A normal swap involves two accounts, so 6 token accounts being writable may be perceived as a rug: + +```javascript +const result = await sus({ + connection, + wallet, + serializedTransaction: [transaction.serialize({ + verifySignatures: false, + requireAllSignatures: false, + })], + // Check for cNFT changes, this only works if you have an RPC with DAS support + checkCNfts: true, + // Necessary for explorer link + cluster: "devnet" +}) +console.log(result[0].warnings) +``` + +```javascript +[ + { + severity: 'warning', + message: "More than 2 accounts with negative balance change. Is this emptying your wallet?", + shortMessage: '2+ Writable' + } +] +``` + +## Human-readable balance changes with token tickers + +Balance changes need to be paired with token symbols/tickers to create useful human-redable changes. + +```javascript +import { sus } from "@helium/sus" + +const result = await sus({ + connection, + wallet, + serializedTransaction: [transaction.serialize({ + verifySignatures: false, + requireAllSignatures: false, + })], + // Check for cNFT changes, this only works if you have an RPC with DAS support + checkCNfts: true, + // Necessary for explorer link + cluster: "devnet" +}) +console.log(result[0].balanceChanges) +``` + +```javascript +[ + { + owner: PublicKey [PublicKey(sustWW3deA7acADNGJnkYj2EAf65EmqUNLxKekDpu6w)] { + _bn: + }, + address: PublicKey [PublicKey(sustWW3deA7acADNGJnkYj2EAf65EmqUNLxKekDpu6w)] { + _bn: + }, + amount: -2044280n, + metadata: { + mint: [PublicKey [PublicKey(So11111111111111111111111111111111111111112)]], + decimals: 9, + name: 'SOL', + symbol: 'SOL' + } + }, + { + owner: PublicKey [PublicKey(11111111111111111111111111111111)] { + _bn: + }, + address: PublicKey [PublicKey(5pcFdhUfokbCKuQv8id7GV1ZFGWLt2vBEDGX76QxkpxW)] { + _bn: + }, + amount: 1000000000n, + metadata: { + name: 'Helium Network Token', + symbol: 'HNT', + uri: 'https://shdw-drive.genesysgo.net/CsDkETHRRR1EcueeN346MJoqzymkkr7RFjMqGpZMzAib/hnt.json', + decimals: 8, + mint: [PublicKey [PublicKey(hntyVP6YFm1Hg25TN9WGLqM12b8TQmcknKrdu1oxWux)]] + } + }, + { + owner: PublicKey [PublicKey(sustWW3deA7acADNGJnkYj2EAf65EmqUNLxKekDpu6w)] { + _bn: + }, + address: PublicKey [PublicKey(FzLQKNNe67QgPJnUJyZ2zrNBqmjYaBYgoaYh69Yitn8Q)] { + _bn: + }, + amount: -1000000000n, + metadata: { + name: 'Helium Network Token', + symbol: 'HNT', + uri: 'https://shdw-drive.genesysgo.net/CsDkETHRRR1EcueeN346MJoqzymkkr7RFjMqGpZMzAib/hnt.json', + decimals: 8, + mint: [PublicKey [PublicKey(hntyVP6YFm1Hg25TN9WGLqM12b8TQmcknKrdu1oxWux)]] + } + } +] +``` + +## Possible cNFT Balance Changes + +Traditional transaction simulation shows the changes in balance of typical token accounts. This is, unfortunately, not directly possible with cNFTs. However, we can make a best effort by observing which assets in a wallet belong to a merkle tree that is labeled as writable. This allows us to flag that a cNFT _might_ be transferred, burned, or updated. + +To use this feature, you must either (a) use an RPC with DAS support or pass the `cNfts` arg with an array of cNFTs already in the wallet. You must also enable the `checkCNfts` param. + +```javascript +import { sus } from "@helium/sus" + +const result = await sus({ + connection, + wallet, + serializedTransaction: [transaction.serialize({ + verifySignatures: false, + requireAllSignatures: false, + })], + // Check for cNFT changes, this only works if you have an RPC with DAS support + checkCNfts: true, + // Necessary for explorer link + cluster: "devnet" +}) +console.log(result[0].possibleCNftChanges) +``` + +Unfortunately, this method is limited by how much data can be fetched from DAS. If a user has more than 200 hotspots, for example, Sus will not be able to check all hotspots past that limit for matches to a mutable tree in the transaction. + +`possibleCNftChanges` will contain a list of DAS assets that could be changed in this tx. + +## Explorer Link + +It is sometimes useful to inspect a simulated transaction in the solana explorer. `susResult.explorerLink` will give you a valid explorer link to inspect the transaction. Note that you will also need to provide the `cluster` param for explorer. + +## Base and Priority Fees + +Sus will tell you both the base fee and the priority fees on a transaction. This is through `susResult.priorityFee` and `susResult.solFee`. + diff --git a/packages/sus/package.json b/packages/sus/package.json new file mode 100644 index 000000000..35217f775 --- /dev/null +++ b/packages/sus/package.json @@ -0,0 +1,48 @@ +{ + "name": "@helium/sus", + "version": "0.6.23", + "description": "Transaction simulation sus checker", + "publishConfig": { + "access": "public", + "registry": "https://registry.npmjs.org/" + }, + "license": "Apache-2.0", + "repository": { + "type": "git", + "url": "https://github.com/helium/helium-program-library" + }, + "main": "./lib/cjs/index.js", + "module": "./lib/esm/src/index.js", + "types": "./lib/types/src/index.d.ts", + "sideEffects": false, + "files": [ + "lib" + ], + "exports": { + "import": "./lib/esm/src/index.js", + "require": "./lib/cjs/index.js", + "types": "./lib/types/src/index.d.ts" + }, + "scripts": { + "format": "prettier --write \"src/**/*.{ts,tsx}\"", + "precommit": "npx git-format-staged -f 'prettier --ignore-unknown --stdin --stdin-filepath \"{}\"' .", + "clean": "npx shx mkdir -p lib && npx shx rm -rf lib", + "package": "npx shx mkdir -p lib/cjs lib/esm", + "prebuild": "npm run clean && npm run package" + }, + "dependencies": { + "@coral-xyz/anchor": "^0.28.0", + "@metaplex-foundation/mpl-token-metadata": "^2.10.0", + "@solana/spl-token": "^0.3.8", + "@solana/web3.js": "^1.78.4", + "axios": "^1.6.5", + "bn.js": "^5.2.0", + "bs58": "^4.0.1" + }, + "devDependencies": { + "git-format-staged": "^2.1.3", + "ts-loader": "^9.2.3", + "typescript": "^5.2.2" + }, + "gitHead": "5a8bf0b7b88e5934ef8d774e686f7c95804fbb8d" +} diff --git a/packages/sus/src/index.ts b/packages/sus/src/index.ts new file mode 100644 index 000000000..51b33713d --- /dev/null +++ b/packages/sus/src/index.ts @@ -0,0 +1,997 @@ +import { + BN, + BorshAccountsCoder, + BorshInstructionCoder, + Idl, +} from "@coral-xyz/anchor"; +import { decodeIdlAccount } from "@coral-xyz/anchor/dist/cjs/idl"; +import { utf8 } from "@coral-xyz/anchor/dist/cjs/utils/bytes"; +import { getLeafAssetId } from "@metaplex-foundation/mpl-bubblegum"; +import { + PROGRAM_ID as MPL_PID, + Metadata, +} from "@metaplex-foundation/mpl-token-metadata"; +import { sha256 } from "@noble/hashes/sha256"; +import { + NATIVE_MINT, + TOKEN_2022_PROGRAM_ID, + TOKEN_PROGRAM_ID, + unpackAccount, + unpackMint, + unpackMultisig, +} from "@solana/spl-token"; +import { + AccountInfo, + AccountMeta, + AddressLookupTableAccount, + Connection, + MessageAccountKeys, + PublicKey, + RpcResponseAndContext, + SimulatedTransactionResponse, + SystemProgram, + TransactionError, + VersionedTransaction, +} from "@solana/web3.js"; +import axios from "axios"; +import { inflate } from "pako"; + +const BUBBLEGUM_PROGRAM_ID = new PublicKey( + "BGUMAp9Gq7iTEuizy4pqaxsTyUCBK68MDfK752saRPUY" +); + +const ACCOUNT_COMPRESSION_PROGRAM_ID = new PublicKey( + "cmtDvXumGCrqC1Age74AVPhSRVXJMd8PJS91L8KbNCK" +); + +export type BalanceChange = { + owner: PublicKey; + address: PublicKey; + amount: bigint; + metadata: TokenMetadata; +}; + +export type TokenMetadata = { + mint: PublicKey; + decimals: number; + name?: string; + symbol?: string; + uri?: string; +}; + +export type Asset = { + id: string; + content: any; + compression: { + eligible: boolean; + compressed: boolean; + data_hash?: string; + creator_hash?: string; + asset_hash?: string; + tree?: string; + leaf_id?: number; + }; + ownership: { + owner: string; + delegate: string; + }; + royalty: { + basis_points: number; + primary_sale_happened: boolean; + }; + mutable: boolean; + supply: { + edition_nonce: number | null; + }; + grouping?: { group_key: string; group_value: PublicKey }[]; +}; + +export type WritableAccount = { + address: PublicKey; + // If this is something like a token account, display the owner + owner?: PublicKey; + // Attempt to parse a name for the account + // For token accounts may be "USDC Account" + // For anchor accounts, will be the name of the struct + name: string; + changedInSimulation: boolean; + pre: { + type: "TokenAccount" | string; + account: AccountInfo | null; + parsed: any | null; + }; + post: { + type: "TokenAccount" | string; + account: AccountInfo | null; + parsed: any | null; + }; + metadata?: TokenMetadata; +}; + +export type SusResult = { + instructions: { parsed?: ParsedInstruction; raw: RawInstruction }[]; + logs: string[] | null; + solFee: number; + priorityFee?: number; + insufficientFunds: boolean; + explorerLink: string; + balanceChanges: BalanceChange[]; + /// WARNING: This is best effort. You can't actually know which cNFTs can change, but you can + /// highlight any that belong to a tree that is changing. This is made worse by the fact that you + /// can't query DAS by tree. So we do our best and fetch at most 200 cNFTs and see if any can change. + /// If you're using this feature, you may want to use `extraSearchAssetParams` to limit to important collections + possibleCNftChanges: Asset[]; + writableAccounts: WritableAccount[]; + rawSimulation: SimulatedTransactionResponse; + error?: TransactionError; + /// Warnings about potential sus things in this transaction + warnings: Warning[]; +}; + +export type Warning = { + severity: "critical" | "warning"; + shortMessage: string; + message: string; + account?: PublicKey; +}; + +async function getAccountKeys({ + connection, + transaction, +}: { + connection: Connection; + transaction: VersionedTransaction; +}): Promise { + const addressLookupTableAccounts: Array = []; + const { addressTableLookups } = transaction.message; + if (addressTableLookups.length > 0) { + // eslint-disable-next-line no-restricted-syntax + for (const addressTableLookup of addressTableLookups) { + // eslint-disable-next-line no-await-in-loop + const result = await connection?.getAddressLookupTable( + addressTableLookup.accountKey + ); + if (result?.value) { + addressLookupTableAccounts.push(result?.value); + } + } + } + return transaction.message.getAccountKeys({ + addressLookupTableAccounts, + }); +} + +async function getMultipleAccounts({ + connection, + keys, +}): Promise[]> { + const batchSize = 100; + const batches = Math.ceil(keys.length / batchSize); + const results: AccountInfo[] = []; + + for (let i = 0; i < batches; i++) { + const batchKeys = keys.slice(i * batchSize, (i + 1) * batchSize); + const batchResults = await connection.getMultipleAccountsInfo(batchKeys); + results.push(...batchResults); + } + + return results; +} + +export async function sus({ + connection, + wallet, + serializedTransactions, + + /// CNFT specific params + checkCNfts = false, + extraSearchAssetParams, + cNfts, + // Cluster for explorer + cluster = "mainnet-beta", + accountBlacklist, +}: { + connection: Connection; + wallet: PublicKey; + serializedTransactions: Buffer[]; + /// See docs for SusResult `possibleCNftChanges` + checkCNfts?: boolean; + extraSearchAssetParams?: any; + /// Optionally pass cnfts to check instead of searchAssets. This can save on RPC calls, or keep from needing + /// An rpc that supports DAS + cNfts?: Asset[]; + cluster?: string; + /// Disallow fetching on this set of accounts. This is useful for cases like avoiding fetching + /// known massive merkle trees to save on data. + accountBlacklist?: Set; +}): Promise { + let assets = cNfts; + if (checkCNfts) { + if (!assets) { + const assetsResponse = await axios.post(connection.rpcEndpoint, { + jsonrpc: "2.0", + method: "searchAssets", + id: "get-assets-op-1", + params: { + page: 1, + // limit to checking 200 assets + limit: 200, + compressed: true, + ownerAddress: wallet.toBase58(), + ...extraSearchAssetParams, + }, + headers: { + "Cache-Control": "no-cache", + Pragma: "no-cache", + Expires: "0", + }, + }); + assets = assetsResponse.data.result?.items as Asset[]; + } + } + const warningsByTx: Warning[][] = serializedTransactions.map(() => []); + const transactions = serializedTransactions.map((t) => + VersionedTransaction.deserialize(t) + ); + + const accountKeysByTx = await Promise.all( + transactions.map((transaction) => + getAccountKeys({ connection, transaction }) + ) + ); + + const simulationAccountsByTx = accountKeysByTx.map((accountKeys, txIndex) => + [ + ...new Set( + accountKeys.staticAccountKeys + .filter((_, index) => + transactions[txIndex].message.isAccountWritable(index) + ) + .concat( + accountKeys.accountKeysFromLookups + ? // Only writable accounts will contribute to balance changes + accountKeys.accountKeysFromLookups.writable + : [] + ) + ), + ].filter((a) => !accountBlacklist?.has(a.toBase58())) + ); + const allAccounts = [...new Set(simulationAccountsByTx.flat())]; + const fetchedAccounts = await getMultipleAccounts({ + connection, + keys: allAccounts, + }); + const fetchedAccountsByAddr = fetchedAccounts.reduce((acc, account, index) => { + acc[allAccounts[index].toBase58()] = account + return acc + }, {} as Record>) + const { blockhash } = await connection?.getLatestBlockhash(); + const simulatedTxs: RpcResponseAndContext[] = + []; + // Linearly simulate txs so as not to hit rate limits + for (const [index, transaction] of transactions.entries()) { + transaction.message.recentBlockhash = blockhash; + const simulatedTxn = await connection?.simulateTransaction(transaction, { + accounts: { + encoding: "base64", + addresses: + simulationAccountsByTx[index]?.map((account) => account.toBase58()) || + [], + }, + }); + simulatedTxs.push(simulatedTxn); + } + + const fullAccountsByTxn = simulationAccountsByTx.map( + (simulationAccounts, transactionIndex) => { + const simulatedTxn = simulatedTxs[transactionIndex]; + return simulationAccounts.map((account, index) => { + const post = simulatedTxn.value.accounts?.[index]; + return { + address: account, + post: post + ? { + ...post, + owner: new PublicKey(post.owner), + data: Buffer.from(post.data[0], post.data[1] as any), + } + : undefined, + pre: fetchedAccountsByAddr[account.toBase58()], + }; + }); + } + ); + + const instructionProgramIds = transactions + .flatMap((transaction, index) => + transaction.message.compiledInstructions.map( + (ix) => accountKeysByTx[index].get(ix.programIdIndex) || null + ) + ) + .filter(truthy); + const programKeys = fullAccountsByTxn + .flat() + .map( + (acc) => + acc?.pre?.owner || (acc.post ? new PublicKey(acc.post.owner) : null) + ) + .concat(...instructionProgramIds) + .filter(truthy); + const idlKeys = programKeys.map(getIdlKey); + const idls = (await getMultipleAccounts({ connection, keys: idlKeys })) + .map((acc, index) => { + if (acc) { + return { + program: programKeys[index], + idl: decodeIdl(acc), + }; + } + }) + .filter(truthy) + .reduce((acc, { program, idl }) => { + if (idl) { + acc[program.toBase58()] = idl; + } + return acc; + }, {} as Record); + + const writableAccountsByTxRaw = fullAccountsByTxn.map((accounts) => + getDetailedWritableAccountsWithoutTM({ + accounts, + idls, + }) + ); + const tokens = [ + ...new Set( + writableAccountsByTxRaw.flatMap((w) => w.tokens).map((t) => t.toBase58()) + ), + ].map((t) => new PublicKey(t)); + const metadatas = (await fetchMetadatas(connection, tokens)).reduce( + (acc, m, index) => { + if (m) { + acc[tokens[index].toBase58()] = m; + } + return acc; + }, + {} as Record + ); + const writableAccountsByTx = writableAccountsByTxRaw.map( + ({ withoutMetadata }, index) => { + const writableAccounts = withoutMetadata.map((acc) => { + let name = acc.name; + let metadata; + // Attempt to take last known type + const type = + (acc.pre.type !== "Unknown" && acc.pre.type) || + (acc.post.type !== "Unknown" && acc.post.type) || + "Unknown"; + // If token, get the name based on the metadata + if (type === "Mint") { + metadata = metadatas[acc.address.toBase58()]; + if (metadata) { + name = `${metadata.symbol} Mint`; + } else { + name = `Unknown Mint`; + } + } else if (type === "TokenAccount") { + metadata = + metadatas[ + (acc.pre.parsed?.mint || acc.post.parsed?.mint).toBase58() + ]; + if (metadata) { + name = `${metadata.symbol} Token Account`; + } else { + name = `Unknown Token Account`; + } + } + + return { + ...acc, + name, + metadata, + }; + }); + writableAccounts.forEach((acc) => { + if (!acc.changedInSimulation) { + warningsByTx[index].push({ + severity: "warning", + shortMessage: "Unchanged", + message: + "Account did not change in simulation but was labeled as writable. The behavior of the transaction may differ from the simulation.", + account: acc.address, + }); + } + + // Catch malicious sol ownwer change + const sysProg = new PublicKey("11111111111111111111111111111111") + const postOwner = acc.post.account?.owner || sysProg + const preOwner = acc.pre.account?.owner || sysProg + const accountOwnerChanged = !preOwner.equals(postOwner) + if (acc.name === "Native SOL Account" && acc.owner && acc.owner.equals(wallet) && accountOwnerChanged) { + warningsByTx[index].push({ + severity: "critical", + shortMessage: "Owner Changed", + message: `The owner of ${acc.name} changed to ${acc.post.parsed?.owner?.toBase58()}. This gives that wallet full custody of these tokens.`, + account: acc.address, + }); + } + }); + + return writableAccounts; + } + ); + + const instructionsByTx = await Promise.all( + transactions.map(async (transaction, index) => { + const instructions = parseInstructions({ + idls, + instructions: transaction.message.compiledInstructions.map((ix) => ({ + data: Buffer.from(ix.data), + programId: accountKeysByTx[index].get(ix.programIdIndex)!, + accounts: ix.accountKeyIndexes.map((ix) => ({ + pubkey: accountKeysByTx[index].get(ix)!, + isSigner: transaction.message.isAccountSigner(ix), + isWritable: transaction.message.isAccountWritable(ix), + })), + })), + }); + if ( + instructions.some( + (ix) => ix.parsed?.name === "ledgerTransferPositionV0" + ) + ) { + warningsByTx[index].push({ + severity: "critical", + shortMessage: "Theft of Locked HNT", + message: + "This transaction is attempting to steal your locked HNT positions", + }); + } + if ( + ( + await Promise.all( + instructions.map((ix) => isBurnHotspot(connection, ix, assets)) + ) + ).some((isBurn) => isBurn) + ) { + warningsByTx[index].push({ + severity: "critical", + shortMessage: "Hotspot Destroyed", + message: "This transaction will brick your Hotspot!", + }); + } + + return instructions; + }) + ); + + const results: SusResult[] = []; + for (const [index, simulatedTxn] of simulatedTxs.entries()) { + const warnings = warningsByTx[index]; + const instructions = instructionsByTx[index]; + const writableAccounts = writableAccountsByTx[index]; + const transaction = transactions[index]; + + const message = transaction.message.serialize().toString("base64"); + const explorerLink = `https://explorer.solana.com/tx/inspector?cluster=${cluster}&message=${encodeURIComponent( + message + )}`; + + const logs = simulatedTxn.value.logs; + let result: SusResult; + if (simulatedTxn?.value.err) { + warnings.push({ + severity: "critical", + shortMessage: "Simulation Failed", + message: "Transaction failed in simulation", + }); + result = { + instructions, + error: simulatedTxn.value.err, + logs, + solFee: 0, + priorityFee: 0, + insufficientFunds: isInsufficientBal(simulatedTxn?.value.err), + explorerLink, + balanceChanges: [], + possibleCNftChanges: [], + writableAccounts, + rawSimulation: simulatedTxn.value, + warnings, + }; + } else { + let solFee = (transaction?.signatures.length || 1) * 5000; + let priorityFee = 0; + + const fee = + (await connection?.getFeeForMessage(transaction.message, "confirmed")) + .value || solFee; + priorityFee = fee - solFee; + const balanceChanges = writableAccounts + .map((acc) => { + const type = + (acc.pre.type !== "Unknown" && acc.pre.type) || + (acc.post.type !== "Unknown" && acc.post.type); + switch (type) { + case "TokenAccount": + if (acc.post.parsed?.delegate && !acc.pre.parsed?.delegate) { + warnings.push({ + severity: "warning", + shortMessage: "Withdraw Authority Given", + message: `Delegation was taken on ${acc.name}. This gives permission to withdraw tokens without the owner's permission.`, + account: acc.address, + }); + } + if ( + acc.post.parsed && + acc.pre.parsed && + !acc.post.parsed.owner.equals(acc.pre.parsed.owner) + ) { + warnings.push({ + severity: "warning", + shortMessage: "Owner Changed", + message: `The owner of ${ + acc.name + } changed to ${acc.post.parsed?.owner?.toBase58()}. This gives that wallet full custody of these tokens.`, + account: acc.address, + }); + } + return { + owner: acc.post.parsed?.owner || acc.pre.parsed?.owner, + address: acc.address, + amount: + ((acc.post.parsed?.amount as bigint) || BigInt(0)) - + ((acc.pre.parsed?.amount as bigint) || BigInt(0)), + metadata: acc.metadata, + } as BalanceChange; + case "NativeAccount": + return { + owner: acc.address, + address: acc.address, + amount: BigInt( + (acc.post.account?.lamports || 0) - + (acc.pre.account?.lamports || 0) + ), + metadata: { + mint: NATIVE_MINT, + decimals: 9, + name: "SOL", + symbol: "SOL", + }, + } as BalanceChange; + default: + return null; + } + }) + .filter(truthy); + + // Don't count new mints being created, as this might flag on candymachine txs + if (balanceChanges.filter((b) => b.owner.equals(wallet) && fetchedAccountsByAddr[b.address.toBase58()]).length >= 3) { + warnings.push({ + severity: "warning", + shortMessage: "3+ Token Accounts", + message: + "3 or more token accounts are impacted by this transaction. Any token account listed as writable can be emptied by the transaction, is this okay?", + }); + } + + let possibleCNftChanges: Asset[] = []; + if (checkCNfts) { + const possibleMerkles = new Set( + writableAccounts + .filter((acc) => acc.name === "Merkle Tree") + .map((a) => a.address.toBase58()) + ); + + possibleCNftChanges = (assets || []).filter( + (item) => + item.compression.tree && possibleMerkles.has(item.compression.tree) + ); + } + + result = { + instructions, + logs, + solFee, + priorityFee, + insufficientFunds: false, + explorerLink, + balanceChanges, + possibleCNftChanges, + writableAccounts, + rawSimulation: simulatedTxn.value, + warnings, + }; + } + + results.push(result); + } + + return results +} + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export function isInsufficientBal(e: any) { + return ( + e.toString().includes("Insufficient Balance") || + e.toString().includes('"Custom":1') || + e.InstructionError?.[1]?.Custom === 1 + ); +} + +export type ParsedInstruction = { + name: string; + programName: string; + data: any; + accounts: { + name?: string; + pubkey: PublicKey; + isSigner: boolean; + isWritable: boolean; + }[]; +}; + +export type RawInstruction = { + data: Buffer; + programId: PublicKey; + accounts: AccountMeta[]; +}; +function parseInstructions({ + idls, + instructions, +}: { + idls: Record; + instructions: RawInstruction[]; +}): { parsed?: ParsedInstruction; raw: RawInstruction }[] { + return instructions.map((ix) => { + const idl = idls[ix.programId.toBase58()]; + if (idl) { + try { + const coder = new BorshInstructionCoder(idl); + const parsed = coder.decode(ix.data, "base58"); + if (parsed) { + const formatted = coder.format(parsed, ix.accounts); + if (formatted) { + return { + parsed: { + name: parsed.name, + programName: idl.name, + data: parsed.data, + accounts: formatted.accounts, + }, + raw: ix, + }; + } + } + } catch (e: any) { + // Ignore, not a valid ix + } + } + return { raw: ix }; + }); +} + +function getIdlKey(programId: PublicKey): PublicKey { + const base = PublicKey.findProgramAddressSync([], programId)[0]; + const buffer = Buffer.concat([ + base.toBuffer(), + Buffer.from("anchor:idl"), + programId.toBuffer(), + ]); + const publicKeyBytes = sha256(buffer); + return new PublicKey(publicKeyBytes); +} + +function decodeIdl(account: AccountInfo): Idl | undefined { + try { + const idlData = decodeIdlAccount(Buffer.from(account.data.subarray(8))); + const inflatedIdl = inflate(idlData.data); + return JSON.parse(utf8.decode(inflatedIdl)); + } catch (e: any) { + // Ignore, not a valid IDL + } +} + +export function getDetailedWritableAccountsWithoutTM({ + accounts, + idls, +}: { + accounts: { + address: PublicKey; + pre: AccountInfo | null | undefined; + post: AccountInfo | null | undefined; + }[]; + idls: Record; +}): { withoutMetadata: WritableAccount[]; tokens: PublicKey[] } { + const uniqueTokens: Set = new Set(); + const withoutMetadata = accounts.map(({ address, pre, post }) => { + let name = "Unknown"; + let type = "Unknown"; + let preParsed: null | any = null; + let postParsed: null | any = null; + let accountOwner: PublicKey | undefined = undefined; + + const postData = post && post.data; + const postAccount = + post && postData + ? { + executable: post.executable, + owner: new PublicKey(post.owner), + lamports: post.lamports, + data: postData, + rentEpoch: post.rentEpoch, + } + : null; + + const owner = pre?.owner || (post ? new PublicKey(post.owner) : null); + switch (owner?.toBase58()) { + case ACCOUNT_COMPRESSION_PROGRAM_ID.toBase58(): + name = "Merkle Tree"; + type = "MerkleTree"; + break; + case SystemProgram.programId.toBase58(): + name = "Native SOL Account"; + type = "NativeAccount"; + accountOwner = address; + break; + case TOKEN_2022_PROGRAM_ID.toBase58(): + ({ parsed: preParsed, type } = decodeTokenStruct( + address, + pre, + TOKEN_2022_PROGRAM_ID + ) || { type: "Unknown Token Program" }); + ({ parsed: postParsed, type } = decodeTokenStruct( + address, + postAccount, + TOKEN_2022_PROGRAM_ID + ) || { type: "Unknown Token Program" }); + + break; + case TOKEN_PROGRAM_ID.toBase58(): + ({ parsed: preParsed, type } = decodeTokenStruct( + address, + pre, + TOKEN_PROGRAM_ID + ) || { type: "Unknown Token Program" }); + ({ parsed: postParsed, type } = decodeTokenStruct( + address, + postAccount, + TOKEN_PROGRAM_ID + ) || { type: "Unknown Token Program" }); + + break; + default: + if (owner) { + const idl = idls[owner.toBase58()]; + if (idl) { + const decodedPre = decodeIdlStruct(idl, pre) + const decodedPost = decodeIdlStruct( + idl, + postAccount + ) + preParsed = decodedPre?.parsed + postParsed = decodedPost?.parsed + type = decodedPre?.type || decodedPost?.type || "Unknown" + name = type; + } + } + + break; + } + + // If token, get the name based on the metadata + if ( + new Set([ + TOKEN_2022_PROGRAM_ID.toBase58(), + TOKEN_PROGRAM_ID.toBase58(), + ]).has(owner?.toBase58() || "") + ) { + if (type === "Mint") { + uniqueTokens.add(address.toBase58()); + } else if (type === "TokenAccount") { + const mint = (preParsed?.mint || postParsed?.mint).toBase58(); + accountOwner = preParsed?.owner || postParsed?.owner; + uniqueTokens.add(mint); + } + } + + return { + address, + name, + owner: accountOwner, + pre: { + type, + account: pre || null, + parsed: preParsed, + }, + post: { + type, + account: post || null, + parsed: postParsed, + }, + changedInSimulation: + pre && postData + ? !pre.data.equals(postData) || + pre.lamports != post.lamports || + !pre.owner.equals(new PublicKey(post.owner)) + : true, + }; + }); + + const tokens = [...uniqueTokens].map((t) => new PublicKey(t)); + return { + withoutMetadata, + tokens, + }; +} + +function decodeIdlStruct( + idl: Idl, + account: AccountInfo | null | undefined +): { type: string; parsed: any } | null { + if (!account) { + return null; + } + + try { + const coder = new BorshAccountsCoder(idl); + const descriminator = account.data.slice(0, 8); + const type = idl.accounts?.find((account) => + BorshAccountsCoder.accountDiscriminator(account.name).equals( + descriminator + ) + )?.name; + if (type) { + return { + type, + parsed: coder.decode(type, account.data), + }; + } + } catch (e: any) { + // Ignore, not a valid account + } + + return null; +} + +function decodeTokenStruct( + address: PublicKey, + account: AccountInfo | null | undefined, + programId: PublicKey +): { type: string; parsed: any } | null { + if (!account) { + return null; + } + + try { + return { + type: "TokenAccount", + parsed: unpackAccount(address, account, programId), + }; + } catch (e: any) { + // Not an account + } + + try { + return { + type: "Mint", + parsed: unpackMint(address, account, programId), + }; + } catch (e: any) { + // Not an account + } + + try { + return { + type: "Multisig", + parsed: unpackMultisig(address, account, programId), + }; + } catch (e: any) { + // Not an account + } + return null; +} + +export function getMetadataId(mint: PublicKey): PublicKey { + return PublicKey.findProgramAddressSync( + [Buffer.from("metadata", "utf-8"), MPL_PID.toBuffer(), mint.toBuffer()], + MPL_PID + )[0]; +} + +export async function fetchMetadatas( + connection: Connection, + tokens: PublicKey[] +): Promise<(TokenMetadata | null)[]> { + const metadatas = tokens.map(getMetadataId); + const all = await getMultipleAccounts({ + keys: [...metadatas, ...tokens], + connection, + }); + const metadataAccounts = all.slice(0, metadatas.length); + const mintAccounts = all.slice(metadatas.length, metadatas.length * 2); + return metadataAccounts.map((acc, index) => { + try { + const mint = unpackMint(tokens[index], mintAccounts[index]); + if (acc) { + const collectable = Metadata.fromAccountInfo(acc)[0]; + return { + name: collectable.data.name.replace(/\0/g, ""), + symbol: collectable.data.symbol.replace(/\0/g, ""), + uri: collectable.data.uri.replace(/\0/g, ""), + decimals: mint.decimals, + mint: tokens[index], + }; + } + + return { + mint: tokens[index], + decimals: mint.decimals, + }; + } catch (e: any) { + // Ignore, not a valid mint + } + + return null + }); +} + +type Truthy = T extends false | "" | 0 | null | undefined ? never : T; // from lodash + +const truthy = (value: T): value is Truthy => !!value; + +async function isBurnHotspot( + connection: Connection, + ix: { parsed?: ParsedInstruction | undefined; raw: RawInstruction }, + assets?: Asset[] +): Promise { + if ( + ix.raw.programId.equals(BUBBLEGUM_PROGRAM_ID) && + ix.parsed?.name === "burn" + ) { + const tree = ix.parsed?.accounts.find( + (acc) => acc.name === "Merkle Tree" + )?.pubkey; + if (tree) { + const index = ix.parsed?.data?.index; + const assetId = await getLeafAssetId(tree, new BN(index)); + let asset + if (assets) { + asset = assets.find(a => a.id === assetId.toBase58()) + } else { + const assetResponse = await axios.post(connection.rpcEndpoint, { + jsonrpc: "2.0", + method: "getAsset", + id: "get-asset-op-1", + params: { + id: assetId.toBase58(), + }, + headers: { + "Cache-Control": "no-cache", + Pragma: "no-cache", + Expires: "0", + }, + }); + asset = assetResponse.data.result + } + return ( + asset && + asset.creators[0]?.address == HELIUM_ENTITY_CREATOR.toBase58() && + asset.creators[0]?.verified + ); + } + } + return false; +} + +const DAO = PublicKey.findProgramAddressSync( + [ + Buffer.from("dao", "utf-8"), + new PublicKey("hntyVP6YFm1Hg25TN9WGLqM12b8TQmcknKrdu1oxWux").toBuffer(), + ], + new PublicKey("hdaoVTCqhfHHo75XdAMxBKdUqvq1i5bF23sisBqVgGR") +)[0]; +const HELIUM_ENTITY_CREATOR = PublicKey.findProgramAddressSync( + [Buffer.from("entity_creator", "utf-8"), DAO.toBuffer()], + new PublicKey("hemjuPXBpNvggtaUnN1MwT3wrdhttKEfosTcc2P9Pg8") +)[0]; diff --git a/packages/sus/tsconfig.cjs.json b/packages/sus/tsconfig.cjs.json new file mode 100644 index 000000000..950b2365f --- /dev/null +++ b/packages/sus/tsconfig.cjs.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.cjs.json", + "include": ["src"], + "compilerOptions": { + "outDir": "lib/cjs" + } +} \ No newline at end of file diff --git a/packages/sus/tsconfig.esm.json b/packages/sus/tsconfig.esm.json new file mode 100644 index 000000000..4b7ba456e --- /dev/null +++ b/packages/sus/tsconfig.esm.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.esm.json", + "include": ["src"], + "compilerOptions": { + "outDir": "lib/esm", + "declarationDir": "lib/types" + } +} diff --git a/packages/sus/tsconfig.json b/packages/sus/tsconfig.json new file mode 100644 index 000000000..7b8e5fca2 --- /dev/null +++ b/packages/sus/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../../tsconfig.root.json", + "references": [ + { + "path": "./tsconfig.cjs.json" + }, + { + "path": "./tsconfig.esm.json" + }, + ] +} diff --git a/packages/sus/yarn.deploy.lock b/packages/sus/yarn.deploy.lock new file mode 100644 index 000000000..f6f96ecad --- /dev/null +++ b/packages/sus/yarn.deploy.lock @@ -0,0 +1,1973 @@ +# This file is generated by running "yarn install" inside your project. +# Manual changes might be lost - proceed with caution! + +__metadata: + version: 6 + cacheKey: 8 + +"@babel/runtime@npm:^7.17.2, @babel/runtime@npm:^7.22.6": + version: 7.22.11 + resolution: "@babel/runtime@npm:7.22.11" + dependencies: + regenerator-runtime: "npm:^0.14.0" + checksum: a5cd6683a8fcdb8065cb1677f221e22f6c67ec8f15ad1d273b180b93ab3bd86c66da2c48f500d4e72d8d2cfa85ff4872a3f350e5aa3855630036af5da765c001 + languageName: node + linkType: hard + +"@coral-xyz/anchor@npm:^0.28.0": + version: 0.28.0 + resolution: "@coral-xyz/anchor@npm:0.28.0" + dependencies: + "@coral-xyz/borsh": "npm:^0.28.0" + "@solana/web3.js": "npm:^1.68.0" + base64-js: "npm:^1.5.1" + bn.js: "npm:^5.1.2" + bs58: "npm:^4.0.1" + buffer-layout: "npm:^1.2.2" + camelcase: "npm:^6.3.0" + cross-fetch: "npm:^3.1.5" + crypto-hash: "npm:^1.3.0" + eventemitter3: "npm:^4.0.7" + js-sha256: "npm:^0.9.0" + pako: "npm:^2.0.3" + snake-case: "npm:^3.0.4" + superstruct: "npm:^0.15.4" + toml: "npm:^3.0.0" + checksum: 58b3677b5b2ce2c779045184ce4a0ef696966a6a58f41c1c56f6f178db0491acecb6ec677ce0502f0b382a2c724f9c2860d82cc88601784d556d95fbeda415e5 + languageName: node + linkType: hard + +"@coral-xyz/borsh@npm:^0.28.0": + version: 0.28.0 + resolution: "@coral-xyz/borsh@npm:0.28.0" + dependencies: + bn.js: "npm:^5.1.2" + buffer-layout: "npm:^1.2.0" + peerDependencies: + "@solana/web3.js": ^1.68.0 + checksum: bc2b06b777f9ed43d3b886d2350826bd44d5b932c4fd4471af5956e8755236f5854938c890ee4986d88f61d1439e1d84e715c43dcb6dca4e76198c1ce8dc7a58 + languageName: node + linkType: hard + +"@helium/sus@workspace:.": + version: 0.0.0-use.local + resolution: "@helium/sus@workspace:." + dependencies: + "@coral-xyz/anchor": ^0.28.0 + "@metaplex-foundation/mpl-token-metadata": ^2.10.0 + "@solana/spl-token": ^0.3.8 + "@solana/web3.js": ^1.78.4 + axios: ^1.6.5 + bn.js: ^5.2.0 + bs58: ^4.0.1 + git-format-staged: ^2.1.3 + ts-loader: ^9.2.3 + typescript: ^5.2.2 + languageName: unknown + linkType: soft + +"@isaacs/cliui@npm:^8.0.2": + version: 8.0.2 + resolution: "@isaacs/cliui@npm:8.0.2" + dependencies: + string-width: "npm:^5.1.2" + string-width-cjs: "npm:string-width@^4.2.0" + strip-ansi: "npm:^7.0.1" + strip-ansi-cjs: "npm:strip-ansi@^6.0.1" + wrap-ansi: "npm:^8.1.0" + wrap-ansi-cjs: "npm:wrap-ansi@^7.0.0" + checksum: 4a473b9b32a7d4d3cfb7a614226e555091ff0c5a29a1734c28c72a182c2f6699b26fc6b5c2131dfd841e86b185aea714c72201d7c98c2fba5f17709333a67aeb + languageName: node + linkType: hard + +"@metaplex-foundation/beet-solana@npm:^0.4.0": + version: 0.4.0 + resolution: "@metaplex-foundation/beet-solana@npm:0.4.0" + dependencies: + "@metaplex-foundation/beet": "npm:>=0.1.0" + "@solana/web3.js": "npm:^1.56.2" + bs58: "npm:^5.0.0" + debug: "npm:^4.3.4" + checksum: ee746c2d15f985c31d133d4ee29efbda445877473cc32aafa4b684ce3fa9a916ddff30d0e3cfef7654ff5725adff59a62a635c76bc781a6e1362c5b5d3137ed0 + languageName: node + linkType: hard + +"@metaplex-foundation/beet@npm:>=0.1.0, @metaplex-foundation/beet@npm:^0.7.1": + version: 0.7.1 + resolution: "@metaplex-foundation/beet@npm:0.7.1" + dependencies: + ansicolors: "npm:^0.3.2" + bn.js: "npm:^5.2.0" + debug: "npm:^4.3.3" + checksum: f8a330073ab1a0976478e9847c0e63e32f7bee67ea6306e1f89784e8275e30daaecba7cbc5f3424e5d96c411aa3bfbc2b638c105a90067a985acdfbd33a1a287 + languageName: node + linkType: hard + +"@metaplex-foundation/cusper@npm:^0.0.2": + version: 0.0.2 + resolution: "@metaplex-foundation/cusper@npm:0.0.2" + checksum: d157953baf42a2a012cdeb809c1785f29a44d80a3b5a3841c930baeb12ac6ddcf37f1a15eded4dce20d66f7bc8f23bedb87e905758df721e274bfcd816e70ba1 + languageName: node + linkType: hard + +"@metaplex-foundation/mpl-token-metadata@npm:^2.10.0": + version: 2.13.0 + resolution: "@metaplex-foundation/mpl-token-metadata@npm:2.13.0" + dependencies: + "@metaplex-foundation/beet": "npm:^0.7.1" + "@metaplex-foundation/beet-solana": "npm:^0.4.0" + "@metaplex-foundation/cusper": "npm:^0.0.2" + "@solana/spl-token": "npm:^0.3.6" + "@solana/web3.js": "npm:^1.66.2" + bn.js: "npm:^5.2.0" + debug: "npm:^4.3.4" + checksum: 89f82980f435ac45d961e6ab03859c7e4ab9809ad2d9f84aca91bcf50fdc60e210d0596d8856adf63e474ca69d971c51a4c27d0fe4dab115fcef64d57f3be611 + languageName: node + linkType: hard + +"@noble/curves@npm:^1.0.0": + version: 1.2.0 + resolution: "@noble/curves@npm:1.2.0" + dependencies: + "@noble/hashes": "npm:1.3.2" + checksum: bb798d7a66d8e43789e93bc3c2ddff91a1e19fdb79a99b86cd98f1e5eff0ee2024a2672902c2576ef3577b6f282f3b5c778bebd55761ddbb30e36bf275e83dd0 + languageName: node + linkType: hard + +"@noble/hashes@npm:1.3.2, @noble/hashes@npm:^1.3.1": + version: 1.3.2 + resolution: "@noble/hashes@npm:1.3.2" + checksum: fe23536b436539d13f90e4b9be843cc63b1b17666a07634a2b1259dded6f490be3d050249e6af98076ea8f2ea0d56f578773c2197f2aa0eeaa5fba5bc18ba474 + languageName: node + linkType: hard + +"@npmcli/fs@npm:^3.1.0": + version: 3.1.0 + resolution: "@npmcli/fs@npm:3.1.0" + dependencies: + semver: "npm:^7.3.5" + checksum: a50a6818de5fc557d0b0e6f50ec780a7a02ab8ad07e5ac8b16bf519e0ad60a144ac64f97d05c443c3367235d337182e1d012bbac0eb8dbae8dc7b40b193efd0e + languageName: node + linkType: hard + +"@pkgjs/parseargs@npm:^0.11.0": + version: 0.11.0 + resolution: "@pkgjs/parseargs@npm:0.11.0" + checksum: 6ad6a00fc4f2f2cfc6bff76fb1d88b8ee20bc0601e18ebb01b6d4be583733a860239a521a7fbca73b612e66705078809483549d2b18f370eb346c5155c8e4a0f + languageName: node + linkType: hard + +"@solana/buffer-layout-utils@npm:^0.2.0": + version: 0.2.0 + resolution: "@solana/buffer-layout-utils@npm:0.2.0" + dependencies: + "@solana/buffer-layout": "npm:^4.0.0" + "@solana/web3.js": "npm:^1.32.0" + bigint-buffer: "npm:^1.1.5" + bignumber.js: "npm:^9.0.1" + checksum: 9284242245b18b49577195ba7548263850be865a4a2d183944fa01bb76382039db589aab8473698e9bb734b515ada9b4d70db0a72e341c5d567c59b83d6d0840 + languageName: node + linkType: hard + +"@solana/buffer-layout@npm:^4.0.0": + version: 4.0.1 + resolution: "@solana/buffer-layout@npm:4.0.1" + dependencies: + buffer: "npm:~6.0.3" + checksum: bf846888e813187243d4008a7a9f58b49d16cbd995b9d7f1b72898aa510ed77b1ce5e8468e7b2fd26dd81e557a4e74a666e21fccb95f123c1f740d41138bbacd + languageName: node + linkType: hard + +"@solana/spl-token@npm:^0.3.6, @solana/spl-token@npm:^0.3.8": + version: 0.3.8 + resolution: "@solana/spl-token@npm:0.3.8" + dependencies: + "@solana/buffer-layout": "npm:^4.0.0" + "@solana/buffer-layout-utils": "npm:^0.2.0" + buffer: "npm:^6.0.3" + peerDependencies: + "@solana/web3.js": ^1.47.4 + checksum: 01f4f87112b0ad277701a3bcb8e03069b69449b92724b17959107686731082bfd3475b5f105e1e8f04badd2e810a43d5ef811744ced5178eea1232de8fd75147 + languageName: node + linkType: hard + +"@solana/web3.js@npm:^1.32.0, @solana/web3.js@npm:^1.56.2, @solana/web3.js@npm:^1.66.2, @solana/web3.js@npm:^1.68.0, @solana/web3.js@npm:^1.78.4": + version: 1.78.4 + resolution: "@solana/web3.js@npm:1.78.4" + dependencies: + "@babel/runtime": "npm:^7.22.6" + "@noble/curves": "npm:^1.0.0" + "@noble/hashes": "npm:^1.3.1" + "@solana/buffer-layout": "npm:^4.0.0" + agentkeepalive: "npm:^4.3.0" + bigint-buffer: "npm:^1.1.5" + bn.js: "npm:^5.2.1" + borsh: "npm:^0.7.0" + bs58: "npm:^4.0.1" + buffer: "npm:6.0.3" + fast-stable-stringify: "npm:^1.0.0" + jayson: "npm:^4.1.0" + node-fetch: "npm:^2.6.12" + rpc-websockets: "npm:^7.5.1" + superstruct: "npm:^0.14.2" + checksum: e1c44c6cbec87cdfd4d6d23b4241b746e14ed3a9ca73d596693758d91ac825cecf579345da3b0b7bb5e54b6794791bc0eac02cadf11f1ec79e859b6536f26f11 + languageName: node + linkType: hard + +"@tootallnate/once@npm:2": + version: 2.0.0 + resolution: "@tootallnate/once@npm:2.0.0" + checksum: ad87447820dd3f24825d2d947ebc03072b20a42bfc96cbafec16bff8bbda6c1a81fcb0be56d5b21968560c5359a0af4038a68ba150c3e1694fe4c109a063bed8 + languageName: node + linkType: hard + +"@types/connect@npm:^3.4.33": + version: 3.4.35 + resolution: "@types/connect@npm:3.4.35" + dependencies: + "@types/node": "npm:*" + checksum: fe81351470f2d3165e8b12ce33542eef89ea893e36dd62e8f7d72566dfb7e448376ae962f9f3ea888547ce8b55a40020ca0e01d637fab5d99567673084542641 + languageName: node + linkType: hard + +"@types/node@npm:*": + version: 20.5.7 + resolution: "@types/node@npm:20.5.7" + checksum: fc284c8e16ddc04569730d58e87eae349eb1c3dd9020cb79a1862d9d9add6f04e7367a236f3252db8db2572f90278e250f4cd43d27d264972b54394eaba1ed76 + languageName: node + linkType: hard + +"@types/node@npm:^12.12.54": + version: 12.20.55 + resolution: "@types/node@npm:12.20.55" + checksum: e4f86785f4092706e0d3b0edff8dca5a13b45627e4b36700acd8dfe6ad53db71928c8dee914d4276c7fd3b6ccd829aa919811c9eb708a2c8e4c6eb3701178c37 + languageName: node + linkType: hard + +"@types/ws@npm:^7.4.4": + version: 7.4.7 + resolution: "@types/ws@npm:7.4.7" + dependencies: + "@types/node": "npm:*" + checksum: b4c9b8ad209620c9b21e78314ce4ff07515c0cadab9af101c1651e7bfb992d7fd933bd8b9c99d110738fd6db523ed15f82f29f50b45510288da72e964dedb1a3 + languageName: node + linkType: hard + +"JSONStream@npm:^1.3.5": + version: 1.3.5 + resolution: "JSONStream@npm:1.3.5" + dependencies: + jsonparse: "npm:^1.2.0" + through: "npm:>=2.2.7 <3" + bin: + JSONStream: ./bin.js + checksum: 2605fa124260c61bad38bb65eba30d2f72216a78e94d0ab19b11b4e0327d572b8d530c0c9cc3b0764f727ad26d39e00bf7ebad57781ca6368394d73169c59e46 + languageName: node + linkType: hard + +"abbrev@npm:^1.0.0": + version: 1.1.1 + resolution: "abbrev@npm:1.1.1" + checksum: a4a97ec07d7ea112c517036882b2ac22f3109b7b19077dc656316d07d308438aac28e4d9746dc4d84bf6b1e75b4a7b0a5f3cb30592419f128ca9a8cee3bcfa17 + languageName: node + linkType: hard + +"agent-base@npm:6, agent-base@npm:^6.0.2": + version: 6.0.2 + resolution: "agent-base@npm:6.0.2" + dependencies: + debug: "npm:4" + checksum: f52b6872cc96fd5f622071b71ef200e01c7c4c454ee68bc9accca90c98cfb39f2810e3e9aa330435835eedc8c23f4f8a15267f67c6e245d2b33757575bdac49d + languageName: node + linkType: hard + +"agentkeepalive@npm:^4.2.1, agentkeepalive@npm:^4.3.0": + version: 4.5.0 + resolution: "agentkeepalive@npm:4.5.0" + dependencies: + humanize-ms: "npm:^1.2.1" + checksum: 13278cd5b125e51eddd5079f04d6fe0914ac1b8b91c1f3db2c1822f99ac1a7457869068997784342fe455d59daaff22e14fb7b8c3da4e741896e7e31faf92481 + languageName: node + linkType: hard + +"aggregate-error@npm:^3.0.0": + version: 3.1.0 + resolution: "aggregate-error@npm:3.1.0" + dependencies: + clean-stack: "npm:^2.0.0" + indent-string: "npm:^4.0.0" + checksum: 1101a33f21baa27a2fa8e04b698271e64616b886795fd43c31068c07533c7b3facfcaf4e9e0cab3624bd88f729a592f1c901a1a229c9e490eafce411a8644b79 + languageName: node + linkType: hard + +"ansi-regex@npm:^5.0.1": + version: 5.0.1 + resolution: "ansi-regex@npm:5.0.1" + checksum: 2aa4bb54caf2d622f1afdad09441695af2a83aa3fe8b8afa581d205e57ed4261c183c4d3877cee25794443fde5876417d859c108078ab788d6af7e4fe52eb66b + languageName: node + linkType: hard + +"ansi-regex@npm:^6.0.1": + version: 6.0.1 + resolution: "ansi-regex@npm:6.0.1" + checksum: 1ff8b7667cded1de4fa2c9ae283e979fc87036864317da86a2e546725f96406746411d0d85e87a2d12fa5abd715d90006de7fa4fa0477c92321ad3b4c7d4e169 + languageName: node + linkType: hard + +"ansi-styles@npm:^4.0.0, ansi-styles@npm:^4.1.0": + version: 4.3.0 + resolution: "ansi-styles@npm:4.3.0" + dependencies: + color-convert: "npm:^2.0.1" + checksum: 513b44c3b2105dd14cc42a19271e80f386466c4be574bccf60b627432f9198571ebf4ab1e4c3ba17347658f4ee1711c163d574248c0c1cdc2d5917a0ad582ec4 + languageName: node + linkType: hard + +"ansi-styles@npm:^6.1.0": + version: 6.2.1 + resolution: "ansi-styles@npm:6.2.1" + checksum: ef940f2f0ced1a6347398da88a91da7930c33ecac3c77b72c5905f8b8fe402c52e6fde304ff5347f616e27a742da3f1dc76de98f6866c69251ad0b07a66776d9 + languageName: node + linkType: hard + +"ansicolors@npm:^0.3.2": + version: 0.3.2 + resolution: "ansicolors@npm:0.3.2" + checksum: e84fae7ebc27ac96d9dbb57f35f078cd6dde1b7046b0f03f73dcefc9fbb1f2e82e3685d083466aded8faf038f9fa9ebb408d215282bcd7aaa301d5ac3c486815 + languageName: node + linkType: hard + +"aproba@npm:^1.0.3 || ^2.0.0": + version: 2.0.0 + resolution: "aproba@npm:2.0.0" + checksum: 5615cadcfb45289eea63f8afd064ab656006361020e1735112e346593856f87435e02d8dcc7ff0d11928bc7d425f27bc7c2a84f6c0b35ab0ff659c814c138a24 + languageName: node + linkType: hard + +"are-we-there-yet@npm:^3.0.0": + version: 3.0.1 + resolution: "are-we-there-yet@npm:3.0.1" + dependencies: + delegates: "npm:^1.0.0" + readable-stream: "npm:^3.6.0" + checksum: 52590c24860fa7173bedeb69a4c05fb573473e860197f618b9a28432ee4379049336727ae3a1f9c4cb083114601c1140cee578376164d0e651217a9843f9fe83 + languageName: node + linkType: hard + +"asynckit@npm:^0.4.0": + version: 0.4.0 + resolution: "asynckit@npm:0.4.0" + checksum: 7b78c451df768adba04e2d02e63e2d0bf3b07adcd6e42b4cf665cb7ce899bedd344c69a1dcbce355b5f972d597b25aaa1c1742b52cffd9caccb22f348114f6be + languageName: node + linkType: hard + +"axios@npm:^1.6.5": + version: 1.6.5 + resolution: "axios@npm:1.6.5" + dependencies: + follow-redirects: ^1.15.4 + form-data: ^4.0.0 + proxy-from-env: ^1.1.0 + checksum: e28d67b2d9134cb4608c44d8068b0678cfdccc652742e619006f27264a30c7aba13b2cd19c6f1f52ae195b5232734925928fb192d5c85feea7edd2f273df206d + languageName: node + linkType: hard + +"balanced-match@npm:^1.0.0": + version: 1.0.2 + resolution: "balanced-match@npm:1.0.2" + checksum: 9706c088a283058a8a99e0bf91b0a2f75497f185980d9ffa8b304de1d9e58ebda7c72c07ebf01dadedaac5b2907b2c6f566f660d62bd336c3468e960403b9d65 + languageName: node + linkType: hard + +"base-x@npm:^3.0.2": + version: 3.0.9 + resolution: "base-x@npm:3.0.9" + dependencies: + safe-buffer: "npm:^5.0.1" + checksum: 957101d6fd09e1903e846fd8f69fd7e5e3e50254383e61ab667c725866bec54e5ece5ba49ce385128ae48f9ec93a26567d1d5ebb91f4d56ef4a9cc0d5a5481e8 + languageName: node + linkType: hard + +"base-x@npm:^4.0.0": + version: 4.0.0 + resolution: "base-x@npm:4.0.0" + checksum: b25db9e07eb1998472a20557c7f00c797dc0595f79df95155ab74274e7fa98b9f2659b3ee547ac8773666b7f69540656793aeb97ad2b1ceccdb6fa5faaf69ac0 + languageName: node + linkType: hard + +"base64-js@npm:^1.3.1, base64-js@npm:^1.5.1": + version: 1.5.1 + resolution: "base64-js@npm:1.5.1" + checksum: 669632eb3745404c2f822a18fc3a0122d2f9a7a13f7fb8b5823ee19d1d2ff9ee5b52c53367176ea4ad093c332fd5ab4bd0ebae5a8e27917a4105a4cfc86b1005 + languageName: node + linkType: hard + +"bigint-buffer@npm:^1.1.5": + version: 1.1.5 + resolution: "bigint-buffer@npm:1.1.5" + dependencies: + bindings: "npm:^1.3.0" + node-gyp: "npm:latest" + checksum: d010c9f57758bcdaccb435d88b483ffcc95fe8bbc6e7fb3a44fb5221f29c894ffaf4a3c5a4a530e0e7d6608203c2cde9b79ee4f2386cd6d4462d1070bc8c9f4e + languageName: node + linkType: hard + +"bignumber.js@npm:^9.0.1": + version: 9.1.2 + resolution: "bignumber.js@npm:9.1.2" + checksum: 582c03af77ec9cb0ebd682a373ee6c66475db94a4325f92299621d544aa4bd45cb45fd60001610e94aef8ae98a0905fa538241d9638d4422d57abbeeac6fadaf + languageName: node + linkType: hard + +"bindings@npm:^1.3.0": + version: 1.5.0 + resolution: "bindings@npm:1.5.0" + dependencies: + file-uri-to-path: "npm:1.0.0" + checksum: 65b6b48095717c2e6105a021a7da4ea435aa8d3d3cd085cb9e85bcb6e5773cf318c4745c3f7c504412855940b585bdf9b918236612a1c7a7942491de176f1ae7 + languageName: node + linkType: hard + +"bn.js@npm:^5.1.2, bn.js@npm:^5.2.0, bn.js@npm:^5.2.1": + version: 5.2.1 + resolution: "bn.js@npm:5.2.1" + checksum: 3dd8c8d38055fedfa95c1d5fc3c99f8dd547b36287b37768db0abab3c239711f88ff58d18d155dd8ad902b0b0cee973747b7ae20ea12a09473272b0201c9edd3 + languageName: node + linkType: hard + +"borsh@npm:^0.7.0": + version: 0.7.0 + resolution: "borsh@npm:0.7.0" + dependencies: + bn.js: "npm:^5.2.0" + bs58: "npm:^4.0.0" + text-encoding-utf-8: "npm:^1.0.2" + checksum: e98bfb5f7cfb820819c2870b884dac58dd4b4ce6a86c286c8fbf5c9ca582e73a8c6094df67e81a28c418ff07a309c6b118b2e27fdfea83fd92b8100c741da0b5 + languageName: node + linkType: hard + +"brace-expansion@npm:^1.1.7": + version: 1.1.11 + resolution: "brace-expansion@npm:1.1.11" + dependencies: + balanced-match: "npm:^1.0.0" + concat-map: "npm:0.0.1" + checksum: faf34a7bb0c3fcf4b59c7808bc5d2a96a40988addf2e7e09dfbb67a2251800e0d14cd2bfc1aa79174f2f5095c54ff27f46fb1289fe2d77dac755b5eb3434cc07 + languageName: node + linkType: hard + +"brace-expansion@npm:^2.0.1": + version: 2.0.1 + resolution: "brace-expansion@npm:2.0.1" + dependencies: + balanced-match: "npm:^1.0.0" + checksum: a61e7cd2e8a8505e9f0036b3b6108ba5e926b4b55089eeb5550cd04a471fe216c96d4fe7e4c7f995c728c554ae20ddfc4244cad10aef255e72b62930afd233d1 + languageName: node + linkType: hard + +"braces@npm:^3.0.2": + version: 3.0.2 + resolution: "braces@npm:3.0.2" + dependencies: + fill-range: "npm:^7.0.1" + checksum: e2a8e769a863f3d4ee887b5fe21f63193a891c68b612ddb4b68d82d1b5f3ff9073af066c343e9867a393fe4c2555dcb33e89b937195feb9c1613d259edfcd459 + languageName: node + linkType: hard + +"bs58@npm:^4.0.0, bs58@npm:^4.0.1": + version: 4.0.1 + resolution: "bs58@npm:4.0.1" + dependencies: + base-x: "npm:^3.0.2" + checksum: b3c5365bb9e0c561e1a82f1a2d809a1a692059fae016be233a6127ad2f50a6b986467c3a50669ce4c18929dcccb297c5909314dd347a25a68c21b68eb3e95ac2 + languageName: node + linkType: hard + +"bs58@npm:^5.0.0": + version: 5.0.0 + resolution: "bs58@npm:5.0.0" + dependencies: + base-x: "npm:^4.0.0" + checksum: 2475cb0684e07077521aac718e604a13e0f891d58cff923d437a2f7e9e28703ab39fce9f84c7c703ab369815a675f11e3bd394d38643bfe8969fbe42e6833d45 + languageName: node + linkType: hard + +"buffer-layout@npm:^1.2.0, buffer-layout@npm:^1.2.2": + version: 1.2.2 + resolution: "buffer-layout@npm:1.2.2" + checksum: e5809ba275530bf4e52fd09558b7c2111fbda5b405124f581acf364261d9c154e271800271898cd40473f9bcbb42c31584efb04219bde549d3460ca4bafeaa07 + languageName: node + linkType: hard + +"buffer@npm:6.0.3, buffer@npm:^6.0.3, buffer@npm:~6.0.3": + version: 6.0.3 + resolution: "buffer@npm:6.0.3" + dependencies: + base64-js: "npm:^1.3.1" + ieee754: "npm:^1.2.1" + checksum: 5ad23293d9a731e4318e420025800b42bf0d264004c0286c8cc010af7a270c7a0f6522e84f54b9ad65cbd6db20b8badbfd8d2ebf4f80fa03dab093b89e68c3f9 + languageName: node + linkType: hard + +"bufferutil@npm:^4.0.1": + version: 4.0.7 + resolution: "bufferutil@npm:4.0.7" + dependencies: + node-gyp: "npm:latest" + node-gyp-build: "npm:^4.3.0" + checksum: f75aa87e3d1b99b87a95f60a855e63f70af07b57fb8443e75a2ddfef2e47788d130fdd46e3a78fd7e0c10176082b26dfbed970c5b8632e1cc299cafa0e93ce45 + languageName: node + linkType: hard + +"cacache@npm:^17.0.0": + version: 17.1.4 + resolution: "cacache@npm:17.1.4" + dependencies: + "@npmcli/fs": "npm:^3.1.0" + fs-minipass: "npm:^3.0.0" + glob: "npm:^10.2.2" + lru-cache: "npm:^7.7.1" + minipass: "npm:^7.0.3" + minipass-collect: "npm:^1.0.2" + minipass-flush: "npm:^1.0.5" + minipass-pipeline: "npm:^1.2.4" + p-map: "npm:^4.0.0" + ssri: "npm:^10.0.0" + tar: "npm:^6.1.11" + unique-filename: "npm:^3.0.0" + checksum: b7751df756656954a51201335addced8f63fc53266fa56392c9f5ae83c8d27debffb4458ac2d168a744a4517ec3f2163af05c20097f93d17bdc2dc8a385e14a6 + languageName: node + linkType: hard + +"camelcase@npm:^6.3.0": + version: 6.3.0 + resolution: "camelcase@npm:6.3.0" + checksum: 8c96818a9076434998511251dcb2761a94817ea17dbdc37f47ac080bd088fc62c7369429a19e2178b993497132c8cbcf5cc1f44ba963e76782ba469c0474938d + languageName: node + linkType: hard + +"chalk@npm:^4.1.0": + version: 4.1.2 + resolution: "chalk@npm:4.1.2" + dependencies: + ansi-styles: "npm:^4.1.0" + supports-color: "npm:^7.1.0" + checksum: fe75c9d5c76a7a98d45495b91b2172fa3b7a09e0cc9370e5c8feb1c567b85c4288e2b3fded7cfdd7359ac28d6b3844feb8b82b8686842e93d23c827c417e83fc + languageName: node + linkType: hard + +"chownr@npm:^2.0.0": + version: 2.0.0 + resolution: "chownr@npm:2.0.0" + checksum: c57cf9dd0791e2f18a5ee9c1a299ae6e801ff58fee96dc8bfd0dcb4738a6ce58dd252a3605b1c93c6418fe4f9d5093b28ffbf4d66648cb2a9c67eaef9679be2f + languageName: node + linkType: hard + +"clean-stack@npm:^2.0.0": + version: 2.2.0 + resolution: "clean-stack@npm:2.2.0" + checksum: 2ac8cd2b2f5ec986a3c743935ec85b07bc174d5421a5efc8017e1f146a1cf5f781ae962618f416352103b32c9cd7e203276e8c28241bbe946160cab16149fb68 + languageName: node + linkType: hard + +"color-convert@npm:^2.0.1": + version: 2.0.1 + resolution: "color-convert@npm:2.0.1" + dependencies: + color-name: "npm:~1.1.4" + checksum: 79e6bdb9fd479a205c71d89574fccfb22bd9053bd98c6c4d870d65c132e5e904e6034978e55b43d69fcaa7433af2016ee203ce76eeba9cfa554b373e7f7db336 + languageName: node + linkType: hard + +"color-name@npm:~1.1.4": + version: 1.1.4 + resolution: "color-name@npm:1.1.4" + checksum: b0445859521eb4021cd0fb0cc1a75cecf67fceecae89b63f62b201cca8d345baf8b952c966862a9d9a2632987d4f6581f0ec8d957dfacece86f0a7919316f610 + languageName: node + linkType: hard + +"color-support@npm:^1.1.3": + version: 1.1.3 + resolution: "color-support@npm:1.1.3" + bin: + color-support: bin.js + checksum: 9b7356817670b9a13a26ca5af1c21615463b500783b739b7634a0c2047c16cef4b2865d7576875c31c3cddf9dd621fa19285e628f20198b233a5cfdda6d0793b + languageName: node + linkType: hard + +"combined-stream@npm:^1.0.8": + version: 1.0.8 + resolution: "combined-stream@npm:1.0.8" + dependencies: + delayed-stream: "npm:~1.0.0" + checksum: 49fa4aeb4916567e33ea81d088f6584749fc90c7abec76fd516bf1c5aa5c79f3584b5ba3de6b86d26ddd64bae5329c4c7479343250cfe71c75bb366eae53bb7c + languageName: node + linkType: hard + +"commander@npm:^2.20.3": + version: 2.20.3 + resolution: "commander@npm:2.20.3" + checksum: ab8c07884e42c3a8dbc5dd9592c606176c7eb5c1ca5ff274bcf907039b2c41de3626f684ea75ccf4d361ba004bbaff1f577d5384c155f3871e456bdf27becf9e + languageName: node + linkType: hard + +"concat-map@npm:0.0.1": + version: 0.0.1 + resolution: "concat-map@npm:0.0.1" + checksum: 902a9f5d8967a3e2faf138d5cb784b9979bad2e6db5357c5b21c568df4ebe62bcb15108af1b2253744844eb964fc023fbd9afbbbb6ddd0bcc204c6fb5b7bf3af + languageName: node + linkType: hard + +"console-control-strings@npm:^1.1.0": + version: 1.1.0 + resolution: "console-control-strings@npm:1.1.0" + checksum: 8755d76787f94e6cf79ce4666f0c5519906d7f5b02d4b884cf41e11dcd759ed69c57da0670afd9236d229a46e0f9cf519db0cd829c6dca820bb5a5c3def584ed + languageName: node + linkType: hard + +"cross-fetch@npm:^3.1.5": + version: 3.1.8 + resolution: "cross-fetch@npm:3.1.8" + dependencies: + node-fetch: "npm:^2.6.12" + checksum: 78f993fa099eaaa041122ab037fe9503ecbbcb9daef234d1d2e0b9230a983f64d645d088c464e21a247b825a08dc444a6e7064adfa93536d3a9454b4745b3632 + languageName: node + linkType: hard + +"cross-spawn@npm:^7.0.0": + version: 7.0.3 + resolution: "cross-spawn@npm:7.0.3" + dependencies: + path-key: "npm:^3.1.0" + shebang-command: "npm:^2.0.0" + which: "npm:^2.0.1" + checksum: 671cc7c7288c3a8406f3c69a3ae2fc85555c04169e9d611def9a675635472614f1c0ed0ef80955d5b6d4e724f6ced67f0ad1bb006c2ea643488fcfef994d7f52 + languageName: node + linkType: hard + +"crypto-hash@npm:^1.3.0": + version: 1.3.0 + resolution: "crypto-hash@npm:1.3.0" + checksum: a3a507e0d2b18fbd2da8088a1c62d0c53c009a99bbfa6d851cac069734ffa546922fa51bdd776d006459701cdda873463e5059ece3431aca048fd99e7573d138 + languageName: node + linkType: hard + +"debug@npm:4, debug@npm:^4.3.3, debug@npm:^4.3.4": + version: 4.3.4 + resolution: "debug@npm:4.3.4" + dependencies: + ms: "npm:2.1.2" + peerDependenciesMeta: + supports-color: + optional: true + checksum: 3dbad3f94ea64f34431a9cbf0bafb61853eda57bff2880036153438f50fb5a84f27683ba0d8e5426bf41a8c6ff03879488120cf5b3a761e77953169c0600a708 + languageName: node + linkType: hard + +"delay@npm:^5.0.0": + version: 5.0.0 + resolution: "delay@npm:5.0.0" + checksum: 62f151151ecfde0d9afbb8a6be37a6d103c4cb24f35a20ef3fe56f920b0d0d0bb02bc9c0a3084d0179ef669ca332b91155f2ee4d9854622cd2cdba5fc95285f9 + languageName: node + linkType: hard + +"delayed-stream@npm:~1.0.0": + version: 1.0.0 + resolution: "delayed-stream@npm:1.0.0" + checksum: 46fe6e83e2cb1d85ba50bd52803c68be9bd953282fa7096f51fc29edd5d67ff84ff753c51966061e5ba7cb5e47ef6d36a91924eddb7f3f3483b1c560f77a0020 + languageName: node + linkType: hard + +"delegates@npm:^1.0.0": + version: 1.0.0 + resolution: "delegates@npm:1.0.0" + checksum: a51744d9b53c164ba9c0492471a1a2ffa0b6727451bdc89e31627fdf4adda9d51277cfcbfb20f0a6f08ccb3c436f341df3e92631a3440226d93a8971724771fd + languageName: node + linkType: hard + +"dot-case@npm:^3.0.4": + version: 3.0.4 + resolution: "dot-case@npm:3.0.4" + dependencies: + no-case: "npm:^3.0.4" + tslib: "npm:^2.0.3" + checksum: a65e3519414856df0228b9f645332f974f2bf5433370f544a681122eab59e66038fc3349b4be1cdc47152779dac71a5864f1ccda2f745e767c46e9c6543b1169 + languageName: node + linkType: hard + +"eastasianwidth@npm:^0.2.0": + version: 0.2.0 + resolution: "eastasianwidth@npm:0.2.0" + checksum: 7d00d7cd8e49b9afa762a813faac332dee781932d6f2c848dc348939c4253f1d4564341b7af1d041853bc3f32c2ef141b58e0a4d9862c17a7f08f68df1e0f1ed + languageName: node + linkType: hard + +"emoji-regex@npm:^8.0.0": + version: 8.0.0 + resolution: "emoji-regex@npm:8.0.0" + checksum: d4c5c39d5a9868b5fa152f00cada8a936868fd3367f33f71be515ecee4c803132d11b31a6222b2571b1e5f7e13890156a94880345594d0ce7e3c9895f560f192 + languageName: node + linkType: hard + +"emoji-regex@npm:^9.2.2": + version: 9.2.2 + resolution: "emoji-regex@npm:9.2.2" + checksum: 8487182da74aabd810ac6d6f1994111dfc0e331b01271ae01ec1eb0ad7b5ecc2bbbbd2f053c05cb55a1ac30449527d819bbfbf0e3de1023db308cbcb47f86601 + languageName: node + linkType: hard + +"encoding@npm:^0.1.13": + version: 0.1.13 + resolution: "encoding@npm:0.1.13" + dependencies: + iconv-lite: "npm:^0.6.2" + checksum: bb98632f8ffa823996e508ce6a58ffcf5856330fde839ae42c9e1f436cc3b5cc651d4aeae72222916545428e54fd0f6aa8862fd8d25bdbcc4589f1e3f3715e7f + languageName: node + linkType: hard + +"enhanced-resolve@npm:^5.0.0": + version: 5.15.0 + resolution: "enhanced-resolve@npm:5.15.0" + dependencies: + graceful-fs: "npm:^4.2.4" + tapable: "npm:^2.2.0" + checksum: fbd8cdc9263be71cc737aa8a7d6c57b43d6aa38f6cc75dde6fcd3598a130cc465f979d2f4d01bb3bf475acb43817749c79f8eef9be048683602ca91ab52e4f11 + languageName: node + linkType: hard + +"env-paths@npm:^2.2.0": + version: 2.2.1 + resolution: "env-paths@npm:2.2.1" + checksum: 65b5df55a8bab92229ab2b40dad3b387fad24613263d103a97f91c9fe43ceb21965cd3392b1ccb5d77088021e525c4e0481adb309625d0cb94ade1d1fb8dc17e + languageName: node + linkType: hard + +"err-code@npm:^2.0.2": + version: 2.0.3 + resolution: "err-code@npm:2.0.3" + checksum: 8b7b1be20d2de12d2255c0bc2ca638b7af5171142693299416e6a9339bd7d88fc8d7707d913d78e0993176005405a236b066b45666b27b797252c771156ace54 + languageName: node + linkType: hard + +"es6-promise@npm:^4.0.3": + version: 4.2.8 + resolution: "es6-promise@npm:4.2.8" + checksum: 95614a88873611cb9165a85d36afa7268af5c03a378b35ca7bda9508e1d4f1f6f19a788d4bc755b3fd37c8ebba40782018e02034564ff24c9d6fa37e959ad57d + languageName: node + linkType: hard + +"es6-promisify@npm:^5.0.0": + version: 5.0.0 + resolution: "es6-promisify@npm:5.0.0" + dependencies: + es6-promise: "npm:^4.0.3" + checksum: fbed9d791598831413be84a5374eca8c24800ec71a16c1c528c43a98e2dadfb99331483d83ae6094ddb9b87e6f799a15d1553cebf756047e0865c753bc346b92 + languageName: node + linkType: hard + +"eventemitter3@npm:^4.0.7": + version: 4.0.7 + resolution: "eventemitter3@npm:4.0.7" + checksum: 1875311c42fcfe9c707b2712c32664a245629b42bb0a5a84439762dd0fd637fc54d078155ea83c2af9e0323c9ac13687e03cfba79b03af9f40c89b4960099374 + languageName: node + linkType: hard + +"exponential-backoff@npm:^3.1.1": + version: 3.1.1 + resolution: "exponential-backoff@npm:3.1.1" + checksum: 3d21519a4f8207c99f7457287291316306255a328770d320b401114ec8481986e4e467e854cb9914dd965e0a1ca810a23ccb559c642c88f4c7f55c55778a9b48 + languageName: node + linkType: hard + +"eyes@npm:^0.1.8": + version: 0.1.8 + resolution: "eyes@npm:0.1.8" + checksum: c31703a92bf36ba75ee8d379ee7985c24ee6149f3a6175f44cec7a05b178c38bce9836d3ca48c9acb0329a960ac2c4b2ead4e60cdd4fe6e8c92cad7cd6913687 + languageName: node + linkType: hard + +"fast-stable-stringify@npm:^1.0.0": + version: 1.0.0 + resolution: "fast-stable-stringify@npm:1.0.0" + checksum: ef1203d246a7e8ac15e2bfbda0a89fa375947bccf9f7910be0ea759856dbe8ea5024a0d8cc2cceabe18a9cb67e95927b78bb6173a3ae37ec55a518cf36e5244b + languageName: node + linkType: hard + +"file-uri-to-path@npm:1.0.0": + version: 1.0.0 + resolution: "file-uri-to-path@npm:1.0.0" + checksum: b648580bdd893a008c92c7ecc96c3ee57a5e7b6c4c18a9a09b44fb5d36d79146f8e442578bc0e173dc027adf3987e254ba1dfd6e3ec998b7c282873010502144 + languageName: node + linkType: hard + +"fill-range@npm:^7.0.1": + version: 7.0.1 + resolution: "fill-range@npm:7.0.1" + dependencies: + to-regex-range: "npm:^5.0.1" + checksum: cc283f4e65b504259e64fd969bcf4def4eb08d85565e906b7d36516e87819db52029a76b6363d0f02d0d532f0033c9603b9e2d943d56ee3b0d4f7ad3328ff917 + languageName: node + linkType: hard + +"follow-redirects@npm:^1.15.4": + version: 1.15.5 + resolution: "follow-redirects@npm:1.15.5" + peerDependenciesMeta: + debug: + optional: true + checksum: 5ca49b5ce6f44338cbfc3546823357e7a70813cecc9b7b768158a1d32c1e62e7407c944402a918ea8c38ae2e78266312d617dc68783fac502cbb55e1047b34ec + languageName: node + linkType: hard + +"foreground-child@npm:^3.1.0": + version: 3.1.1 + resolution: "foreground-child@npm:3.1.1" + dependencies: + cross-spawn: "npm:^7.0.0" + signal-exit: "npm:^4.0.1" + checksum: 139d270bc82dc9e6f8bc045fe2aae4001dc2472157044fdfad376d0a3457f77857fa883c1c8b21b491c6caade9a926a4bed3d3d2e8d3c9202b151a4cbbd0bcd5 + languageName: node + linkType: hard + +"form-data@npm:^4.0.0": + version: 4.0.0 + resolution: "form-data@npm:4.0.0" + dependencies: + asynckit: "npm:^0.4.0" + combined-stream: "npm:^1.0.8" + mime-types: "npm:^2.1.12" + checksum: 01135bf8675f9d5c61ff18e2e2932f719ca4de964e3be90ef4c36aacfc7b9cb2fceb5eca0b7e0190e3383fe51c5b37f4cb80b62ca06a99aaabfcfd6ac7c9328c + languageName: node + linkType: hard + +"fs-minipass@npm:^2.0.0": + version: 2.1.0 + resolution: "fs-minipass@npm:2.1.0" + dependencies: + minipass: "npm:^3.0.0" + checksum: 1b8d128dae2ac6cc94230cc5ead341ba3e0efaef82dab46a33d171c044caaa6ca001364178d42069b2809c35a1c3c35079a32107c770e9ffab3901b59af8c8b1 + languageName: node + linkType: hard + +"fs-minipass@npm:^3.0.0": + version: 3.0.3 + resolution: "fs-minipass@npm:3.0.3" + dependencies: + minipass: "npm:^7.0.3" + checksum: 8722a41109130851d979222d3ec88aabaceeaaf8f57b2a8f744ef8bd2d1ce95453b04a61daa0078822bc5cd21e008814f06fe6586f56fef511e71b8d2394d802 + languageName: node + linkType: hard + +"fs.realpath@npm:^1.0.0": + version: 1.0.0 + resolution: "fs.realpath@npm:1.0.0" + checksum: 99ddea01a7e75aa276c250a04eedeffe5662bce66c65c07164ad6264f9de18fb21be9433ead460e54cff20e31721c811f4fb5d70591799df5f85dce6d6746fd0 + languageName: node + linkType: hard + +"gauge@npm:^4.0.3": + version: 4.0.4 + resolution: "gauge@npm:4.0.4" + dependencies: + aproba: "npm:^1.0.3 || ^2.0.0" + color-support: "npm:^1.1.3" + console-control-strings: "npm:^1.1.0" + has-unicode: "npm:^2.0.1" + signal-exit: "npm:^3.0.7" + string-width: "npm:^4.2.3" + strip-ansi: "npm:^6.0.1" + wide-align: "npm:^1.1.5" + checksum: 788b6bfe52f1dd8e263cda800c26ac0ca2ff6de0b6eee2fe0d9e3abf15e149b651bd27bf5226be10e6e3edb5c4e5d5985a5a1a98137e7a892f75eff76467ad2d + languageName: node + linkType: hard + +"git-format-staged@npm:^2.1.3": + version: 2.1.3 + resolution: "git-format-staged@npm:2.1.3" + bin: + git-format-staged: git-format-staged + checksum: 749da68f0d9bf24db53b87a5f1613fc1a8790801d7c3ccb31d02b94d99f4cf2450126ef565f16adcc0649fbbf90dc44b4f009d4f99ff8a26921ba754bdb09b31 + languageName: node + linkType: hard + +"glob@npm:^10.2.2": + version: 10.3.3 + resolution: "glob@npm:10.3.3" + dependencies: + foreground-child: "npm:^3.1.0" + jackspeak: "npm:^2.0.3" + minimatch: "npm:^9.0.1" + minipass: "npm:^5.0.0 || ^6.0.2 || ^7.0.0" + path-scurry: "npm:^1.10.1" + bin: + glob: dist/cjs/src/bin.js + checksum: 29190d3291f422da0cb40b77a72fc8d2c51a36524e99b8bf412548b7676a6627489528b57250429612b6eec2e6fe7826d328451d3e694a9d15e575389308ec53 + languageName: node + linkType: hard + +"glob@npm:^7.1.3, glob@npm:^7.1.4": + version: 7.2.3 + resolution: "glob@npm:7.2.3" + dependencies: + fs.realpath: "npm:^1.0.0" + inflight: "npm:^1.0.4" + inherits: "npm:2" + minimatch: "npm:^3.1.1" + once: "npm:^1.3.0" + path-is-absolute: "npm:^1.0.0" + checksum: 29452e97b38fa704dabb1d1045350fb2467cf0277e155aa9ff7077e90ad81d1ea9d53d3ee63bd37c05b09a065e90f16aec4a65f5b8de401d1dac40bc5605d133 + languageName: node + linkType: hard + +"graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6": + version: 4.2.11 + resolution: "graceful-fs@npm:4.2.11" + checksum: ac85f94da92d8eb6b7f5a8b20ce65e43d66761c55ce85ac96df6865308390da45a8d3f0296dd3a663de65d30ba497bd46c696cc1e248c72b13d6d567138a4fc7 + languageName: node + linkType: hard + +"has-flag@npm:^4.0.0": + version: 4.0.0 + resolution: "has-flag@npm:4.0.0" + checksum: 261a1357037ead75e338156b1f9452c016a37dcd3283a972a30d9e4a87441ba372c8b81f818cd0fbcd9c0354b4ae7e18b9e1afa1971164aef6d18c2b6095a8ad + languageName: node + linkType: hard + +"has-unicode@npm:^2.0.1": + version: 2.0.1 + resolution: "has-unicode@npm:2.0.1" + checksum: 1eab07a7436512db0be40a710b29b5dc21fa04880b7f63c9980b706683127e3c1b57cb80ea96d47991bdae2dfe479604f6a1ba410106ee1046a41d1bd0814400 + languageName: node + linkType: hard + +"http-cache-semantics@npm:^4.1.1": + version: 4.1.1 + resolution: "http-cache-semantics@npm:4.1.1" + checksum: 83ac0bc60b17a3a36f9953e7be55e5c8f41acc61b22583060e8dedc9dd5e3607c823a88d0926f9150e571f90946835c7fe150732801010845c72cd8bbff1a236 + languageName: node + linkType: hard + +"http-proxy-agent@npm:^5.0.0": + version: 5.0.0 + resolution: "http-proxy-agent@npm:5.0.0" + dependencies: + "@tootallnate/once": "npm:2" + agent-base: "npm:6" + debug: "npm:4" + checksum: e2ee1ff1656a131953839b2a19cd1f3a52d97c25ba87bd2559af6ae87114abf60971e498021f9b73f9fd78aea8876d1fb0d4656aac8a03c6caa9fc175f22b786 + languageName: node + linkType: hard + +"https-proxy-agent@npm:^5.0.0": + version: 5.0.1 + resolution: "https-proxy-agent@npm:5.0.1" + dependencies: + agent-base: "npm:6" + debug: "npm:4" + checksum: 571fccdf38184f05943e12d37d6ce38197becdd69e58d03f43637f7fa1269cf303a7d228aa27e5b27bbd3af8f09fd938e1c91dcfefff2df7ba77c20ed8dfc765 + languageName: node + linkType: hard + +"humanize-ms@npm:^1.2.1": + version: 1.2.1 + resolution: "humanize-ms@npm:1.2.1" + dependencies: + ms: "npm:^2.0.0" + checksum: 9c7a74a2827f9294c009266c82031030eae811ca87b0da3dceb8d6071b9bde22c9f3daef0469c3c533cc67a97d8a167cd9fc0389350e5f415f61a79b171ded16 + languageName: node + linkType: hard + +"iconv-lite@npm:^0.6.2": + version: 0.6.3 + resolution: "iconv-lite@npm:0.6.3" + dependencies: + safer-buffer: "npm:>= 2.1.2 < 3.0.0" + checksum: 3f60d47a5c8fc3313317edfd29a00a692cc87a19cac0159e2ce711d0ebc9019064108323b5e493625e25594f11c6236647d8e256fbe7a58f4a3b33b89e6d30bf + languageName: node + linkType: hard + +"ieee754@npm:^1.2.1": + version: 1.2.1 + resolution: "ieee754@npm:1.2.1" + checksum: 5144c0c9815e54ada181d80a0b810221a253562422e7c6c3a60b1901154184f49326ec239d618c416c1c5945a2e197107aee8d986a3dd836b53dffefd99b5e7e + languageName: node + linkType: hard + +"imurmurhash@npm:^0.1.4": + version: 0.1.4 + resolution: "imurmurhash@npm:0.1.4" + checksum: 7cae75c8cd9a50f57dadd77482359f659eaebac0319dd9368bcd1714f55e65badd6929ca58569da2b6494ef13fdd5598cd700b1eba23f8b79c5f19d195a3ecf7 + languageName: node + linkType: hard + +"indent-string@npm:^4.0.0": + version: 4.0.0 + resolution: "indent-string@npm:4.0.0" + checksum: 824cfb9929d031dabf059bebfe08cf3137365e112019086ed3dcff6a0a7b698cb80cf67ccccde0e25b9e2d7527aa6cc1fed1ac490c752162496caba3e6699612 + languageName: node + linkType: hard + +"inflight@npm:^1.0.4": + version: 1.0.6 + resolution: "inflight@npm:1.0.6" + dependencies: + once: "npm:^1.3.0" + wrappy: "npm:1" + checksum: f4f76aa072ce19fae87ce1ef7d221e709afb59d445e05d47fba710e85470923a75de35bfae47da6de1b18afc3ce83d70facf44cfb0aff89f0a3f45c0a0244dfd + languageName: node + linkType: hard + +"inherits@npm:2, inherits@npm:^2.0.3": + version: 2.0.4 + resolution: "inherits@npm:2.0.4" + checksum: 4a48a733847879d6cf6691860a6b1e3f0f4754176e4d71494c41f3475553768b10f84b5ce1d40fbd0e34e6bfbb864ee35858ad4dd2cf31e02fc4a154b724d7f1 + languageName: node + linkType: hard + +"ip@npm:^2.0.0": + version: 2.0.0 + resolution: "ip@npm:2.0.0" + checksum: cfcfac6b873b701996d71ec82a7dd27ba92450afdb421e356f44044ed688df04567344c36cbacea7d01b1c39a4c732dc012570ebe9bebfb06f27314bca625349 + languageName: node + linkType: hard + +"is-fullwidth-code-point@npm:^3.0.0": + version: 3.0.0 + resolution: "is-fullwidth-code-point@npm:3.0.0" + checksum: 44a30c29457c7fb8f00297bce733f0a64cd22eca270f83e58c105e0d015e45c019491a4ab2faef91ab51d4738c670daff901c799f6a700e27f7314029e99e348 + languageName: node + linkType: hard + +"is-lambda@npm:^1.0.1": + version: 1.0.1 + resolution: "is-lambda@npm:1.0.1" + checksum: 93a32f01940220532e5948538699ad610d5924ac86093fcee83022252b363eb0cc99ba53ab084a04e4fb62bf7b5731f55496257a4c38adf87af9c4d352c71c35 + languageName: node + linkType: hard + +"is-number@npm:^7.0.0": + version: 7.0.0 + resolution: "is-number@npm:7.0.0" + checksum: 456ac6f8e0f3111ed34668a624e45315201dff921e5ac181f8ec24923b99e9f32ca1a194912dc79d539c97d33dba17dc635202ff0b2cf98326f608323276d27a + languageName: node + linkType: hard + +"isexe@npm:^2.0.0": + version: 2.0.0 + resolution: "isexe@npm:2.0.0" + checksum: 26bf6c5480dda5161c820c5b5c751ae1e766c587b1f951ea3fcfc973bafb7831ae5b54a31a69bd670220e42e99ec154475025a468eae58ea262f813fdc8d1c62 + languageName: node + linkType: hard + +"isomorphic-ws@npm:^4.0.1": + version: 4.0.1 + resolution: "isomorphic-ws@npm:4.0.1" + peerDependencies: + ws: "*" + checksum: d7190eadefdc28bdb93d67b5f0c603385aaf87724fa2974abb382ac1ec9756ed2cfb27065cbe76122879c2d452e2982bc4314317f3d6c737ddda6c047328771a + languageName: node + linkType: hard + +"jackspeak@npm:^2.0.3": + version: 2.3.1 + resolution: "jackspeak@npm:2.3.1" + dependencies: + "@isaacs/cliui": "npm:^8.0.2" + "@pkgjs/parseargs": "npm:^0.11.0" + dependenciesMeta: + "@pkgjs/parseargs": + optional: true + checksum: 34ea4d618d8d36ac104fe1053c85dfb6a63306cfe87e157ef42f18a7aa30027887370a4e163dd4993e45c6bf8a8ae003bf8476fdb8538e8ee5cd1938c27b15d0 + languageName: node + linkType: hard + +"jayson@npm:^4.1.0": + version: 4.1.0 + resolution: "jayson@npm:4.1.0" + dependencies: + "@types/connect": "npm:^3.4.33" + "@types/node": "npm:^12.12.54" + "@types/ws": "npm:^7.4.4" + JSONStream: "npm:^1.3.5" + commander: "npm:^2.20.3" + delay: "npm:^5.0.0" + es6-promisify: "npm:^5.0.0" + eyes: "npm:^0.1.8" + isomorphic-ws: "npm:^4.0.1" + json-stringify-safe: "npm:^5.0.1" + uuid: "npm:^8.3.2" + ws: "npm:^7.4.5" + bin: + jayson: bin/jayson.js + checksum: 86464322fbdc6db65d2bb4fc278cb6c86fad5c2a506065490d39459f09ba0d30f2b4fb740b33828a1424791419b6c8bd295dc54d361a4ad959bf70cc62b1ca7e + languageName: node + linkType: hard + +"js-sha256@npm:^0.9.0": + version: 0.9.0 + resolution: "js-sha256@npm:0.9.0" + checksum: ffad54b3373f81581e245866abfda50a62c483803a28176dd5c28fd2d313e0bdf830e77dac7ff8afd193c53031618920f3d98daf21cbbe80082753ab639c0365 + languageName: node + linkType: hard + +"json-stringify-safe@npm:^5.0.1": + version: 5.0.1 + resolution: "json-stringify-safe@npm:5.0.1" + checksum: 48ec0adad5280b8a96bb93f4563aa1667fd7a36334f79149abd42446d0989f2ddc58274b479f4819f1f00617957e6344c886c55d05a4e15ebb4ab931e4a6a8ee + languageName: node + linkType: hard + +"jsonparse@npm:^1.2.0": + version: 1.3.1 + resolution: "jsonparse@npm:1.3.1" + checksum: 6514a7be4674ebf407afca0eda3ba284b69b07f9958a8d3113ef1005f7ec610860c312be067e450c569aab8b89635e332cee3696789c750692bb60daba627f4d + languageName: node + linkType: hard + +"lower-case@npm:^2.0.2": + version: 2.0.2 + resolution: "lower-case@npm:2.0.2" + dependencies: + tslib: "npm:^2.0.3" + checksum: 83a0a5f159ad7614bee8bf976b96275f3954335a84fad2696927f609ddae902802c4f3312d86668722e668bef41400254807e1d3a7f2e8c3eede79691aa1f010 + languageName: node + linkType: hard + +"lru-cache@npm:^6.0.0": + version: 6.0.0 + resolution: "lru-cache@npm:6.0.0" + dependencies: + yallist: "npm:^4.0.0" + checksum: f97f499f898f23e4585742138a22f22526254fdba6d75d41a1c2526b3b6cc5747ef59c5612ba7375f42aca4f8461950e925ba08c991ead0651b4918b7c978297 + languageName: node + linkType: hard + +"lru-cache@npm:^7.7.1": + version: 7.18.3 + resolution: "lru-cache@npm:7.18.3" + checksum: e550d772384709deea3f141af34b6d4fa392e2e418c1498c078de0ee63670f1f46f5eee746e8ef7e69e1c895af0d4224e62ee33e66a543a14763b0f2e74c1356 + languageName: node + linkType: hard + +"lru-cache@npm:^9.1.1 || ^10.0.0": + version: 10.0.1 + resolution: "lru-cache@npm:10.0.1" + checksum: 06f8d0e1ceabd76bb6f644a26dbb0b4c471b79c7b514c13c6856113879b3bf369eb7b497dad4ff2b7e2636db202412394865b33c332100876d838ad1372f0181 + languageName: node + linkType: hard + +"make-fetch-happen@npm:^11.0.3": + version: 11.1.1 + resolution: "make-fetch-happen@npm:11.1.1" + dependencies: + agentkeepalive: "npm:^4.2.1" + cacache: "npm:^17.0.0" + http-cache-semantics: "npm:^4.1.1" + http-proxy-agent: "npm:^5.0.0" + https-proxy-agent: "npm:^5.0.0" + is-lambda: "npm:^1.0.1" + lru-cache: "npm:^7.7.1" + minipass: "npm:^5.0.0" + minipass-fetch: "npm:^3.0.0" + minipass-flush: "npm:^1.0.5" + minipass-pipeline: "npm:^1.2.4" + negotiator: "npm:^0.6.3" + promise-retry: "npm:^2.0.1" + socks-proxy-agent: "npm:^7.0.0" + ssri: "npm:^10.0.0" + checksum: 7268bf274a0f6dcf0343829489a4506603ff34bd0649c12058753900b0eb29191dce5dba12680719a5d0a983d3e57810f594a12f3c18494e93a1fbc6348a4540 + languageName: node + linkType: hard + +"micromatch@npm:^4.0.0": + version: 4.0.5 + resolution: "micromatch@npm:4.0.5" + dependencies: + braces: "npm:^3.0.2" + picomatch: "npm:^2.3.1" + checksum: 02a17b671c06e8fefeeb6ef996119c1e597c942e632a21ef589154f23898c9c6a9858526246abb14f8bca6e77734aa9dcf65476fca47cedfb80d9577d52843fc + languageName: node + linkType: hard + +"mime-db@npm:1.52.0": + version: 1.52.0 + resolution: "mime-db@npm:1.52.0" + checksum: 0d99a03585f8b39d68182803b12ac601d9c01abfa28ec56204fa330bc9f3d1c5e14beb049bafadb3dbdf646dfb94b87e24d4ec7b31b7279ef906a8ea9b6a513f + languageName: node + linkType: hard + +"mime-types@npm:^2.1.12": + version: 2.1.35 + resolution: "mime-types@npm:2.1.35" + dependencies: + mime-db: "npm:1.52.0" + checksum: 89a5b7f1def9f3af5dad6496c5ed50191ae4331cc5389d7c521c8ad28d5fdad2d06fd81baf38fed813dc4e46bb55c8145bb0ff406330818c9cf712fb2e9b3836 + languageName: node + linkType: hard + +"minimatch@npm:^3.1.1": + version: 3.1.2 + resolution: "minimatch@npm:3.1.2" + dependencies: + brace-expansion: "npm:^1.1.7" + checksum: c154e566406683e7bcb746e000b84d74465b3a832c45d59912b9b55cd50dee66e5c4b1e5566dba26154040e51672f9aa450a9aef0c97cfc7336b78b7afb9540a + languageName: node + linkType: hard + +"minimatch@npm:^9.0.1": + version: 9.0.3 + resolution: "minimatch@npm:9.0.3" + dependencies: + brace-expansion: "npm:^2.0.1" + checksum: 253487976bf485b612f16bf57463520a14f512662e592e95c571afdab1442a6a6864b6c88f248ce6fc4ff0b6de04ac7aa6c8bb51e868e99d1d65eb0658a708b5 + languageName: node + linkType: hard + +"minipass-collect@npm:^1.0.2": + version: 1.0.2 + resolution: "minipass-collect@npm:1.0.2" + dependencies: + minipass: "npm:^3.0.0" + checksum: 14df761028f3e47293aee72888f2657695ec66bd7d09cae7ad558da30415fdc4752bbfee66287dcc6fd5e6a2fa3466d6c484dc1cbd986525d9393b9523d97f10 + languageName: node + linkType: hard + +"minipass-fetch@npm:^3.0.0": + version: 3.0.4 + resolution: "minipass-fetch@npm:3.0.4" + dependencies: + encoding: "npm:^0.1.13" + minipass: "npm:^7.0.3" + minipass-sized: "npm:^1.0.3" + minizlib: "npm:^2.1.2" + dependenciesMeta: + encoding: + optional: true + checksum: af7aad15d5c128ab1ebe52e043bdf7d62c3c6f0cecb9285b40d7b395e1375b45dcdfd40e63e93d26a0e8249c9efd5c325c65575aceee192883970ff8cb11364a + languageName: node + linkType: hard + +"minipass-flush@npm:^1.0.5": + version: 1.0.5 + resolution: "minipass-flush@npm:1.0.5" + dependencies: + minipass: "npm:^3.0.0" + checksum: 56269a0b22bad756a08a94b1ffc36b7c9c5de0735a4dd1ab2b06c066d795cfd1f0ac44a0fcae13eece5589b908ecddc867f04c745c7009be0b566421ea0944cf + languageName: node + linkType: hard + +"minipass-pipeline@npm:^1.2.4": + version: 1.2.4 + resolution: "minipass-pipeline@npm:1.2.4" + dependencies: + minipass: "npm:^3.0.0" + checksum: b14240dac0d29823c3d5911c286069e36d0b81173d7bdf07a7e4a91ecdef92cdff4baaf31ea3746f1c61e0957f652e641223970870e2353593f382112257971b + languageName: node + linkType: hard + +"minipass-sized@npm:^1.0.3": + version: 1.0.3 + resolution: "minipass-sized@npm:1.0.3" + dependencies: + minipass: "npm:^3.0.0" + checksum: 79076749fcacf21b5d16dd596d32c3b6bf4d6e62abb43868fac21674078505c8b15eaca4e47ed844985a4514854f917d78f588fcd029693709417d8f98b2bd60 + languageName: node + linkType: hard + +"minipass@npm:^3.0.0": + version: 3.3.6 + resolution: "minipass@npm:3.3.6" + dependencies: + yallist: "npm:^4.0.0" + checksum: a30d083c8054cee83cdcdc97f97e4641a3f58ae743970457b1489ce38ee1167b3aaf7d815cd39ec7a99b9c40397fd4f686e83750e73e652b21cb516f6d845e48 + languageName: node + linkType: hard + +"minipass@npm:^5.0.0": + version: 5.0.0 + resolution: "minipass@npm:5.0.0" + checksum: 425dab288738853fded43da3314a0b5c035844d6f3097a8e3b5b29b328da8f3c1af6fc70618b32c29ff906284cf6406b6841376f21caaadd0793c1d5a6a620ea + languageName: node + linkType: hard + +"minipass@npm:^5.0.0 || ^6.0.2 || ^7.0.0, minipass@npm:^7.0.3": + version: 7.0.3 + resolution: "minipass@npm:7.0.3" + checksum: 6f1614f5b5b55568a46bca5fec0e7c46dac027691db27d0e1923a8192866903144cd962ac772c0e9f89b608ea818b702709c042bce98e190d258847d85461531 + languageName: node + linkType: hard + +"minizlib@npm:^2.1.1, minizlib@npm:^2.1.2": + version: 2.1.2 + resolution: "minizlib@npm:2.1.2" + dependencies: + minipass: "npm:^3.0.0" + yallist: "npm:^4.0.0" + checksum: f1fdeac0b07cf8f30fcf12f4b586795b97be856edea22b5e9072707be51fc95d41487faec3f265b42973a304fe3a64acd91a44a3826a963e37b37bafde0212c3 + languageName: node + linkType: hard + +"mkdirp@npm:^1.0.3": + version: 1.0.4 + resolution: "mkdirp@npm:1.0.4" + bin: + mkdirp: bin/cmd.js + checksum: a96865108c6c3b1b8e1d5e9f11843de1e077e57737602de1b82030815f311be11f96f09cce59bd5b903d0b29834733e5313f9301e3ed6d6f6fba2eae0df4298f + languageName: node + linkType: hard + +"ms@npm:2.1.2": + version: 2.1.2 + resolution: "ms@npm:2.1.2" + checksum: 673cdb2c3133eb050c745908d8ce632ed2c02d85640e2edb3ace856a2266a813b30c613569bf3354fdf4ea7d1a1494add3bfa95e2713baa27d0c2c71fc44f58f + languageName: node + linkType: hard + +"ms@npm:^2.0.0": + version: 2.1.3 + resolution: "ms@npm:2.1.3" + checksum: aa92de608021b242401676e35cfa5aa42dd70cbdc082b916da7fb925c542173e36bce97ea3e804923fe92c0ad991434e4a38327e15a1b5b5f945d66df615ae6d + languageName: node + linkType: hard + +"negotiator@npm:^0.6.3": + version: 0.6.3 + resolution: "negotiator@npm:0.6.3" + checksum: b8ffeb1e262eff7968fc90a2b6767b04cfd9842582a9d0ece0af7049537266e7b2506dfb1d107a32f06dd849ab2aea834d5830f7f4d0e5cb7d36e1ae55d021d9 + languageName: node + linkType: hard + +"no-case@npm:^3.0.4": + version: 3.0.4 + resolution: "no-case@npm:3.0.4" + dependencies: + lower-case: "npm:^2.0.2" + tslib: "npm:^2.0.3" + checksum: 0b2ebc113dfcf737d48dde49cfebf3ad2d82a8c3188e7100c6f375e30eafbef9e9124aadc3becef237b042fd5eb0aad2fd78669c20972d045bbe7fea8ba0be5c + languageName: node + linkType: hard + +"node-fetch@npm:^2.6.12": + version: 2.7.0 + resolution: "node-fetch@npm:2.7.0" + dependencies: + whatwg-url: "npm:^5.0.0" + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + checksum: d76d2f5edb451a3f05b15115ec89fc6be39de37c6089f1b6368df03b91e1633fd379a7e01b7ab05089a25034b2023d959b47e59759cb38d88341b2459e89d6e5 + languageName: node + linkType: hard + +"node-gyp-build@npm:^4.3.0": + version: 4.6.1 + resolution: "node-gyp-build@npm:4.6.1" + bin: + node-gyp-build: bin.js + node-gyp-build-optional: optional.js + node-gyp-build-test: build-test.js + checksum: c3676d337b36803bc7792e35bf7fdcda7cdcb7e289b8f9855a5535702a82498eb976842fefcf487258c58005ca32ce3d537fbed91280b04409161dcd7232a882 + languageName: node + linkType: hard + +"node-gyp@npm:latest": + version: 9.4.0 + resolution: "node-gyp@npm:9.4.0" + dependencies: + env-paths: "npm:^2.2.0" + exponential-backoff: "npm:^3.1.1" + glob: "npm:^7.1.4" + graceful-fs: "npm:^4.2.6" + make-fetch-happen: "npm:^11.0.3" + nopt: "npm:^6.0.0" + npmlog: "npm:^6.0.0" + rimraf: "npm:^3.0.2" + semver: "npm:^7.3.5" + tar: "npm:^6.1.2" + which: "npm:^2.0.2" + bin: + node-gyp: bin/node-gyp.js + checksum: 78b404e2e0639d64e145845f7f5a3cb20c0520cdaf6dda2f6e025e9b644077202ea7de1232396ba5bde3fee84cdc79604feebe6ba3ec84d464c85d407bb5da99 + languageName: node + linkType: hard + +"nopt@npm:^6.0.0": + version: 6.0.0 + resolution: "nopt@npm:6.0.0" + dependencies: + abbrev: "npm:^1.0.0" + bin: + nopt: bin/nopt.js + checksum: 82149371f8be0c4b9ec2f863cc6509a7fd0fa729929c009f3a58e4eb0c9e4cae9920e8f1f8eb46e7d032fec8fb01bede7f0f41a67eb3553b7b8e14fa53de1dac + languageName: node + linkType: hard + +"npmlog@npm:^6.0.0": + version: 6.0.2 + resolution: "npmlog@npm:6.0.2" + dependencies: + are-we-there-yet: "npm:^3.0.0" + console-control-strings: "npm:^1.1.0" + gauge: "npm:^4.0.3" + set-blocking: "npm:^2.0.0" + checksum: ae238cd264a1c3f22091cdd9e2b106f684297d3c184f1146984ecbe18aaa86343953f26b9520dedd1b1372bc0316905b736c1932d778dbeb1fcf5a1001390e2a + languageName: node + linkType: hard + +"once@npm:^1.3.0": + version: 1.4.0 + resolution: "once@npm:1.4.0" + dependencies: + wrappy: "npm:1" + checksum: cd0a88501333edd640d95f0d2700fbde6bff20b3d4d9bdc521bdd31af0656b5706570d6c6afe532045a20bb8dc0849f8332d6f2a416e0ba6d3d3b98806c7db68 + languageName: node + linkType: hard + +"p-map@npm:^4.0.0": + version: 4.0.0 + resolution: "p-map@npm:4.0.0" + dependencies: + aggregate-error: "npm:^3.0.0" + checksum: cb0ab21ec0f32ddffd31dfc250e3afa61e103ef43d957cc45497afe37513634589316de4eb88abdfd969fe6410c22c0b93ab24328833b8eb1ccc087fc0442a1c + languageName: node + linkType: hard + +"pako@npm:^2.0.3": + version: 2.1.0 + resolution: "pako@npm:2.1.0" + checksum: 71666548644c9a4d056bcaba849ca6fd7242c6cf1af0646d3346f3079a1c7f4a66ffec6f7369ee0dc88f61926c10d6ab05da3e1fca44b83551839e89edd75a3e + languageName: node + linkType: hard + +"path-is-absolute@npm:^1.0.0": + version: 1.0.1 + resolution: "path-is-absolute@npm:1.0.1" + checksum: 060840f92cf8effa293bcc1bea81281bd7d363731d214cbe5c227df207c34cd727430f70c6037b5159c8a870b9157cba65e775446b0ab06fd5ecc7e54615a3b8 + languageName: node + linkType: hard + +"path-key@npm:^3.1.0": + version: 3.1.1 + resolution: "path-key@npm:3.1.1" + checksum: 55cd7a9dd4b343412a8386a743f9c746ef196e57c823d90ca3ab917f90ab9f13dd0ded27252ba49dbdfcab2b091d998bc446f6220cd3cea65db407502a740020 + languageName: node + linkType: hard + +"path-scurry@npm:^1.10.1": + version: 1.10.1 + resolution: "path-scurry@npm:1.10.1" + dependencies: + lru-cache: "npm:^9.1.1 || ^10.0.0" + minipass: "npm:^5.0.0 || ^6.0.2 || ^7.0.0" + checksum: e2557cff3a8fb8bc07afdd6ab163a92587884f9969b05bbbaf6fe7379348bfb09af9ed292af12ed32398b15fb443e81692047b786d1eeb6d898a51eb17ed7d90 + languageName: node + linkType: hard + +"picomatch@npm:^2.3.1": + version: 2.3.1 + resolution: "picomatch@npm:2.3.1" + checksum: 050c865ce81119c4822c45d3c84f1ced46f93a0126febae20737bd05ca20589c564d6e9226977df859ed5e03dc73f02584a2b0faad36e896936238238b0446cf + languageName: node + linkType: hard + +"promise-retry@npm:^2.0.1": + version: 2.0.1 + resolution: "promise-retry@npm:2.0.1" + dependencies: + err-code: "npm:^2.0.2" + retry: "npm:^0.12.0" + checksum: f96a3f6d90b92b568a26f71e966cbbc0f63ab85ea6ff6c81284dc869b41510e6cdef99b6b65f9030f0db422bf7c96652a3fff9f2e8fb4a0f069d8f4430359429 + languageName: node + linkType: hard + +"proxy-from-env@npm:^1.1.0": + version: 1.1.0 + resolution: "proxy-from-env@npm:1.1.0" + checksum: ed7fcc2ba0a33404958e34d95d18638249a68c430e30fcb6c478497d72739ba64ce9810a24f53a7d921d0c065e5b78e3822759800698167256b04659366ca4d4 + languageName: node + linkType: hard + +"readable-stream@npm:^3.6.0": + version: 3.6.2 + resolution: "readable-stream@npm:3.6.2" + dependencies: + inherits: "npm:^2.0.3" + string_decoder: "npm:^1.1.1" + util-deprecate: "npm:^1.0.1" + checksum: bdcbe6c22e846b6af075e32cf8f4751c2576238c5043169a1c221c92ee2878458a816a4ea33f4c67623c0b6827c8a400409bfb3cf0bf3381392d0b1dfb52ac8d + languageName: node + linkType: hard + +"regenerator-runtime@npm:^0.14.0": + version: 0.14.0 + resolution: "regenerator-runtime@npm:0.14.0" + checksum: 1c977ad82a82a4412e4f639d65d22be376d3ebdd30da2c003eeafdaaacd03fc00c2320f18120007ee700900979284fc78a9f00da7fb593f6e6eeebc673fba9a3 + languageName: node + linkType: hard + +"retry@npm:^0.12.0": + version: 0.12.0 + resolution: "retry@npm:0.12.0" + checksum: 623bd7d2e5119467ba66202d733ec3c2e2e26568074923bc0585b6b99db14f357e79bdedb63cab56cec47491c4a0da7e6021a7465ca6dc4f481d3898fdd3158c + languageName: node + linkType: hard + +"rimraf@npm:^3.0.2": + version: 3.0.2 + resolution: "rimraf@npm:3.0.2" + dependencies: + glob: "npm:^7.1.3" + bin: + rimraf: bin.js + checksum: 87f4164e396f0171b0a3386cc1877a817f572148ee13a7e113b238e48e8a9f2f31d009a92ec38a591ff1567d9662c6b67fd8818a2dbbaed74bc26a87a2a4a9a0 + languageName: node + linkType: hard + +"rpc-websockets@npm:^7.5.1": + version: 7.6.0 + resolution: "rpc-websockets@npm:7.6.0" + dependencies: + "@babel/runtime": "npm:^7.17.2" + bufferutil: "npm:^4.0.1" + eventemitter3: "npm:^4.0.7" + utf-8-validate: "npm:^5.0.2" + uuid: "npm:^8.3.2" + ws: "npm:^8.5.0" + dependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + checksum: af2b254f65985610bd354e8e13de07b5a36010b94672b0b5a9d226b9bb1b8b17d01c63221cad97263845888f3610e55867a32e4c0017dfb92fddf89417c4cb6c + languageName: node + linkType: hard + +"safe-buffer@npm:^5.0.1, safe-buffer@npm:~5.2.0": + version: 5.2.1 + resolution: "safe-buffer@npm:5.2.1" + checksum: b99c4b41fdd67a6aaf280fcd05e9ffb0813654894223afb78a31f14a19ad220bba8aba1cb14eddce1fcfb037155fe6de4e861784eb434f7d11ed58d1e70dd491 + languageName: node + linkType: hard + +"safer-buffer@npm:>= 2.1.2 < 3.0.0": + version: 2.1.2 + resolution: "safer-buffer@npm:2.1.2" + checksum: cab8f25ae6f1434abee8d80023d7e72b598cf1327164ddab31003c51215526801e40b66c5e65d658a0af1e9d6478cadcb4c745f4bd6751f97d8644786c0978b0 + languageName: node + linkType: hard + +"semver@npm:^7.3.4, semver@npm:^7.3.5": + version: 7.5.4 + resolution: "semver@npm:7.5.4" + dependencies: + lru-cache: "npm:^6.0.0" + bin: + semver: bin/semver.js + checksum: 12d8ad952fa353b0995bf180cdac205a4068b759a140e5d3c608317098b3575ac2f1e09182206bf2eb26120e1c0ed8fb92c48c592f6099680de56bb071423ca3 + languageName: node + linkType: hard + +"set-blocking@npm:^2.0.0": + version: 2.0.0 + resolution: "set-blocking@npm:2.0.0" + checksum: 6e65a05f7cf7ebdf8b7c75b101e18c0b7e3dff4940d480efed8aad3a36a4005140b660fa1d804cb8bce911cac290441dc728084a30504d3516ac2ff7ad607b02 + languageName: node + linkType: hard + +"shebang-command@npm:^2.0.0": + version: 2.0.0 + resolution: "shebang-command@npm:2.0.0" + dependencies: + shebang-regex: "npm:^3.0.0" + checksum: 6b52fe87271c12968f6a054e60f6bde5f0f3d2db483a1e5c3e12d657c488a15474121a1d55cd958f6df026a54374ec38a4a963988c213b7570e1d51575cea7fa + languageName: node + linkType: hard + +"shebang-regex@npm:^3.0.0": + version: 3.0.0 + resolution: "shebang-regex@npm:3.0.0" + checksum: 1a2bcae50de99034fcd92ad4212d8e01eedf52c7ec7830eedcf886622804fe36884278f2be8be0ea5fde3fd1c23911643a4e0f726c8685b61871c8908af01222 + languageName: node + linkType: hard + +"signal-exit@npm:^3.0.7": + version: 3.0.7 + resolution: "signal-exit@npm:3.0.7" + checksum: a2f098f247adc367dffc27845853e9959b9e88b01cb301658cfe4194352d8d2bb32e18467c786a7fe15f1d44b233ea35633d076d5e737870b7139949d1ab6318 + languageName: node + linkType: hard + +"signal-exit@npm:^4.0.1": + version: 4.1.0 + resolution: "signal-exit@npm:4.1.0" + checksum: 64c757b498cb8629ffa5f75485340594d2f8189e9b08700e69199069c8e3070fb3e255f7ab873c05dc0b3cec412aea7402e10a5990cb6a050bd33ba062a6c549 + languageName: node + linkType: hard + +"smart-buffer@npm:^4.2.0": + version: 4.2.0 + resolution: "smart-buffer@npm:4.2.0" + checksum: b5167a7142c1da704c0e3af85c402002b597081dd9575031a90b4f229ca5678e9a36e8a374f1814c8156a725d17008ae3bde63b92f9cfd132526379e580bec8b + languageName: node + linkType: hard + +"snake-case@npm:^3.0.4": + version: 3.0.4 + resolution: "snake-case@npm:3.0.4" + dependencies: + dot-case: "npm:^3.0.4" + tslib: "npm:^2.0.3" + checksum: 0a7a79900bbb36f8aaa922cf111702a3647ac6165736d5dc96d3ef367efc50465cac70c53cd172c382b022dac72ec91710608e5393de71f76d7142e6fd80e8a3 + languageName: node + linkType: hard + +"socks-proxy-agent@npm:^7.0.0": + version: 7.0.0 + resolution: "socks-proxy-agent@npm:7.0.0" + dependencies: + agent-base: "npm:^6.0.2" + debug: "npm:^4.3.3" + socks: "npm:^2.6.2" + checksum: 720554370154cbc979e2e9ce6a6ec6ced205d02757d8f5d93fe95adae454fc187a5cbfc6b022afab850a5ce9b4c7d73e0f98e381879cf45f66317a4895953846 + languageName: node + linkType: hard + +"socks@npm:^2.6.2": + version: 2.7.1 + resolution: "socks@npm:2.7.1" + dependencies: + ip: "npm:^2.0.0" + smart-buffer: "npm:^4.2.0" + checksum: 259d9e3e8e1c9809a7f5c32238c3d4d2a36b39b83851d0f573bfde5f21c4b1288417ce1af06af1452569cd1eb0841169afd4998f0e04ba04656f6b7f0e46d748 + languageName: node + linkType: hard + +"ssri@npm:^10.0.0": + version: 10.0.5 + resolution: "ssri@npm:10.0.5" + dependencies: + minipass: "npm:^7.0.3" + checksum: 0a31b65f21872dea1ed3f7c200d7bc1c1b91c15e419deca14f282508ba917cbb342c08a6814c7f68ca4ca4116dd1a85da2bbf39227480e50125a1ceffeecb750 + languageName: node + linkType: hard + +"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^1.0.2 || 2 || 3 || 4, string-width@npm:^4.1.0, string-width@npm:^4.2.3": + version: 4.2.3 + resolution: "string-width@npm:4.2.3" + dependencies: + emoji-regex: "npm:^8.0.0" + is-fullwidth-code-point: "npm:^3.0.0" + strip-ansi: "npm:^6.0.1" + checksum: e52c10dc3fbfcd6c3a15f159f54a90024241d0f149cf8aed2982a2d801d2e64df0bf1dc351cf8e95c3319323f9f220c16e740b06faecd53e2462df1d2b5443fb + languageName: node + linkType: hard + +"string-width@npm:^5.0.1, string-width@npm:^5.1.2": + version: 5.1.2 + resolution: "string-width@npm:5.1.2" + dependencies: + eastasianwidth: "npm:^0.2.0" + emoji-regex: "npm:^9.2.2" + strip-ansi: "npm:^7.0.1" + checksum: 7369deaa29f21dda9a438686154b62c2c5f661f8dda60449088f9f980196f7908fc39fdd1803e3e01541970287cf5deae336798337e9319a7055af89dafa7193 + languageName: node + linkType: hard + +"string_decoder@npm:^1.1.1": + version: 1.3.0 + resolution: "string_decoder@npm:1.3.0" + dependencies: + safe-buffer: "npm:~5.2.0" + checksum: 8417646695a66e73aefc4420eb3b84cc9ffd89572861fe004e6aeb13c7bc00e2f616247505d2dbbef24247c372f70268f594af7126f43548565c68c117bdeb56 + languageName: node + linkType: hard + +"strip-ansi-cjs@npm:strip-ansi@^6.0.1, strip-ansi@npm:^6.0.0, strip-ansi@npm:^6.0.1": + version: 6.0.1 + resolution: "strip-ansi@npm:6.0.1" + dependencies: + ansi-regex: "npm:^5.0.1" + checksum: f3cd25890aef3ba6e1a74e20896c21a46f482e93df4a06567cebf2b57edabb15133f1f94e57434e0a958d61186087b1008e89c94875d019910a213181a14fc8c + languageName: node + linkType: hard + +"strip-ansi@npm:^7.0.1": + version: 7.1.0 + resolution: "strip-ansi@npm:7.1.0" + dependencies: + ansi-regex: "npm:^6.0.1" + checksum: 859c73fcf27869c22a4e4d8c6acfe690064659e84bef9458aa6d13719d09ca88dcfd40cbf31fd0be63518ea1a643fe070b4827d353e09533a5b0b9fd4553d64d + languageName: node + linkType: hard + +"superstruct@npm:^0.14.2": + version: 0.14.2 + resolution: "superstruct@npm:0.14.2" + checksum: c5c4840f432da82125b923ec45faca5113217e83ae416e314d80eae012b8bb603d2e745025d173450758d116348820bc7028157f8c9a72b6beae879f94b837c0 + languageName: node + linkType: hard + +"superstruct@npm:^0.15.4": + version: 0.15.5 + resolution: "superstruct@npm:0.15.5" + checksum: 6d1f5249fee789424b7178fa0a1ffb2ace629c5480c39505885bd8c0046a4ff8b267569a3442fa53b8c560a7ba6599cf3f8af94225aebeb2cf6023f7dd911050 + languageName: node + linkType: hard + +"supports-color@npm:^7.1.0": + version: 7.2.0 + resolution: "supports-color@npm:7.2.0" + dependencies: + has-flag: "npm:^4.0.0" + checksum: 3dda818de06ebbe5b9653e07842d9479f3555ebc77e9a0280caf5a14fb877ffee9ed57007c3b78f5a6324b8dbeec648d9e97a24e2ed9fdb81ddc69ea07100f4a + languageName: node + linkType: hard + +"tapable@npm:^2.2.0": + version: 2.2.1 + resolution: "tapable@npm:2.2.1" + checksum: 3b7a1b4d86fa940aad46d9e73d1e8739335efd4c48322cb37d073eb6f80f5281889bf0320c6d8ffcfa1a0dd5bfdbd0f9d037e252ef972aca595330538aac4d51 + languageName: node + linkType: hard + +"tar@npm:^6.1.11, tar@npm:^6.1.2": + version: 6.1.15 + resolution: "tar@npm:6.1.15" + dependencies: + chownr: "npm:^2.0.0" + fs-minipass: "npm:^2.0.0" + minipass: "npm:^5.0.0" + minizlib: "npm:^2.1.1" + mkdirp: "npm:^1.0.3" + yallist: "npm:^4.0.0" + checksum: f23832fceeba7578bf31907aac744ae21e74a66f4a17a9e94507acf460e48f6db598c7023882db33bab75b80e027c21f276d405e4a0322d58f51c7088d428268 + languageName: node + linkType: hard + +"text-encoding-utf-8@npm:^1.0.2": + version: 1.0.2 + resolution: "text-encoding-utf-8@npm:1.0.2" + checksum: ec4c15d50e738c5dba7327ad432ebf0725ec75d4d69c0bd55609254c5a3bc5341272d7003691084a0a73d60d981c8eb0e87603676fdb6f3fed60f4c9192309f9 + languageName: node + linkType: hard + +"through@npm:>=2.2.7 <3": + version: 2.3.8 + resolution: "through@npm:2.3.8" + checksum: a38c3e059853c494af95d50c072b83f8b676a9ba2818dcc5b108ef252230735c54e0185437618596c790bbba8fcdaef5b290405981ffa09dce67b1f1bf190cbd + languageName: node + linkType: hard + +"to-regex-range@npm:^5.0.1": + version: 5.0.1 + resolution: "to-regex-range@npm:5.0.1" + dependencies: + is-number: "npm:^7.0.0" + checksum: f76fa01b3d5be85db6a2a143e24df9f60dd047d151062d0ba3df62953f2f697b16fe5dad9b0ac6191c7efc7b1d9dcaa4b768174b7b29da89d4428e64bc0a20ed + languageName: node + linkType: hard + +"toml@npm:^3.0.0": + version: 3.0.0 + resolution: "toml@npm:3.0.0" + checksum: 5d7f1d8413ad7780e9bdecce8ea4c3f5130dd53b0a4f2e90b93340979a137739879d7b9ce2ce05c938b8cc828897fe9e95085197342a1377dd8850bf5125f15f + languageName: node + linkType: hard + +"tr46@npm:~0.0.3": + version: 0.0.3 + resolution: "tr46@npm:0.0.3" + checksum: 726321c5eaf41b5002e17ffbd1fb7245999a073e8979085dacd47c4b4e8068ff5777142fc6726d6ca1fd2ff16921b48788b87225cbc57c72636f6efa8efbffe3 + languageName: node + linkType: hard + +"ts-loader@npm:^9.2.3": + version: 9.4.4 + resolution: "ts-loader@npm:9.4.4" + dependencies: + chalk: "npm:^4.1.0" + enhanced-resolve: "npm:^5.0.0" + micromatch: "npm:^4.0.0" + semver: "npm:^7.3.4" + peerDependencies: + typescript: "*" + webpack: ^5.0.0 + checksum: 8e5e6b839b0edfa40d2156c880d88ccab58226894ea5978221bc48c7db3215e2e856bfd0093f148e925a2befc42d6c94cafa9a994a7da274541efaa916012b63 + languageName: node + linkType: hard + +"tslib@npm:^2.0.3": + version: 2.6.2 + resolution: "tslib@npm:2.6.2" + checksum: 329ea56123005922f39642318e3d1f0f8265d1e7fcb92c633e0809521da75eeaca28d2cf96d7248229deb40e5c19adf408259f4b9640afd20d13aecc1430f3ad + languageName: node + linkType: hard + +"typescript@npm:^5.2.2": + version: 5.2.2 + resolution: "typescript@npm:5.2.2" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 7912821dac4d962d315c36800fe387cdc0a6298dba7ec171b350b4a6e988b51d7b8f051317786db1094bd7431d526b648aba7da8236607febb26cf5b871d2d3c + languageName: node + linkType: hard + +"typescript@patch:typescript@^5.2.2#~builtin": + version: 5.2.2 + resolution: "typescript@patch:typescript@npm%3A5.2.2#~builtin::version=5.2.2&hash=f3b441" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 0f4da2f15e6f1245e49db15801dbee52f2bbfb267e1c39225afdab5afee1a72839cd86000e65ee9d7e4dfaff12239d28beaf5ee431357fcced15fb08583d72ca + languageName: node + linkType: hard + +"unique-filename@npm:^3.0.0": + version: 3.0.0 + resolution: "unique-filename@npm:3.0.0" + dependencies: + unique-slug: "npm:^4.0.0" + checksum: 8e2f59b356cb2e54aab14ff98a51ac6c45781d15ceaab6d4f1c2228b780193dc70fae4463ce9e1df4479cb9d3304d7c2043a3fb905bdeca71cc7e8ce27e063df + languageName: node + linkType: hard + +"unique-slug@npm:^4.0.0": + version: 4.0.0 + resolution: "unique-slug@npm:4.0.0" + dependencies: + imurmurhash: "npm:^0.1.4" + checksum: 0884b58365af59f89739e6f71e3feacb5b1b41f2df2d842d0757933620e6de08eff347d27e9d499b43c40476cbaf7988638d3acb2ffbcb9d35fd035591adfd15 + languageName: node + linkType: hard + +"utf-8-validate@npm:^5.0.2": + version: 5.0.10 + resolution: "utf-8-validate@npm:5.0.10" + dependencies: + node-gyp: "npm:latest" + node-gyp-build: "npm:^4.3.0" + checksum: 5579350a023c66a2326752b6c8804cc7b39dcd251bb088241da38db994b8d78352e388dcc24ad398ab98385ba3c5ffcadb6b5b14b2637e43f767869055e46ba6 + languageName: node + linkType: hard + +"util-deprecate@npm:^1.0.1": + version: 1.0.2 + resolution: "util-deprecate@npm:1.0.2" + checksum: 474acf1146cb2701fe3b074892217553dfcf9a031280919ba1b8d651a068c9b15d863b7303cb15bd00a862b498e6cf4ad7b4a08fb134edd5a6f7641681cb54a2 + languageName: node + linkType: hard + +"uuid@npm:^8.3.2": + version: 8.3.2 + resolution: "uuid@npm:8.3.2" + bin: + uuid: dist/bin/uuid + checksum: 5575a8a75c13120e2f10e6ddc801b2c7ed7d8f3c8ac22c7ed0c7b2ba6383ec0abda88c905085d630e251719e0777045ae3236f04c812184b7c765f63a70e58df + languageName: node + linkType: hard + +"webidl-conversions@npm:^3.0.0": + version: 3.0.1 + resolution: "webidl-conversions@npm:3.0.1" + checksum: c92a0a6ab95314bde9c32e1d0a6dfac83b578f8fa5f21e675bc2706ed6981bc26b7eb7e6a1fab158e5ce4adf9caa4a0aee49a52505d4d13c7be545f15021b17c + languageName: node + linkType: hard + +"whatwg-url@npm:^5.0.0": + version: 5.0.0 + resolution: "whatwg-url@npm:5.0.0" + dependencies: + tr46: "npm:~0.0.3" + webidl-conversions: "npm:^3.0.0" + checksum: b8daed4ad3356cc4899048a15b2c143a9aed0dfae1f611ebd55073310c7b910f522ad75d727346ad64203d7e6c79ef25eafd465f4d12775ca44b90fa82ed9e2c + languageName: node + linkType: hard + +"which@npm:^2.0.1, which@npm:^2.0.2": + version: 2.0.2 + resolution: "which@npm:2.0.2" + dependencies: + isexe: "npm:^2.0.0" + bin: + node-which: ./bin/node-which + checksum: 1a5c563d3c1b52d5f893c8b61afe11abc3bab4afac492e8da5bde69d550de701cf9806235f20a47b5c8fa8a1d6a9135841de2596535e998027a54589000e66d1 + languageName: node + linkType: hard + +"wide-align@npm:^1.1.5": + version: 1.1.5 + resolution: "wide-align@npm:1.1.5" + dependencies: + string-width: "npm:^1.0.2 || 2 || 3 || 4" + checksum: d5fc37cd561f9daee3c80e03b92ed3e84d80dde3365a8767263d03dacfc8fa06b065ffe1df00d8c2a09f731482fcacae745abfbb478d4af36d0a891fad4834d3 + languageName: node + linkType: hard + +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": + version: 7.0.0 + resolution: "wrap-ansi@npm:7.0.0" + dependencies: + ansi-styles: "npm:^4.0.0" + string-width: "npm:^4.1.0" + strip-ansi: "npm:^6.0.0" + checksum: a790b846fd4505de962ba728a21aaeda189b8ee1c7568ca5e817d85930e06ef8d1689d49dbf0e881e8ef84436af3a88bc49115c2e2788d841ff1b8b5b51a608b + languageName: node + linkType: hard + +"wrap-ansi@npm:^8.1.0": + version: 8.1.0 + resolution: "wrap-ansi@npm:8.1.0" + dependencies: + ansi-styles: "npm:^6.1.0" + string-width: "npm:^5.0.1" + strip-ansi: "npm:^7.0.1" + checksum: 371733296dc2d616900ce15a0049dca0ef67597d6394c57347ba334393599e800bab03c41d4d45221b6bc967b8c453ec3ae4749eff3894202d16800fdfe0e238 + languageName: node + linkType: hard + +"wrappy@npm:1": + version: 1.0.2 + resolution: "wrappy@npm:1.0.2" + checksum: 159da4805f7e84a3d003d8841557196034155008f817172d4e986bd591f74aa82aa7db55929a54222309e01079a65a92a9e6414da5a6aa4b01ee44a511ac3ee5 + languageName: node + linkType: hard + +"ws@npm:^7.4.5": + version: 7.5.9 + resolution: "ws@npm:7.5.9" + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + checksum: c3c100a181b731f40b7f2fddf004aa023f79d64f489706a28bc23ff88e87f6a64b3c6651fbec3a84a53960b75159574d7a7385709847a62ddb7ad6af76f49138 + languageName: node + linkType: hard + +"ws@npm:^8.5.0": + version: 8.13.0 + resolution: "ws@npm:8.13.0" + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ">=5.0.2" + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + checksum: 53e991bbf928faf5dc6efac9b8eb9ab6497c69feeb94f963d648b7a3530a720b19ec2e0ec037344257e05a4f35bd9ad04d9de6f289615ffb133282031b18c61c + languageName: node + linkType: hard + +"yallist@npm:^4.0.0": + version: 4.0.0 + resolution: "yallist@npm:4.0.0" + checksum: 343617202af32df2a15a3be36a5a8c0c8545208f3d3dfbc6bb7c3e3b7e8c6f8e7485432e4f3b88da3031a6e20afa7c711eded32ddfb122896ac5d914e75848d5 + languageName: node + linkType: hard diff --git a/programs/voter-stake-registry/src/instructions/initialize_position_v0.rs b/programs/voter-stake-registry/src/instructions/initialize_position_v0.rs index a574f7ec8..e49345a72 100644 --- a/programs/voter-stake-registry/src/instructions/initialize_position_v0.rs +++ b/programs/voter-stake-registry/src/instructions/initialize_position_v0.rs @@ -31,7 +31,6 @@ pub struct InitializePositionArgsV0 { #[derive(Accounts)] pub struct InitializePositionV0<'info> { #[account( - mut, has_one = collection )] pub registrar: Box>, diff --git a/tests/sus.ts b/tests/sus.ts new file mode 100644 index 000000000..4b2dcdd99 --- /dev/null +++ b/tests/sus.ts @@ -0,0 +1,430 @@ +import { AnchorProvider, Wallet } from "@coral-xyz/anchor"; +import { init as initDc } from "@helium/data-credits-sdk"; +import { subDaoKey } from "@helium/helium-sub-daos-sdk"; +import { DC_MINT, HNT_MINT, IOT_MINT } from "@helium/spl-utils"; +import { Asset, sus } from "@helium/sus"; +import { + PROGRAM_ID as BUBBLEGUM_PROGRAM_ID, + createBurnInstruction as createBubblegumBurnInstruction, + createTransferInstruction as createBubblegumTransferInstruction +} from "@metaplex-foundation/mpl-bubblegum"; +import { + ConcurrentMerkleTreeAccount, + SPL_ACCOUNT_COMPRESSION_PROGRAM_ID, + SPL_NOOP_PROGRAM_ID, +} from "@solana/spl-account-compression"; +import { + createAssociatedTokenAccountIdempotentInstruction, + createTransferInstruction, + getAssociatedTokenAddressSync, +} from "@solana/spl-token"; +import { + AccountMeta, + Connection, + PublicKey, + Transaction, + TransactionInstruction, +} from "@solana/web3.js"; +import axios from "axios"; +import { BN } from "bn.js"; +import bs58 from "bs58"; +import { expect } from "chai"; + +const SUS = new PublicKey("sustWW3deA7acADNGJnkYj2EAf65EmqUNLxKekDpu6w"); +const hotspot = "9Cyj2K3Fi7xH8fZ1xrp4gtr1CU6Zk8VFM4fZN9NR9ncz"; +describe("sus", () => { + const connection = new Connection( + "https://solana-rpc.web.test-helium.com?session-key=Pluto" + ); + it("handles basic token changes", async () => { + const transaction = new Transaction({ + feePayer: SUS, + recentBlockhash: (await connection.getLatestBlockhash()).blockhash, + }); + const dest = getAssociatedTokenAddressSync(HNT_MINT, PublicKey.default); + transaction.add( + createAssociatedTokenAccountIdempotentInstruction( + SUS, + dest, + PublicKey.default, + HNT_MINT + ), + createTransferInstruction( + getAssociatedTokenAddressSync(HNT_MINT, SUS), + dest, + SUS, + BigInt(1000000000) + ) + ); + const susR = await sus({ + connection, + wallet: SUS, + serializedTransactions: [transaction.serialize({ + verifySignatures: false, + requireAllSignatures: false, + })], + cluster: "devnet" + }); + + const { writableAccounts, balanceChanges } = susR[0]; + expect(writableAccounts[0].name).to.eq("Native SOL Account"); + expect(writableAccounts[0].address.toBase58()).to.eq(SUS.toBase58()); + expect(writableAccounts[0].changedInSimulation).to.be.true; + + expect(writableAccounts[1].name).to.eq("HNT Token Account"); + expect(writableAccounts[1].owner?.toBase58()).to.eq( + "11111111111111111111111111111111" + ); + + expect(writableAccounts[2].name).to.eq("HNT Token Account"); + expect(writableAccounts[2].owner?.toBase58()).to.eq(SUS.toBase58()); + expect(writableAccounts[2].metadata?.decimals).to.eq(8); + + console.log(balanceChanges[0]) + expect(balanceChanges[0].owner.toBase58()).to.eq(SUS.toBase58()); + expect(balanceChanges[0].amount).to.eq(BigInt(-2044280)); + + expect(balanceChanges[1].owner.toBase58()).to.eq( + PublicKey.default.toBase58() + ); + expect(balanceChanges[1].amount).to.eq(BigInt(1000000000)); + + expect(balanceChanges[2].owner.toBase58()).to.eq(SUS.toBase58()); + expect(balanceChanges[2].amount).to.eq(BigInt(-1000000000)); + }); + + it("handles anchor transactions", async () => { + const transaction = new Transaction({ + feePayer: SUS, + recentBlockhash: (await connection.getLatestBlockhash()).blockhash, + }); + const dataCredits = await initDc( + new AnchorProvider( + connection, + { + publicKey: SUS, + } as Wallet, + {} + ) + ); + + transaction.add( + await dataCredits.methods + .mintDataCreditsV0({ + hntAmount: null, + dcAmount: new BN(10), + }) + .accounts({ + dcMint: DC_MINT, + }) + .instruction(), + await dataCredits.methods + .delegateDataCreditsV0({ + amount: new BN(10), + routerKey: "Foo", + }) + .accounts({ + subDao: subDaoKey(IOT_MINT)[0], + }) + .instruction() + ); + const [susR] = await sus({ + connection, + wallet: SUS, + serializedTransactions: [transaction.serialize({ + verifySignatures: false, + requireAllSignatures: false, + })], + cluster: "devnet" + }); + console.log(susR.instructions[0].parsed); + + expect(susR.writableAccounts.map((r) => r.name)).to.deep.eq([ + "Native SOL Account", + "DelegatedDataCreditsV0", + "DC Mint", + "DC Token Account", + "HNT Token Account", + "HNT Mint", + "DC Token Account", + "MintWindowedCircuitBreakerV0", + ]); + expect(susR.instructions[0].parsed?.name).to.eq("mintDataCreditsV0"); + expect(susR.instructions[0].parsed?.data.args.dcAmount.toNumber()).to.eq( + 10 + ); + }); + + it("can warn of cNFT changes", async () => { + const assetResponse = await axios.post(connection.rpcEndpoint, { + jsonrpc: "2.0", + method: "getAsset", + id: "get-asset-op-1", + params: { + id: hotspot, + }, + headers: { + "Cache-Control": "no-cache", + Pragma: "no-cache", + Expires: "0", + }, + }); + const asset = assetResponse.data.result; + const transaction = await transferCompressedCollectable( + connection, + SUS, + asset, + PublicKey.default + ); + const [susR] = await sus({ + connection, + wallet: SUS, + serializedTransactions: [transaction.serialize({ + verifySignatures: false, + requireAllSignatures: false, + })], + checkCNfts: true, + cNfts: [asset], + }); + + expect(susR.possibleCNftChanges[0]).to.eq(asset); + }); + + it("can warn of hotspot burn", async () => { + const assetResponse = await axios.post(connection.rpcEndpoint, { + jsonrpc: "2.0", + method: "getAsset", + id: "get-asset-op-1", + params: { + id: hotspot, + }, + headers: { + "Cache-Control": "no-cache", + Pragma: "no-cache", + Expires: "0", + }, + }); + const asset = assetResponse.data.result; + const transaction = await burnCompressedCollectable( + connection, + SUS, + asset, + ); + const [susR] = await sus({ + connection, + wallet: SUS, + serializedTransactions: [transaction.serialize({ + verifySignatures: false, + requireAllSignatures: false, + })], + checkCNfts: true, + cNfts: [asset], + cluster: "devnet" + }); + console.log(susR.explorerLink) + + expect(susR.possibleCNftChanges[0]).to.eq(asset); + expect(susR.warnings[0].message).to.eq( + "This transaction will brick your Hotspot!" + ); + }); +}); + +async function getBubblegumAuthorityPDA(merkleRollPubKey: PublicKey) { + const [bubblegumAuthorityPDAKey] = await PublicKey.findProgramAddress( + [merkleRollPubKey.toBuffer()], + BUBBLEGUM_PROGRAM_ID + ); + return bubblegumAuthorityPDAKey; +} + +const burnCompressedCollectable = async ( + connection: Connection, + wallet: PublicKey, + collectable: Asset, +): Promise => { + const payer = wallet; + + const instructions: TransactionInstruction[] = []; + + const assetResponse = await axios.post(connection.rpcEndpoint, { + jsonrpc: "2.0", + method: "getAssetProof", + id: "get-asset-op-1", + params: { + id: collectable.id, + }, + headers: { + "Cache-Control": "no-cache", + Pragma: "no-cache", + Expires: "0", + }, + }); + const assetProof = assetResponse.data.result; + + const treeAuthority = await getBubblegumAuthorityPDA( + new PublicKey(assetProof.tree_id) + ); + + const leafDelegate = collectable.ownership.delegate + ? new PublicKey(collectable.ownership.delegate) + : new PublicKey(collectable.ownership.owner); + + const merkleTree = new PublicKey(assetProof.tree_id); + + const tree = await ConcurrentMerkleTreeAccount.fromAccountAddress( + connection, + merkleTree, + "confirmed" + ); + + const canopyHeight = tree.getCanopyDepth(); + const proofPath = mapProof(assetProof); + + const anchorRemainingAccounts = proofPath.slice( + 0, + proofPath.length - (canopyHeight || 0) + ); + + instructions.push( + createBubblegumBurnInstruction( + { + treeAuthority, + leafOwner: new PublicKey(collectable.ownership.owner), + leafDelegate, + merkleTree, + logWrapper: SPL_NOOP_PROGRAM_ID, + compressionProgram: SPL_ACCOUNT_COMPRESSION_PROGRAM_ID, + anchorRemainingAccounts, + }, + { + root: bufferToArray(Buffer.from(bs58.decode(assetProof.root))), + dataHash: bufferToArray( + Buffer.from(bs58.decode(collectable.compression.data_hash!.trim())) + ), + creatorHash: bufferToArray( + Buffer.from(bs58.decode(collectable.compression.creator_hash!.trim())) + ), + nonce: collectable.compression.leaf_id!, + index: collectable.compression.leaf_id!, + } + ) + ); + + const { blockhash } = await connection.getLatestBlockhash(); + + const transaction = new Transaction(); + transaction.add(...instructions); + + transaction.recentBlockhash = blockhash; + transaction.feePayer = payer; + + return transaction; +}; + + +const transferCompressedCollectable = async ( + connection: Connection, + wallet: PublicKey, + collectable: Asset, + payee: PublicKey +): Promise => { + const payer = wallet; + const recipientPubKey = payee; + + const instructions: TransactionInstruction[] = []; + + const assetResponse = await axios.post(connection.rpcEndpoint, { + jsonrpc: "2.0", + method: "getAssetProof", + id: "get-asset-op-1", + params: { + id: collectable.id, + }, + headers: { + "Cache-Control": "no-cache", + Pragma: "no-cache", + Expires: "0", + }, + }); + const assetProof = assetResponse.data.result; + + const treeAuthority = await getBubblegumAuthorityPDA( + new PublicKey(assetProof.tree_id) + ); + + const leafDelegate = collectable.ownership.delegate + ? new PublicKey(collectable.ownership.delegate) + : new PublicKey(collectable.ownership.owner); + + const merkleTree = new PublicKey(assetProof.tree_id); + + const tree = await ConcurrentMerkleTreeAccount.fromAccountAddress( + connection, + merkleTree, + "confirmed" + ); + + const canopyHeight = tree.getCanopyDepth(); + const proofPath = mapProof(assetProof); + + const anchorRemainingAccounts = proofPath.slice( + 0, + proofPath.length - (canopyHeight || 0) + ); + + instructions.push( + createBubblegumTransferInstruction( + { + treeAuthority, + leafOwner: new PublicKey(collectable.ownership.owner), + leafDelegate, + newLeafOwner: recipientPubKey, + merkleTree, + logWrapper: SPL_NOOP_PROGRAM_ID, + compressionProgram: SPL_ACCOUNT_COMPRESSION_PROGRAM_ID, + anchorRemainingAccounts, + }, + { + root: bufferToArray(Buffer.from(bs58.decode(assetProof.root))), + dataHash: bufferToArray( + Buffer.from(bs58.decode(collectable.compression.data_hash!.trim())) + ), + creatorHash: bufferToArray( + Buffer.from(bs58.decode(collectable.compression.creator_hash!.trim())) + ), + nonce: collectable.compression.leaf_id!, + index: collectable.compression.leaf_id!, + } + ) + ); + + const { blockhash } = await connection.getLatestBlockhash(); + + const transaction = new Transaction(); + transaction.add(...instructions); + + transaction.recentBlockhash = blockhash; + transaction.feePayer = payer; + + return transaction; +}; + +function bufferToArray(buffer: Buffer): number[] { + const nums: number[] = []; + for (let i = 0; i < buffer.length; i += 1) { + nums.push(buffer[i]); + } + return nums; +} + +const mapProof = (assetProof: { proof: string[] }): AccountMeta[] => { + if (!assetProof.proof || assetProof.proof.length === 0) { + throw new Error("Proof is empty"); + } + return assetProof.proof.map((node) => ({ + pubkey: new PublicKey(node), + isSigner: false, + isWritable: false, + })); +}; diff --git a/tsconfig.json b/tsconfig.json index d8e67b676..4c1f31c15 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,6 +7,9 @@ { "path": "./packages/fanout-sdk" }, + { + "path": "./packages/sus" + }, { "path": "./packages/hexboosting-sdk" }, @@ -81,9 +84,11 @@ }, { "path": "./packages/crons" - }, { + }, + { "path": "./packages/entity-invalidator" - }, { + }, + { "path": "./packages/no-emit-sdk" } ] diff --git a/yarn.lock b/yarn.lock index afadc8553..a8bcc0fb4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1379,6 +1379,23 @@ __metadata: languageName: node linkType: hard +"@helium/sus@workspace:packages/sus": + version: 0.0.0-use.local + resolution: "@helium/sus@workspace:packages/sus" + dependencies: + "@coral-xyz/anchor": ^0.28.0 + "@metaplex-foundation/mpl-token-metadata": ^2.10.0 + "@solana/spl-token": ^0.3.8 + "@solana/web3.js": ^1.78.4 + axios: ^1.6.5 + bn.js: ^5.2.0 + bs58: ^4.0.1 + git-format-staged: ^2.1.3 + ts-loader: ^9.2.3 + typescript: ^5.2.2 + languageName: unknown + linkType: soft + "@helium/tokens-to-rent-service@workspace:packages/tokens-to-rent-service": version: 0.0.0-use.local resolution: "@helium/tokens-to-rent-service@workspace:packages/tokens-to-rent-service" @@ -5694,6 +5711,17 @@ __metadata: languageName: node linkType: hard +"axios@npm:^1.6.5": + version: 1.6.5 + resolution: "axios@npm:1.6.5" + dependencies: + follow-redirects: ^1.15.4 + form-data: ^4.0.0 + proxy-from-env: ^1.1.0 + checksum: e28d67b2d9134cb4608c44d8068b0678cfdccc652742e619006f27264a30c7aba13b2cd19c6f1f52ae195b5232734925928fb192d5c85feea7edd2f273df206d + languageName: node + linkType: hard + "balanced-match@npm:^1.0.0": version: 1.0.2 resolution: "balanced-match@npm:1.0.2" @@ -8381,6 +8409,16 @@ __metadata: languageName: node linkType: hard +"follow-redirects@npm:^1.15.4": + version: 1.15.5 + resolution: "follow-redirects@npm:1.15.5" + peerDependenciesMeta: + debug: + optional: true + checksum: 5ca49b5ce6f44338cbfc3546823357e7a70813cecc9b7b768158a1d32c1e62e7407c944402a918ea8c38ae2e78266312d617dc68783fac502cbb55e1047b34ec + languageName: node + linkType: hard + "for-each@npm:^0.3.3": version: 0.3.3 resolution: "for-each@npm:0.3.3"