diff --git a/Cargo.toml b/Cargo.toml index 63da6394..3a0bd35e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,8 @@ members = [ "basics/create-account/native/program", "basics/create-account/anchor/programs/create-system-account", "basics/cross-program-invocation/anchor/programs/*", + "basics/ed25519-verification/native/program", + "basics/ed25519-verification/anchor/programs/*", "basics/hello-solana/native/program", "basics/hello-solana/anchor/programs/*", "basics/pda-rent-payer/native/program", diff --git a/basics/ed25519-verification/README.md b/basics/ed25519-verification/README.md new file mode 100644 index 00000000..edfc6a92 --- /dev/null +++ b/basics/ed25519-verification/README.md @@ -0,0 +1,128 @@ +# Ed25519 Signature Verification for Custodied Funds + +This example demonstrates how to implement Ed25519 signature verification to manage custodied funds on Solana. The program verifies Ed25519 signatures before allowing transfers from custodial accounts. + +## Overview + +The example shows how to: +- Verify Ed25519 signatures using Solana's native Ed25519 program +- Transfer funds from custodial accounts after signature verification +- Implement secure authorization checks +- Handle signature verification errors + +## Quick Start + +The example is implemented in multiple frameworks: + +### Native +```bash +cd native +pnpm install +pnpm build-and-test +``` + +### Anchor +```bash +cd anchor +pnpm install +anchor build +pnpm test +``` + +### Steel +```bash +cd steel +pnpm install +steel build +steel test +``` + +### Poseidon (TypeScript) +```bash +cd poseidon +pnpm install +pnpm test +``` + +## Program Structure + +The program consists of the following key components: + +1. **Signature Verification**: Uses Solana's Ed25519 program to verify signatures +2. **Fund Transfer**: Handles secure transfer of funds after verification +3. **Account Validation**: Ensures proper account permissions and ownership + +### Account Structure +- Custodial Account: Holds the funds +- Recipient: Account receiving the funds +- Signer: Account authorized to initiate transfers +- Ed25519 Program: Solana's native signature verification program + +### Instruction Data +```rust +pub struct TransferInstruction { + signature: [u8; 64], // Ed25519 signature + public_key: [u8; 32], // Signer's public key + amount: u64, // Transfer amount in lamports + message: Vec, // Message that was signed +} +``` + +## Usage + +### Creating a Transfer + +```typescript +// Create and sign the transfer message +const message = Buffer.from(`Transfer ${amount} lamports to ${recipient.toBase58()}`); +const signature = await sign(message, signerKeypair.secretKey.slice(0, 32)); + +// Create the instruction +const instruction = new TransactionInstruction({ + keys: [ + { pubkey: custodialAccount, isSigner: false, isWritable: true }, + { pubkey: recipient, isSigner: false, isWritable: true }, + { pubkey: signerKeypair.publicKey, isSigner: true, isWritable: false }, + { pubkey: ed25519ProgramId, isSigner: false, isWritable: false }, + ], + programId, + data: Buffer.concat([signature, publicKey, amount, message]), +}); +``` + +### Security Considerations + +1. **Signature Verification**: Always verify signatures before transferring funds +2. **Account Validation**: Check account ownership and permissions +3. **Error Handling**: Properly handle all error cases +4. **Amount Validation**: Verify sufficient funds before transfer + +## Testing + +Each implementation includes comprehensive tests demonstrating: +- Successful signature verification and transfer +- Handling of invalid signatures +- Error cases for insufficient funds +- Account permission checks + +## Framework-Specific Details + +### Native Implementation +- Direct Solana program implementation +- Manual account and instruction handling +- Bankrun tests for verification + +### Anchor Implementation +- Uses Anchor's account validation +- Structured instruction handling +- Type-safe client interface + +### Steel Implementation +- Separated API and program logic +- Steel-specific optimizations +- Integrated testing tools + +### Poseidon Implementation +- TypeScript client implementation +- Modern Solana practices +- Versioned transaction support \ No newline at end of file diff --git a/basics/ed25519-verification/anchor/Anchor.toml b/basics/ed25519-verification/anchor/Anchor.toml new file mode 100644 index 00000000..4f3e13df --- /dev/null +++ b/basics/ed25519-verification/anchor/Anchor.toml @@ -0,0 +1,16 @@ +[features] +seeds = false +skip-lint = false + +[programs.localnet] +ed25519_custodial = "Ed25519CustodiaLXXXXXXXXXXXXXXXXXXXXXXXXXXX" + +[registry] +url = "https://api.apr.dev" + +[provider] +cluster = "Localnet" +wallet = "~/.config/solana/id.json" + +[scripts] +test = "pnpm ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts" \ No newline at end of file diff --git a/basics/ed25519-verification/anchor/package.json b/basics/ed25519-verification/anchor/package.json new file mode 100644 index 00000000..b4dcdb50 --- /dev/null +++ b/basics/ed25519-verification/anchor/package.json @@ -0,0 +1,23 @@ +{ + "scripts": { + "test": "pnpm ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts", + "build": "anchor build", + "deploy": "anchor deploy" + }, + "dependencies": { + "@coral-xyz/anchor": "^0.30.0", + "@solana/web3.js": "^1.95.2", + "@noble/ed25519": "^1.7.1" + }, + "devDependencies": { + "anchor-bankrun": "^0.4.0", + "solana-bankrun": "^0.3.0", + "@types/bn.js": "^5.1.0", + "@types/chai": "^4.3.0", + "@types/mocha": "^9.0.0", + "chai": "^4.3.4", + "mocha": "^9.0.3", + "ts-mocha": "^10.0.0", + "typescript": "^4.3.5" + } +} diff --git a/basics/ed25519-verification/anchor/programs/ed25519-/Cargo.toml b/basics/ed25519-verification/anchor/programs/ed25519-/Cargo.toml new file mode 100644 index 00000000..9f433049 --- /dev/null +++ b/basics/ed25519-verification/anchor/programs/ed25519-/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "ed25519-custodial" +version = "0.1.0" +description = "Created with Anchor" +edition = "2021" + +[lib] +crate-type = ["cdylib", "lib"] +name = "ed25519_custodial" + +[features] +no-entrypoint = [] +no-idl = [] +no-log-ix-name = [] +cpi = ["no-entrypoint"] +default = [] + +[dependencies] +anchor-lang = "0.30.0" +solana-program = "1.16" \ No newline at end of file diff --git a/basics/ed25519-verification/anchor/programs/ed25519-/src/lib.rs b/basics/ed25519-verification/anchor/programs/ed25519-/src/lib.rs new file mode 100644 index 00000000..5985de7c --- /dev/null +++ b/basics/ed25519-verification/anchor/programs/ed25519-/src/lib.rs @@ -0,0 +1,60 @@ +use anchor_lang::prelude::*; +use anchor_lang::solana_program::ed25519_program; + +declare_id!("Ed25519CustodiaLXXXXXXXXXXXXXXXXXXXXXXXXXXX"); + +#[program] +pub mod ed25519_custodial { + use super::*; + + pub fn transfer( + ctx: Context, + signature: [u8; 64], + public_key: [u8; 32], + message: Vec, + amount: u64, + ) -> Result<()> { + // Verify Ed25519 signature + let verification_instruction = ed25519_program::instruction::new_ed25519_instruction( + &public_key, + &message, + &signature, + ); + + // Invoke the Ed25519 program to verify the signature + solana_program::program::invoke( + &verification_instruction, + &[ctx.accounts.ed25519_program.to_account_info()], + )?; + + msg!("Signature verification successful!"); + + // Transfer funds + **ctx.accounts.custodial_account.try_borrow_mut_lamports()? = ctx + .accounts + .custodial_account + .lamports() + .checked_sub(amount) + .ok_or(ProgramError::InsufficientFunds)?; + + **ctx.accounts.recipient.try_borrow_mut_lamports()? = ctx + .accounts + .recipient + .lamports() + .checked_add(amount) + .ok_or(ProgramError::Overflow)?; + + Ok(()) + } +} + +#[derive(Accounts)] +pub struct Transfer<'info> { + #[account(mut)] + pub custodial_account: AccountInfo<'info>, + #[account(mut)] + pub recipient: AccountInfo<'info>, + pub signer: Signer<'info>, + /// CHECK: This is the Ed25519 program ID + pub ed25519_program: AccountInfo<'info>, +} \ No newline at end of file diff --git a/basics/ed25519-verification/anchor/tests/ed25519-custodial.ts b/basics/ed25519-verification/anchor/tests/ed25519-custodial.ts new file mode 100644 index 00000000..30289323 --- /dev/null +++ b/basics/ed25519-verification/anchor/tests/ed25519-custodial.ts @@ -0,0 +1,56 @@ +import { describe, it } from 'node:test'; +import * as anchor from '@coral-xyz/anchor'; +import { Program } from '@coral-xyz/anchor'; +import { sign } from '@noble/ed25519'; +import { Keypair, PublicKey } from '@solana/web3.js'; +import { BankrunProvider } from 'anchor-bankrun'; +import { startAnchor } from 'solana-bankrun'; +import type { Ed25519Custodial } from '../target/types/ed25519_custodial'; + +describe('Ed25519 Custodial', async () => { + const context = await startAnchor( + '', + [ + { + name: 'ed25519_custodial', + programId: new PublicKey('Ed25519CustodiaLXXXXXXXXXXXXXXXXXXXXXXXXXXX'), + }, + ], + [], + ); + const provider = new BankrunProvider(context); + anchor.setProvider(provider); + + const program = anchor.workspace.Ed25519Custodial as Program; + + it('Verifies signature and transfers funds', async () => { + const custodialAccount = Keypair.generate(); + const recipient = Keypair.generate(); + const signerKeypair = Keypair.generate(); + const amount = 1000000; // lamports + + // Message to sign + const message = Buffer.from(`Transfer ${amount} lamports to ${recipient.publicKey.toBase58()}`); + + // Sign the message with Ed25519 + const signature = await sign(message, signerKeypair.secretKey.slice(0, 32)); + + try { + await program.methods + .transfer(Array.from(signature), Array.from(signerKeypair.publicKey.toBytes()), Array.from(message), new anchor.BN(amount)) + .accounts({ + custodialAccount: custodialAccount.publicKey, + recipient: recipient.publicKey, + signer: signerKeypair.publicKey, + ed25519Program: new PublicKey('Ed25519SigVerify111111111111111111111111111'), + }) + .signers([signerKeypair]) + .rpc(); + + console.log('Transaction processed successfully'); + } catch (error) { + console.error('Error:', error); + throw error; + } + }); +}); diff --git a/basics/ed25519-verification/native/cicd.sh b/basics/ed25519-verification/native/cicd.sh new file mode 100644 index 00000000..956ff82c --- /dev/null +++ b/basics/ed25519-verification/native/cicd.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +# This script is for quick building & deploying of the program. +# It also serves as a reference for the commands used for building & deploying Solana programs. +# Run this bad boy with "bash cicd.sh" or "./cicd.sh" + +cargo build-sbf --manifest-path=./program/Cargo.toml --bpf-out-dir=./program/target/so +solana program deploy ./program/target/so/program.so \ No newline at end of file diff --git a/basics/ed25519-verification/native/package.json b/basics/ed25519-verification/native/package.json new file mode 100644 index 00000000..5a499d05 --- /dev/null +++ b/basics/ed25519-verification/native/package.json @@ -0,0 +1,21 @@ +{ + "scripts": { + "test": "pnpm ts-mocha -p ./tests/tsconfig.test.json -t 1000000 ./tests/test.ts", + "build-and-test": "cargo build-sbf --manifest-path=./program/Cargo.toml --sbf-out-dir=./tests/fixtures && pnpm test", + "build": "cargo build-sbf --manifest-path=./program/Cargo.toml --sbf-out-dir=./program/target/so", + "deploy": "solana program deploy ./program/target/so/program.so" + }, + "dependencies": { + "@solana/web3.js": "^1.95.2", + "@noble/ed25519": "^1.7.1", + "buffer": "^6.0.3", + "solana-bankrun": "^0.3.0" + }, + "devDependencies": { + "@types/node": "^18.0.0", + "typescript": "^4.7.4", + "ts-mocha": "^10.0.0", + "@types/mocha": "^9.0.0", + "mocha": "^9.0.3" + } +} diff --git a/basics/ed25519-verification/native/pnpm-lock.yaml b/basics/ed25519-verification/native/pnpm-lock.yaml new file mode 100644 index 00000000..b8f2a257 --- /dev/null +++ b/basics/ed25519-verification/native/pnpm-lock.yaml @@ -0,0 +1,1263 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@noble/ed25519': + specifier: ^1.7.1 + version: 1.7.3 + '@solana/web3.js': + specifier: ^1.95.2 + version: 1.98.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + buffer: + specifier: ^6.0.3 + version: 6.0.3 + solana-bankrun: + specifier: ^0.3.0 + version: 0.3.1(bufferutil@4.0.9)(utf-8-validate@5.0.10) + devDependencies: + '@types/mocha': + specifier: ^9.0.0 + version: 9.1.1 + '@types/node': + specifier: ^18.0.0 + version: 18.19.74 + mocha: + specifier: ^9.0.3 + version: 9.2.2 + ts-mocha: + specifier: ^10.0.0 + version: 10.0.0(mocha@9.2.2) + typescript: + specifier: ^4.7.4 + version: 4.9.5 + +packages: + + '@babel/runtime@7.26.7': + resolution: {integrity: sha512-AOPI3D+a8dXnja+iwsUqGRjr1BbZIe771sXdapOtYI531gSqpi92vXivKcq2asu/DFpdl1ceFAKZyRzK2PCVcQ==} + engines: {node: '>=6.9.0'} + + '@noble/curves@1.8.1': + resolution: {integrity: sha512-warwspo+UYUPep0Q+vtdVB4Ugn8GGQj8iyB3gnRWsztmUHTI3S1nhdiWNsPUGL0vud7JlRRk1XEu7Lq1KGTnMQ==} + engines: {node: ^14.21.3 || >=16} + + '@noble/ed25519@1.7.3': + resolution: {integrity: sha512-iR8GBkDt0Q3GyaVcIu7mSsVIqnFbkbRzGLWlvhwunacoLwt4J3swfKhfaM6rN6WY+TBGoYT1GtT1mIh2/jGbRQ==} + + '@noble/hashes@1.7.1': + resolution: {integrity: sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ==} + engines: {node: ^14.21.3 || >=16} + + '@solana/buffer-layout@4.0.1': + resolution: {integrity: sha512-E1ImOIAD1tBZFRdjeM4/pzTiTApC0AOBGwyAMS4fwIodCWArzJ3DWdoh8cKxeFM2fElkxBh2Aqts1BPC373rHA==} + engines: {node: '>=5.10'} + + '@solana/web3.js@1.98.0': + resolution: {integrity: sha512-nz3Q5OeyGFpFCR+erX2f6JPt3sKhzhYcSycBCSPkWjzSVDh/Rr1FqTVMRe58FKO16/ivTUcuJjeS5MyBvpkbzA==} + + '@swc/helpers@0.5.15': + resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} + + '@types/connect@3.4.38': + resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} + + '@types/json5@0.0.29': + resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + + '@types/mocha@9.1.1': + resolution: {integrity: sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw==} + + '@types/node@12.20.55': + resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} + + '@types/node@18.19.74': + resolution: {integrity: sha512-HMwEkkifei3L605gFdV+/UwtpxP6JSzM+xFk2Ia6DNFSwSVBRh9qp5Tgf4lNFOMfPVuU0WnkcWpXZpgn5ufO4A==} + + '@types/uuid@8.3.4': + resolution: {integrity: sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==} + + '@types/ws@7.4.7': + resolution: {integrity: sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==} + + '@types/ws@8.5.14': + resolution: {integrity: sha512-bd/YFLW+URhBzMXurx7lWByOu+xzU9+kb3RboOteXYDfW+tr+JZa99OyNmPINEGB/ahzKrEuc8rcv4gnpJmxTw==} + + '@ungap/promise-all-settled@1.1.2': + resolution: {integrity: sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==} + + JSONStream@1.3.5: + resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==} + hasBin: true + + agentkeepalive@4.6.0: + resolution: {integrity: sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==} + engines: {node: '>= 8.0.0'} + + ansi-colors@4.1.1: + resolution: {integrity: sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==} + engines: {node: '>=6'} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + arrify@1.0.1: + resolution: {integrity: sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==} + engines: {node: '>=0.10.0'} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + base-x@3.0.10: + resolution: {integrity: sha512-7d0s06rR9rYaIWHkpfLIFICM/tkSVdoPC9qYAQRpxn9DdKNWNsKC0uk++akckyLq16Tx2WIinnZ6WRriAt6njQ==} + + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + bigint-buffer@1.1.5: + resolution: {integrity: sha512-trfYco6AoZ+rKhKnxA0hgX0HAbVP/s808/EuDSe2JDzUnCp/xAsli35Orvk67UrTEcwuxZqYZDmfA2RXJgxVvA==} + engines: {node: '>= 10.0.0'} + + binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + engines: {node: '>=8'} + + bindings@1.5.0: + resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} + + bn.js@5.2.1: + resolution: {integrity: sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==} + + borsh@0.7.0: + resolution: {integrity: sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA==} + + brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + browser-stdout@1.3.1: + resolution: {integrity: sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==} + + bs58@4.0.1: + resolution: {integrity: sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==} + + buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + + buffer@6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + + bufferutil@4.0.9: + resolution: {integrity: sha512-WDtdLmJvAuNNPzByAYpRo2rF1Mmradw6gvWsQKf63476DDXmomT9zUiGypLcG4ibIM67vhAj8jJRdbmEws2Aqw==} + engines: {node: '>=6.14.2'} + + camelcase@6.3.0: + resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} + engines: {node: '>=10'} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + chokidar@3.5.3: + resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} + engines: {node: '>= 8.10.0'} + + cliui@7.0.4: + resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + commander@2.20.3: + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + debug@4.3.3: + resolution: {integrity: sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decamelize@4.0.0: + resolution: {integrity: sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==} + engines: {node: '>=10'} + + delay@5.0.0: + resolution: {integrity: sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==} + engines: {node: '>=10'} + + diff@3.5.0: + resolution: {integrity: sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==} + engines: {node: '>=0.3.1'} + + diff@5.0.0: + resolution: {integrity: sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==} + engines: {node: '>=0.3.1'} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + es6-promise@4.2.8: + resolution: {integrity: sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==} + + es6-promisify@5.0.0: + resolution: {integrity: sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==} + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + eventemitter3@5.0.1: + resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} + + eyes@0.1.8: + resolution: {integrity: sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ==} + engines: {node: '> 0.1.90'} + + fast-stable-stringify@1.0.0: + resolution: {integrity: sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag==} + + file-uri-to-path@1.0.0: + resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + flat@5.0.2: + resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==} + hasBin: true + + fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob@7.2.0: + resolution: {integrity: sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==} + deprecated: Glob versions prior to v9 are no longer supported + + growl@1.10.5: + resolution: {integrity: sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==} + engines: {node: '>=4.x'} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + he@1.2.0: + resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} + hasBin: true + + humanize-ms@1.2.1: + resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==} + + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + + inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-plain-obj@2.1.0: + resolution: {integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==} + engines: {node: '>=8'} + + is-unicode-supported@0.1.0: + resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} + engines: {node: '>=10'} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + isomorphic-ws@4.0.1: + resolution: {integrity: sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==} + peerDependencies: + ws: '*' + + jayson@4.1.3: + resolution: {integrity: sha512-LtXh5aYZodBZ9Fc3j6f2w+MTNcnxteMOrb+QgIouguGOulWi0lieEkOUg+HkjjFs0DGoWDds6bi4E9hpNFLulQ==} + engines: {node: '>=8'} + hasBin: true + + js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + + json-stringify-safe@5.0.1: + resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} + + json5@1.0.2: + resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} + hasBin: true + + jsonparse@1.3.1: + resolution: {integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==} + engines: {'0': node >= 0.2.0} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + log-symbols@4.1.0: + resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} + engines: {node: '>=10'} + + make-error@1.3.6: + resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + + minimatch@4.2.1: + resolution: {integrity: sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g==} + engines: {node: '>=10'} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + mkdirp@0.5.6: + resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} + hasBin: true + + mocha@9.2.2: + resolution: {integrity: sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g==} + engines: {node: '>= 12.0.0'} + hasBin: true + + ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanoid@3.3.1: + resolution: {integrity: sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + node-fetch@2.7.0: + resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + + node-gyp-build@4.8.4: + resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} + hasBin: true + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + randombytes@2.1.0: + resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} + + readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + + regenerator-runtime@0.14.1: + resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} + + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + rpc-websockets@9.0.4: + resolution: {integrity: sha512-yWZWN0M+bivtoNLnaDbtny4XchdAIF5Q4g/ZsC5UC61Ckbp0QczwO8fg44rV3uYmY4WHd+EZQbn90W1d8ojzqQ==} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + serialize-javascript@6.0.0: + resolution: {integrity: sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==} + + solana-bankrun-darwin-arm64@0.3.1: + resolution: {integrity: sha512-9LWtH/3/WR9fs8Ve/srdo41mpSqVHmRqDoo69Dv1Cupi+o1zMU6HiEPUHEvH2Tn/6TDbPEDf18MYNfReLUqE6A==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + solana-bankrun-darwin-universal@0.3.1: + resolution: {integrity: sha512-muGHpVYWT7xCd8ZxEjs/bmsbMp8XBqroYGbE4lQPMDUuLvsJEIrjGqs3MbxEFr71sa58VpyvgywWd5ifI7sGIg==} + engines: {node: '>= 10'} + os: [darwin] + + solana-bankrun-darwin-x64@0.3.1: + resolution: {integrity: sha512-oCaxfHyt7RC3ZMldrh5AbKfy4EH3YRMl8h6fSlMZpxvjQx7nK7PxlRwMeflMnVdkKKp7U8WIDak1lilIPd3/lg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + solana-bankrun-linux-x64-gnu@0.3.1: + resolution: {integrity: sha512-PfRFhr7igGFNt2Ecfdzh3li9eFPB3Xhmk0Eib17EFIB62YgNUg3ItRnQQFaf0spazFjjJLnglY1TRKTuYlgSVA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + solana-bankrun-linux-x64-musl@0.3.1: + resolution: {integrity: sha512-6r8i0NuXg3CGURql8ISMIUqhE7Hx/O7MlIworK4oN08jYrP0CXdLeB/hywNn7Z8d1NXrox/NpYUgvRm2yIzAsQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + solana-bankrun@0.3.1: + resolution: {integrity: sha512-inRwON7fBU5lPC36HdEqPeDg15FXJYcf77+o0iz9amvkUMJepcwnRwEfTNyMVpVYdgjTOBW5vg+596/3fi1kGA==} + engines: {node: '>= 10'} + + source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + superstruct@2.0.2: + resolution: {integrity: sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A==} + engines: {node: '>=14.0.0'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + + text-encoding-utf-8@1.0.2: + resolution: {integrity: sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg==} + + through@2.3.8: + resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + tr46@0.0.3: + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + + ts-mocha@10.0.0: + resolution: {integrity: sha512-VRfgDO+iiuJFlNB18tzOfypJ21xn2xbuZyDvJvqpTbWgkAgD17ONGr8t+Tl8rcBtOBdjXp5e/Rk+d39f7XBHRw==} + engines: {node: '>= 6.X.X'} + hasBin: true + peerDependencies: + mocha: ^3.X.X || ^4.X.X || ^5.X.X || ^6.X.X || ^7.X.X || ^8.X.X || ^9.X.X || ^10.X.X + + ts-node@7.0.1: + resolution: {integrity: sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw==} + engines: {node: '>=4.2.0'} + hasBin: true + + tsconfig-paths@3.15.0: + resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + typescript@4.9.5: + resolution: {integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==} + engines: {node: '>=4.2.0'} + hasBin: true + + undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + + utf-8-validate@5.0.10: + resolution: {integrity: sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==} + engines: {node: '>=6.14.2'} + + uuid@8.3.2: + resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} + hasBin: true + + webidl-conversions@3.0.1: + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + + whatwg-url@5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + workerpool@6.2.0: + resolution: {integrity: sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==} + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + ws@7.5.10: + resolution: {integrity: sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==} + engines: {node: '>=8.3.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + ws@8.18.0: + resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + + yargs-parser@20.2.4: + resolution: {integrity: sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==} + engines: {node: '>=10'} + + yargs-unparser@2.0.0: + resolution: {integrity: sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==} + engines: {node: '>=10'} + + yargs@16.2.0: + resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} + engines: {node: '>=10'} + + yn@2.0.0: + resolution: {integrity: sha512-uTv8J/wiWTgUTg+9vLTi//leUl5vDQS6uii/emeTb2ssY7vl6QWf2fFbIIGjnhjvbdKlU0ed7QPgY1htTC86jQ==} + engines: {node: '>=4'} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + +snapshots: + + '@babel/runtime@7.26.7': + dependencies: + regenerator-runtime: 0.14.1 + + '@noble/curves@1.8.1': + dependencies: + '@noble/hashes': 1.7.1 + + '@noble/ed25519@1.7.3': {} + + '@noble/hashes@1.7.1': {} + + '@solana/buffer-layout@4.0.1': + dependencies: + buffer: 6.0.3 + + '@solana/web3.js@1.98.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)': + dependencies: + '@babel/runtime': 7.26.7 + '@noble/curves': 1.8.1 + '@noble/hashes': 1.7.1 + '@solana/buffer-layout': 4.0.1 + agentkeepalive: 4.6.0 + bigint-buffer: 1.1.5 + bn.js: 5.2.1 + borsh: 0.7.0 + bs58: 4.0.1 + buffer: 6.0.3 + fast-stable-stringify: 1.0.0 + jayson: 4.1.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) + node-fetch: 2.7.0 + rpc-websockets: 9.0.4 + superstruct: 2.0.2 + transitivePeerDependencies: + - bufferutil + - encoding + - utf-8-validate + + '@swc/helpers@0.5.15': + dependencies: + tslib: 2.8.1 + + '@types/connect@3.4.38': + dependencies: + '@types/node': 18.19.74 + + '@types/json5@0.0.29': + optional: true + + '@types/mocha@9.1.1': {} + + '@types/node@12.20.55': {} + + '@types/node@18.19.74': + dependencies: + undici-types: 5.26.5 + + '@types/uuid@8.3.4': {} + + '@types/ws@7.4.7': + dependencies: + '@types/node': 18.19.74 + + '@types/ws@8.5.14': + dependencies: + '@types/node': 18.19.74 + + '@ungap/promise-all-settled@1.1.2': {} + + JSONStream@1.3.5: + dependencies: + jsonparse: 1.3.1 + through: 2.3.8 + + agentkeepalive@4.6.0: + dependencies: + humanize-ms: 1.2.1 + + ansi-colors@4.1.1: {} + + ansi-regex@5.0.1: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + + argparse@2.0.1: {} + + arrify@1.0.1: {} + + balanced-match@1.0.2: {} + + base-x@3.0.10: + dependencies: + safe-buffer: 5.2.1 + + base64-js@1.5.1: {} + + bigint-buffer@1.1.5: + dependencies: + bindings: 1.5.0 + + binary-extensions@2.3.0: {} + + bindings@1.5.0: + dependencies: + file-uri-to-path: 1.0.0 + + bn.js@5.2.1: {} + + borsh@0.7.0: + dependencies: + bn.js: 5.2.1 + bs58: 4.0.1 + text-encoding-utf-8: 1.0.2 + + brace-expansion@1.1.11: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + browser-stdout@1.3.1: {} + + bs58@4.0.1: + dependencies: + base-x: 3.0.10 + + buffer-from@1.1.2: {} + + buffer@6.0.3: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + + bufferutil@4.0.9: + dependencies: + node-gyp-build: 4.8.4 + optional: true + + camelcase@6.3.0: {} + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + chokidar@3.5.3: + dependencies: + anymatch: 3.1.3 + braces: 3.0.3 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + + cliui@7.0.4: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + commander@2.20.3: {} + + concat-map@0.0.1: {} + + debug@4.3.3(supports-color@8.1.1): + dependencies: + ms: 2.1.2 + optionalDependencies: + supports-color: 8.1.1 + + decamelize@4.0.0: {} + + delay@5.0.0: {} + + diff@3.5.0: {} + + diff@5.0.0: {} + + emoji-regex@8.0.0: {} + + es6-promise@4.2.8: {} + + es6-promisify@5.0.0: + dependencies: + es6-promise: 4.2.8 + + escalade@3.2.0: {} + + escape-string-regexp@4.0.0: {} + + eventemitter3@5.0.1: {} + + eyes@0.1.8: {} + + fast-stable-stringify@1.0.0: {} + + file-uri-to-path@1.0.0: {} + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + flat@5.0.2: {} + + fs.realpath@1.0.0: {} + + fsevents@2.3.3: + optional: true + + get-caller-file@2.0.5: {} + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob@7.2.0: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + + growl@1.10.5: {} + + has-flag@4.0.0: {} + + he@1.2.0: {} + + humanize-ms@1.2.1: + dependencies: + ms: 2.1.3 + + ieee754@1.2.1: {} + + inflight@1.0.6: + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + + inherits@2.0.4: {} + + is-binary-path@2.1.0: + dependencies: + binary-extensions: 2.3.0 + + is-extglob@2.1.1: {} + + is-fullwidth-code-point@3.0.0: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-number@7.0.0: {} + + is-plain-obj@2.1.0: {} + + is-unicode-supported@0.1.0: {} + + isexe@2.0.0: {} + + isomorphic-ws@4.0.1(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10)): + dependencies: + ws: 7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10) + + jayson@4.1.3(bufferutil@4.0.9)(utf-8-validate@5.0.10): + dependencies: + '@types/connect': 3.4.38 + '@types/node': 12.20.55 + '@types/ws': 7.4.7 + JSONStream: 1.3.5 + commander: 2.20.3 + delay: 5.0.0 + es6-promisify: 5.0.0 + eyes: 0.1.8 + isomorphic-ws: 4.0.1(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + json-stringify-safe: 5.0.1 + uuid: 8.3.2 + ws: 7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10) + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + js-yaml@4.1.0: + dependencies: + argparse: 2.0.1 + + json-stringify-safe@5.0.1: {} + + json5@1.0.2: + dependencies: + minimist: 1.2.8 + optional: true + + jsonparse@1.3.1: {} + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + log-symbols@4.1.0: + dependencies: + chalk: 4.1.2 + is-unicode-supported: 0.1.0 + + make-error@1.3.6: {} + + minimatch@3.1.2: + dependencies: + brace-expansion: 1.1.11 + + minimatch@4.2.1: + dependencies: + brace-expansion: 1.1.11 + + minimist@1.2.8: {} + + mkdirp@0.5.6: + dependencies: + minimist: 1.2.8 + + mocha@9.2.2: + dependencies: + '@ungap/promise-all-settled': 1.1.2 + ansi-colors: 4.1.1 + browser-stdout: 1.3.1 + chokidar: 3.5.3 + debug: 4.3.3(supports-color@8.1.1) + diff: 5.0.0 + escape-string-regexp: 4.0.0 + find-up: 5.0.0 + glob: 7.2.0 + growl: 1.10.5 + he: 1.2.0 + js-yaml: 4.1.0 + log-symbols: 4.1.0 + minimatch: 4.2.1 + ms: 2.1.3 + nanoid: 3.3.1 + serialize-javascript: 6.0.0 + strip-json-comments: 3.1.1 + supports-color: 8.1.1 + which: 2.0.2 + workerpool: 6.2.0 + yargs: 16.2.0 + yargs-parser: 20.2.4 + yargs-unparser: 2.0.0 + + ms@2.1.2: {} + + ms@2.1.3: {} + + nanoid@3.3.1: {} + + node-fetch@2.7.0: + dependencies: + whatwg-url: 5.0.0 + + node-gyp-build@4.8.4: + optional: true + + normalize-path@3.0.0: {} + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + path-exists@4.0.0: {} + + path-is-absolute@1.0.1: {} + + picomatch@2.3.1: {} + + randombytes@2.1.0: + dependencies: + safe-buffer: 5.2.1 + + readdirp@3.6.0: + dependencies: + picomatch: 2.3.1 + + regenerator-runtime@0.14.1: {} + + require-directory@2.1.1: {} + + rpc-websockets@9.0.4: + dependencies: + '@swc/helpers': 0.5.15 + '@types/uuid': 8.3.4 + '@types/ws': 8.5.14 + buffer: 6.0.3 + eventemitter3: 5.0.1 + uuid: 8.3.2 + ws: 8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + optionalDependencies: + bufferutil: 4.0.9 + utf-8-validate: 5.0.10 + + safe-buffer@5.2.1: {} + + serialize-javascript@6.0.0: + dependencies: + randombytes: 2.1.0 + + solana-bankrun-darwin-arm64@0.3.1: + optional: true + + solana-bankrun-darwin-universal@0.3.1: + optional: true + + solana-bankrun-darwin-x64@0.3.1: + optional: true + + solana-bankrun-linux-x64-gnu@0.3.1: + optional: true + + solana-bankrun-linux-x64-musl@0.3.1: + optional: true + + solana-bankrun@0.3.1(bufferutil@4.0.9)(utf-8-validate@5.0.10): + dependencies: + '@solana/web3.js': 1.98.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + bs58: 4.0.1 + optionalDependencies: + solana-bankrun-darwin-arm64: 0.3.1 + solana-bankrun-darwin-universal: 0.3.1 + solana-bankrun-darwin-x64: 0.3.1 + solana-bankrun-linux-x64-gnu: 0.3.1 + solana-bankrun-linux-x64-musl: 0.3.1 + transitivePeerDependencies: + - bufferutil + - encoding + - utf-8-validate + + source-map-support@0.5.21: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + + source-map@0.6.1: {} + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-bom@3.0.0: + optional: true + + strip-json-comments@3.1.1: {} + + superstruct@2.0.2: {} + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-color@8.1.1: + dependencies: + has-flag: 4.0.0 + + text-encoding-utf-8@1.0.2: {} + + through@2.3.8: {} + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + tr46@0.0.3: {} + + ts-mocha@10.0.0(mocha@9.2.2): + dependencies: + mocha: 9.2.2 + ts-node: 7.0.1 + optionalDependencies: + tsconfig-paths: 3.15.0 + + ts-node@7.0.1: + dependencies: + arrify: 1.0.1 + buffer-from: 1.1.2 + diff: 3.5.0 + make-error: 1.3.6 + minimist: 1.2.8 + mkdirp: 0.5.6 + source-map-support: 0.5.21 + yn: 2.0.0 + + tsconfig-paths@3.15.0: + dependencies: + '@types/json5': 0.0.29 + json5: 1.0.2 + minimist: 1.2.8 + strip-bom: 3.0.0 + optional: true + + tslib@2.8.1: {} + + typescript@4.9.5: {} + + undici-types@5.26.5: {} + + utf-8-validate@5.0.10: + dependencies: + node-gyp-build: 4.8.4 + optional: true + + uuid@8.3.2: {} + + webidl-conversions@3.0.1: {} + + whatwg-url@5.0.0: + dependencies: + tr46: 0.0.3 + webidl-conversions: 3.0.1 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + workerpool@6.2.0: {} + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrappy@1.0.2: {} + + ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10): + optionalDependencies: + bufferutil: 4.0.9 + utf-8-validate: 5.0.10 + + ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10): + optionalDependencies: + bufferutil: 4.0.9 + utf-8-validate: 5.0.10 + + y18n@5.0.8: {} + + yargs-parser@20.2.4: {} + + yargs-unparser@2.0.0: + dependencies: + camelcase: 6.3.0 + decamelize: 4.0.0 + flat: 5.0.2 + is-plain-obj: 2.1.0 + + yargs@16.2.0: + dependencies: + cliui: 7.0.4 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 20.2.4 + + yn@2.0.0: {} + + yocto-queue@0.1.0: {} diff --git a/basics/ed25519-verification/native/program/Cargo.toml b/basics/ed25519-verification/native/program/Cargo.toml new file mode 100644 index 00000000..12f7129a --- /dev/null +++ b/basics/ed25519-verification/native/program/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "ed25519-custodial" +version = "0.1.0" +edition = "2021" +description = "Example Solana program demonstrating Ed25519 signature verification for custodied funds" + +[features] +no-entrypoint = [] + +[dependencies] +solana-program = "1.16" +thiserror = "1.0" + +[lib] +crate-type = ["cdylib", "lib"] \ No newline at end of file diff --git a/basics/ed25519-verification/native/program/src/lib.rs b/basics/ed25519-verification/native/program/src/lib.rs new file mode 100644 index 00000000..6e352756 --- /dev/null +++ b/basics/ed25519-verification/native/program/src/lib.rs @@ -0,0 +1,83 @@ +use solana_program::{ + account_info::{next_account_info, AccountInfo}, + entrypoint, + entrypoint::ProgramResult, + msg, + program_error::ProgramError, + pubkey::Pubkey, + ed25519_program, +}; + +entrypoint!(process_instruction); + +#[derive(Debug)] +pub struct TransferInstruction { + pub amount: u64, +} + +pub fn process_instruction( + _program_id: &Pubkey, + accounts: &[AccountInfo], + instruction_data: &[u8], +) -> ProgramResult { + let accounts_iter = &mut accounts.iter(); + + // Get account info + let custodial_account = next_account_info(accounts_iter)?; + let recipient = next_account_info(accounts_iter)?; + let signer = next_account_info(accounts_iter)?; + let ed25519_program_id = next_account_info(accounts_iter)?; + + // Verify this is the expected Ed25519 program + if ed25519_program_id.key != &ed25519_program::id() { + return Err(ProgramError::InvalidArgument); + } + + // First 64 bytes are the signature + let signature = &instruction_data[..64]; + // Next 32 bytes are the public key + let public_key = &instruction_data[64..96]; + // Next 8 bytes are the amount + let amount = u64::from_le_bytes(instruction_data[96..104].try_into().unwrap()); + // Remaining data is the message to verify + let message = &instruction_data[104..]; + + // Verify the Ed25519 signature + let verification_instruction = ed25519_program::instruction::new_ed25519_instruction( + public_key, + message, + signature, + ); + + // Invoke the Ed25519 program to verify the signature + solana_program::program::invoke( + &verification_instruction, + &[ed25519_program_id.clone()], + )?; + + msg!("Signature verification successful!"); + + // Transfer funds from custodial account to recipient + **custodial_account.try_borrow_mut_lamports()? = custodial_account + .lamports() + .checked_sub(amount) + .ok_or(ProgramError::InsufficientFunds)?; + + **recipient.try_borrow_mut_lamports()? = recipient + .lamports() + .checked_add(amount) + .ok_or(ProgramError::Overflow)?; + + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + use solana_program::clock::Epoch; + + #[test] + fn test_transfer_with_valid_signature() { + // Test implementation here + } +} \ No newline at end of file diff --git a/basics/ed25519-verification/native/tests/test.ts b/basics/ed25519-verification/native/tests/test.ts new file mode 100644 index 00000000..19464265 --- /dev/null +++ b/basics/ed25519-verification/native/tests/test.ts @@ -0,0 +1,71 @@ +import { Buffer } from 'node:buffer'; +import { describe, it } from 'node:test'; +import { sign } from '@noble/ed25519'; +import { + Connection, + Keypair, + LAMPORTS_PER_SOL, + PublicKey, + SystemProgram, + Transaction, + TransactionInstruction, + sendAndConfirmTransaction, +} from '@solana/web3.js'; +import { start } from 'solana-bankrun'; + +describe('Ed25519 Custodial Program', async () => { + const PROGRAM_ID = PublicKey.unique(); + const context = await start([{ name: 'ed25519_custodial', programId: PROGRAM_ID }], []); + const client = context.banksClient; + const payer = context.payer; + + it('should verify signature and transfer funds', async () => { + const custodialAccount = Keypair.generate(); + const recipient = Keypair.generate(); + const signerKeypair = Keypair.generate(); + const amount = 1000000; // lamports + + // Message to sign + const message = Buffer.from(`Transfer ${amount} lamports to ${recipient.publicKey.toBase58()}`); + + // Sign the message with Ed25519 + const signature = await sign(message, signerKeypair.secretKey.slice(0, 32)); + + // Create instruction data + const instructionData = Buffer.concat([ + Buffer.from(signature), + Buffer.from(signerKeypair.publicKey.toBytes()), + Buffer.from(new Uint8Array(new BigUint64Array([BigInt(amount)]).buffer)), + message, + ]); + + const instruction = new TransactionInstruction({ + keys: [ + { + pubkey: custodialAccount.publicKey, + isSigner: false, + isWritable: true, + }, + { pubkey: recipient.publicKey, isSigner: false, isWritable: true }, + { pubkey: signerKeypair.publicKey, isSigner: true, isWritable: false }, + { + pubkey: new PublicKey('Ed25519SigVerify111111111111111111111111111'), + isSigner: false, + isWritable: false, + }, + ], + programId: PROGRAM_ID, + data: instructionData, + }); + + const transaction = new Transaction().add(instruction); + + try { + await client.processTransaction(transaction); + console.log('Transaction processed successfully'); + } catch (error) { + console.error('Error:', error); + throw error; + } + }); +}); diff --git a/basics/ed25519-verification/native/tests/tsconfig.test.json b/basics/ed25519-verification/native/tests/tsconfig.test.json new file mode 100644 index 00000000..9ee40b52 --- /dev/null +++ b/basics/ed25519-verification/native/tests/tsconfig.test.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "types": ["mocha", "node"], + "typeRoots": ["../node_modules/@types"], + "lib": ["es2015"], + "module": "commonjs", + "target": "es6", + "esModuleInterop": true + } +} diff --git a/basics/ed25519-verification/poseidon/package.json b/basics/ed25519-verification/poseidon/package.json new file mode 100644 index 00000000..0c2b3788 --- /dev/null +++ b/basics/ed25519-verification/poseidon/package.json @@ -0,0 +1,25 @@ +{ + "name": "ed25519-custodial-poseidon", + "version": "1.0.0", + "scripts": { + "test": "jest", + "build": "tsc", + "lint": "eslint src/**/*.ts tests/**/*.ts", + "format": "prettier --write src/ tests/" + }, + "dependencies": { + "@solana/web3.js": "^1.95.2", + "@noble/ed25519": "^1.7.1" + }, + "devDependencies": { + "@types/jest": "^29.5.0", + "@types/node": "^18.0.0", + "@typescript-eslint/eslint-plugin": "^5.57.0", + "@typescript-eslint/parser": "^5.57.0", + "eslint": "^8.37.0", + "jest": "^29.5.0", + "prettier": "^2.8.7", + "ts-jest": "^29.1.0", + "typescript": "^5.0.3" + } +} diff --git a/basics/ed25519-verification/poseidon/src/program.ts b/basics/ed25519-verification/poseidon/src/program.ts new file mode 100644 index 00000000..d3ee5199 --- /dev/null +++ b/basics/ed25519-verification/poseidon/src/program.ts @@ -0,0 +1,68 @@ +import { sign } from '@noble/ed25519'; +import { Connection, Keypair, PublicKey, SystemProgram, TransactionInstruction, TransactionMessage, VersionedTransaction } from '@solana/web3.js'; + +export class Ed25519CustodialProgram { + constructor( + private connection: Connection, + private programId: PublicKey, + ) {} + + async createTransferInstruction( + custodialAccount: PublicKey, + recipient: PublicKey, + signer: Keypair, + amount: number, + ): Promise { + // Create message to sign + const message = Buffer.from(`Transfer ${amount} lamports to ${recipient.toBase58()}`); + + // Sign the message with Ed25519 + const signature = await sign(message, signer.secretKey.slice(0, 32)); + + // Create instruction data + const data = Buffer.concat([ + Buffer.from(signature), + Buffer.from(signer.publicKey.toBytes()), + Buffer.from(new Uint8Array(new BigUint64Array([BigInt(amount)]).buffer)), + message, + ]); + + return new TransactionInstruction({ + keys: [ + { pubkey: custodialAccount, isSigner: false, isWritable: true }, + { pubkey: recipient, isSigner: false, isWritable: true }, + { pubkey: signer.publicKey, isSigner: true, isWritable: false }, + { + pubkey: new PublicKey('Ed25519SigVerify111111111111111111111111111'), + isSigner: false, + isWritable: false, + }, + ], + programId: this.programId, + data, + }); + } + + async transfer(custodialAccount: PublicKey, recipient: PublicKey, signer: Keypair, amount: number, payer: Keypair): Promise { + const instruction = await this.createTransferInstruction(custodialAccount, recipient, signer, amount); + + const latestBlockhash = await this.connection.getLatestBlockhash(); + + const messageV0 = new TransactionMessage({ + payerKey: payer.publicKey, + recentBlockhash: latestBlockhash.blockhash, + instructions: [instruction], + }).compileToV0Message(); + + const transaction = new VersionedTransaction(messageV0); + transaction.sign([payer, signer]); + + const signature = await this.connection.sendTransaction(transaction); + await this.connection.confirmTransaction({ + signature, + ...latestBlockhash, + }); + + return signature; + } +} diff --git a/basics/ed25519-verification/poseidon/tests/program.test.ts b/basics/ed25519-verification/poseidon/tests/program.test.ts new file mode 100644 index 00000000..a9053423 --- /dev/null +++ b/basics/ed25519-verification/poseidon/tests/program.test.ts @@ -0,0 +1,43 @@ +import { describe, it } from 'node:test'; +import { Connection, Keypair, LAMPORTS_PER_SOL, PublicKey } from '@solana/web3.js'; +import { Ed25519CustodialProgram } from '../src/program'; + +describe('Ed25519 Custodial Program', () => { + const connection = new Connection('http://localhost:8899', 'confirmed'); + const programId = new PublicKey('your_program_id_here'); + const program = new Ed25519CustodialProgram(connection, programId); + + it('should create transfer instruction', async () => { + const custodialAccount = Keypair.generate(); + const recipient = Keypair.generate(); + const signer = Keypair.generate(); + const amount = LAMPORTS_PER_SOL; + + const instruction = await program.createTransferInstruction(custodialAccount.publicKey, recipient.publicKey, signer, amount); + + // Verify instruction structure + expect(instruction.programId).toEqual(programId); + expect(instruction.keys).toHaveLength(4); + expect(instruction.data).toBeDefined(); + }); + + it('should execute transfer', async () => { + const custodialAccount = Keypair.generate(); + const recipient = Keypair.generate(); + const signer = Keypair.generate(); + const payer = Keypair.generate(); + const amount = LAMPORTS_PER_SOL; + + // Fund accounts for testing + await connection.requestAirdrop(custodialAccount.publicKey, 2 * LAMPORTS_PER_SOL); + await connection.requestAirdrop(payer.publicKey, LAMPORTS_PER_SOL); + + const signature = await program.transfer(custodialAccount.publicKey, recipient.publicKey, signer, amount, payer); + + expect(signature).toBeDefined(); + + // Verify balances + const recipientBalance = await connection.getBalance(recipient.publicKey); + expect(recipientBalance).toEqual(amount); + }); +}); diff --git a/basics/ed25519-verification/poseidon/tsconfig.json b/basics/ed25519-verification/poseidon/tsconfig.json new file mode 100644 index 00000000..9d678580 --- /dev/null +++ b/basics/ed25519-verification/poseidon/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "target": "es2020", + "module": "commonjs", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "outDir": "./dist", + "declaration": true + }, + "include": ["src", "tests"], + "exclude": ["node_modules"] +} diff --git a/basics/ed25519-verification/steel/Cargo.toml b/basics/ed25519-verification/steel/Cargo.toml new file mode 100644 index 00000000..690481da --- /dev/null +++ b/basics/ed25519-verification/steel/Cargo.toml @@ -0,0 +1,10 @@ +[workspace] +members = [ + "api", + "program" +] +resolver = "2" + +[workspace.dependencies] +solana-program = "1.16" +steel = "0.3.0" \ No newline at end of file diff --git a/basics/ed25519-verification/steel/api/Cargo.toml b/basics/ed25519-verification/steel/api/Cargo.toml new file mode 100644 index 00000000..76f341e2 --- /dev/null +++ b/basics/ed25519-verification/steel/api/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "ed25519-custodial-api" +version = "0.1.0" +edition = "2021" + +[dependencies] +solana-program.workspace = true +steel.workspace = true \ No newline at end of file diff --git a/basics/ed25519-verification/steel/api/src/lib.rs b/basics/ed25519-verification/steel/api/src/lib.rs new file mode 100644 index 00000000..35b4f631 --- /dev/null +++ b/basics/ed25519-verification/steel/api/src/lib.rs @@ -0,0 +1,46 @@ +use solana_program::{ + instruction::{AccountMeta, Instruction}, + pubkey::Pubkey, + system_program, +}; +use steel::steel_api; + +#[steel_api] +pub mod ed25519_custodial { + use super::*; + + #[derive(Debug)] + pub struct TransferAccounts { + pub custodial_account: Pubkey, + pub recipient: Pubkey, + pub signer: Pubkey, + } + + pub fn transfer( + program_id: Pubkey, + accounts: TransferAccounts, + signature: [u8; 64], + public_key: [u8; 32], + message: Vec, + amount: u64, + ) -> Instruction { + let accounts = vec![ + AccountMeta::new(accounts.custodial_account, false), + AccountMeta::new(accounts.recipient, false), + AccountMeta::new_readonly(accounts.signer, true), + AccountMeta::new_readonly(system_program::id(), false), + ]; + + let mut data = Vec::with_capacity(104 + message.len()); + data.extend_from_slice(&signature); + data.extend_from_slice(&public_key); + data.extend_from_slice(&amount.to_le_bytes()); + data.extend_from_slice(&message); + + Instruction { + program_id, + accounts, + data, + } + } +} \ No newline at end of file diff --git a/basics/ed25519-verification/steel/package.json b/basics/ed25519-verification/steel/package.json new file mode 100644 index 00000000..b3823d19 --- /dev/null +++ b/basics/ed25519-verification/steel/package.json @@ -0,0 +1,8 @@ +{ + "scripts": { + "test": "steel test", + "build-and-test": "steel build && steel test", + "build": "steel build", + "deploy": "solana program deploy ./program/target/so/program.so" + } +} diff --git a/basics/ed25519-verification/steel/program/Cargo.toml b/basics/ed25519-verification/steel/program/Cargo.toml new file mode 100644 index 00000000..379c877d --- /dev/null +++ b/basics/ed25519-verification/steel/program/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "ed25519-custodial-program" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["cdylib", "lib"] + +[dependencies] +solana-program.workspace = true +steel.workspace = true \ No newline at end of file diff --git a/basics/ed25519-verification/steel/program/src/lib.rs b/basics/ed25519-verification/steel/program/src/lib.rs new file mode 100644 index 00000000..ade9ef88 --- /dev/null +++ b/basics/ed25519-verification/steel/program/src/lib.rs @@ -0,0 +1,61 @@ +use solana_program::{ + account_info::AccountInfo, + entrypoint::ProgramResult, + msg, + program_error::ProgramError, + pubkey::Pubkey, + ed25519_program, +}; +use steel::steel_program; + +#[steel_program] +pub mod ed25519_custodial { + use super::*; + + pub fn transfer( + program_id: &Pubkey, + accounts: &[AccountInfo], + signature: [u8; 64], + public_key: [u8; 32], + message: Vec, + amount: u64, + ) -> ProgramResult { + let custodial_account = &accounts[0]; + let recipient = &accounts[1]; + let signer = &accounts[2]; + let ed25519_program_id = &accounts[3]; + + // Verify this is the expected Ed25519 program + if ed25519_program_id.key != &ed25519_program::id() { + return Err(ProgramError::InvalidArgument); + } + + // Verify the Ed25519 signature + let verification_instruction = ed25519_program::instruction::new_ed25519_instruction( + &public_key, + &message, + &signature, + ); + + // Invoke the Ed25519 program to verify the signature + solana_program::program::invoke( + &verification_instruction, + &[ed25519_program_id.clone()], + )?; + + msg!("Signature verification successful!"); + + // Transfer funds + **custodial_account.try_borrow_mut_lamports()? = custodial_account + .lamports() + .checked_sub(amount) + .ok_or(ProgramError::InsufficientFunds)?; + + **recipient.try_borrow_mut_lamports()? = recipient + .lamports() + .checked_add(amount) + .ok_or(ProgramError::Overflow)?; + + Ok(()) + } +} \ No newline at end of file diff --git a/basics/ed25519-verification/steel/program/tests/test.rs b/basics/ed25519-verification/steel/program/tests/test.rs new file mode 100644 index 00000000..28d68630 --- /dev/null +++ b/basics/ed25519-verification/steel/program/tests/test.rs @@ -0,0 +1,47 @@ +use { + ed25519_custodial_api::ed25519_custodial, + solana_program::{pubkey::Pubkey, system_program}, + solana_program_test::*, + solana_sdk::{signature::Keypair, signer::Signer}, + steel_test::*, +}; + +#[tokio::test] +async fn test_ed25519_transfer() { + let program_id = Pubkey::new_unique(); + let mut context = program_test() + .add_program("ed25519_custodial", program_id) + .start_with_context() + .await; + + let custodial_account = Keypair::new(); + let recipient = Keypair::new(); + let signer = Keypair::new(); + let amount = 1_000_000; + + // Create test message and signature + let message = format!("Transfer {} lamports to {}", amount, recipient.pubkey()); + let signature = signer.sign_message(message.as_bytes()); + + let accounts = ed25519_custodial::TransferAccounts { + custodial_account: custodial_account.pubkey(), + recipient: recipient.pubkey(), + signer: signer.pubkey(), + }; + + let ix = ed25519_custodial::transfer( + program_id, + accounts, + signature.to_bytes(), + signer.pubkey().to_bytes(), + message.as_bytes().to_vec(), + amount, + ); + + let result = context + .banks_client + .process_transaction(&[ix], &[&signer]) + .await; + + assert!(result.is_ok()); +} \ No newline at end of file