From 412749bff249a20e303599c233113e51b2329dd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=ADas=20Mart=C3=ADnez?= <131624652+mat1asm@users.noreply.github.com> Date: Mon, 1 Apr 2024 11:36:18 -0300 Subject: [PATCH] [be] logging instruction data of signed txs (#53) * claim info extraction * decoded data logger * simplify test * pushing to influx * Update address mapping (WIP) * testing data points persistence * remove todo * Fix address mapping|add influx token from secrets --------- Co-authored-by: Abhishek Rajput --- backend/package.json | 6 + backend/src/config.ts | 17 +- backend/src/handlers/fund-transactions.ts | 18 +- backend/src/token-dispenser.json | 653 -------- backend/src/token-dispenser.ts | 1310 +++++++++++++++++ backend/src/types.ts | 10 + backend/src/utils/discord.ts | 7 +- backend/src/utils/fund-transactions.ts | 35 + backend/src/utils/persistence.ts | 128 ++ backend/src/utils/secrets.ts | 26 +- .../test/handlers/fund-transactions.test.ts | 127 +- backend/yarn.lock | 655 ++++++++- 12 files changed, 2287 insertions(+), 705 deletions(-) delete mode 100644 backend/src/token-dispenser.json create mode 100644 backend/src/token-dispenser.ts create mode 100644 backend/src/utils/persistence.ts diff --git a/backend/package.json b/backend/package.json index 26f84d63..d79178fe 100644 --- a/backend/package.json +++ b/backend/package.json @@ -15,8 +15,13 @@ "dependencies": { "@aws-sdk/client-secrets-manager": "^3.535.0", "@coral-xyz/anchor": "^0.29.0", + "@cosmjs/amino": "^0.32.3", + "@cosmjs/crypto": "^0.32.3", + "@cosmjs/encoding": "^0.32.3", + "@influxdata/influxdb-client": "^1.33.2", "@solana/web3.js": "^1.91.1", "bs58": "^5.0.0", + "hi-base32": "^0.5.1", "tweetnacl": "^1.0.3" }, "devDependencies": { @@ -37,6 +42,7 @@ "jest": "^29.7.0", "msw": "^2.2.9", "prettier": "^2.7.1", + "testcontainers": "^10.8.0", "typescript": "^5.4.2" }, "jest": { diff --git a/backend/src/config.ts b/backend/src/config.ts index 9bdba4ca..7b44ab5b 100644 --- a/backend/src/config.ts +++ b/backend/src/config.ts @@ -6,7 +6,7 @@ export default { region: process.env.AWS_REGION ?? 'us-east-2' }, tokenDispenserProgramId: () => process.env.TOKEN_DISPENSER_PROGRAM_ID, - keys: { + secrets: { dispenserGuard: { /** optional. mostly for local testing */ key: process.env.DISPENSER_WALLET_KEY, @@ -16,11 +16,24 @@ export default { }, funding: { /** optional. mostly for local testing */ - key: process.env.FUNDING_WALLET_KEY, + key: () => process.env.FUNDING_WALLET_KEY, /** required. with a default value and used when when key not set */ secretName: process.env.FUNDER_WALLET_KEY_SECRET_NAME ?? 'xli-test-secret-funder-wallet' + }, + influx: { + key: () => process.env.INFLUXDB_TOKEN, + /** required. with a default value */ + secretName: process.env.IDB_SECRET_NAME ?? 'xl-ad-idb' } + }, + influx: { + url: () => process.env.INFLUXDB_URL ?? 'http://localhost:8086', + org: () => process.env.INFLUXDB_ORG ?? 'xl', + bucket: () => process.env.INFLUXDB_BUCKET ?? 'ad', + token: () => process.env.INFLUXDB_TOKEN, + timeout: () => parseInt(process.env.INFLUXDB_TIMEOUT_MS ?? '20500'), + isFlushEnabled: () => process.env.INFLUXDB_FLUSH_ENABLED === 'true' ?? false } } diff --git a/backend/src/handlers/fund-transactions.ts b/backend/src/handlers/fund-transactions.ts index fcfe5ecd..443ea1d7 100644 --- a/backend/src/handlers/fund-transactions.ts +++ b/backend/src/handlers/fund-transactions.ts @@ -3,12 +3,15 @@ import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda' import { getFundingKey } from '../utils/secrets' import { checkTransactions, - deserializeTransactions + deserializeTransactions, + extractCallData } from '../utils/fund-transactions' import { Keypair, VersionedTransaction } from '@solana/web3.js' import bs58 from 'bs58' import { HandlerError } from '../utils/errors' import { asJsonResponse } from '../utils/response' +import { ClaimSignature } from '../types' +import { saveSignedTransactions } from '../utils/persistence' export type FundTransactionRequest = Uint8Array[] @@ -30,7 +33,8 @@ export const fundTransactions = async ( const wallet = await loadFunderWallet() const signedTransactions = await wallet.signAllTransactions(transactions) - logSignatures(signedTransactions) + await saveSignedTransactions(getSignatures(signedTransactions)) + return asJsonResponse( 200, signedTransactions.map((tx) => Buffer.from(tx.serialize())) @@ -79,10 +83,12 @@ function getSignature(tx: VersionedTransaction): string { return 'unkown signature' } -function logSignatures(signedTransactions: VersionedTransaction[]) { - const sigs: string[] = [] +function getSignatures(signedTransactions: VersionedTransaction[]) { + const sigs: ClaimSignature[] = [] signedTransactions.forEach((tx) => { - sigs.push(getSignature(tx)) + sigs.push({ sig: getSignature(tx), instruction: extractCallData(tx) }) }) - console.log(`Signed transactions: ${sigs}`) + console.log(`Signed transactions: ${JSON.stringify(sigs)}`) + + return sigs } diff --git a/backend/src/token-dispenser.json b/backend/src/token-dispenser.json deleted file mode 100644 index 277238a0..00000000 --- a/backend/src/token-dispenser.json +++ /dev/null @@ -1,653 +0,0 @@ -{ - "version": "0.1.0", - "name": "token_dispenser", - "instructions": [ - { - "name": "initialize", - "docs": [ - "This can only be called once and should be called right after the program is deployed." - ], - "accounts": [ - { - "name": "payer", - "isMut": true, - "isSigner": true - }, - { - "name": "config", - "isMut": true, - "isSigner": false - }, - { - "name": "mint", - "isMut": false, - "isSigner": false, - "docs": ["Mint of the treasury"] - }, - { - "name": "treasury", - "isMut": false, - "isSigner": false, - "docs": [ - "Treasury token account. This is an externally owned token account and", - "the owner of this account will approve the config as a delegate using the", - "solana CLI command `spl-token approve `" - ] - }, - { - "name": "systemProgram", - "isMut": false, - "isSigner": false - }, - { - "name": "addressLookupTable", - "isMut": false, - "isSigner": false - } - ], - "args": [ - { - "name": "merkleRoot", - "type": { - "array": ["u8", 20] - } - }, - { - "name": "dispenserGuard", - "type": "publicKey" - }, - { - "name": "funder", - "type": "publicKey" - }, - { - "name": "maxTransfer", - "type": "u64" - } - ] - }, - { - "name": "claim", - "docs": [ - "* Claim a claimant's tokens. This instructions needs to enforce :\n * - The dispenser guard has signed the transaction - DONE\n * - The claimant is claiming no more than once per ecosystem - DONE\n * - The claimant has provided a valid proof of identity (is the owner of the wallet\n * entitled to the tokens)\n * - The claimant has provided a valid proof of inclusion (this confirm that the claimant --\n * DONE\n * - The claimant has not already claimed tokens -- DONE" - ], - "accounts": [ - { - "name": "funder", - "isMut": true, - "isSigner": true - }, - { - "name": "claimant", - "isMut": false, - "isSigner": true - }, - { - "name": "claimantFund", - "isMut": true, - "isSigner": false, - "docs": [ - "Claimant's associated token account to receive the tokens", - "Should be initialized outside of this program." - ] - }, - { - "name": "config", - "isMut": false, - "isSigner": false - }, - { - "name": "mint", - "isMut": false, - "isSigner": false - }, - { - "name": "treasury", - "isMut": true, - "isSigner": false - }, - { - "name": "tokenProgram", - "isMut": false, - "isSigner": false - }, - { - "name": "systemProgram", - "isMut": false, - "isSigner": false - }, - { - "name": "sysvarInstruction", - "isMut": false, - "isSigner": false, - "docs": [ - "CHECK : Anchor wants me to write this comment because I'm using AccountInfo which doesn't check for ownership and doesn't deserialize the account automatically. But it's fine because I check the address and I load it using load_instruction_at_checked." - ] - }, - { - "name": "associatedTokenProgram", - "isMut": false, - "isSigner": false - } - ], - "args": [ - { - "name": "claimCertificate", - "type": { - "defined": "ClaimCertificate" - } - } - ] - } - ], - "accounts": [ - { - "name": "Config", - "type": { - "kind": "struct", - "fields": [ - { - "name": "bump", - "type": "u8" - }, - { - "name": "merkleRoot", - "type": { - "array": ["u8", 20] - } - }, - { - "name": "dispenserGuard", - "type": "publicKey" - }, - { - "name": "mint", - "type": "publicKey" - }, - { - "name": "treasury", - "type": "publicKey" - }, - { - "name": "addressLookupTable", - "type": "publicKey" - }, - { - "name": "funder", - "type": "publicKey" - }, - { - "name": "maxTransfer", - "type": "u64" - } - ] - } - }, - { - "name": "Receipt", - "type": { - "kind": "struct", - "fields": [] - } - } - ], - "types": [ - { - "name": "CosmosMessage", - "docs": [ - "* An ADR036 message used in Cosmos. ADR036 is a standard for signing arbitrary data.\n* Only the message payload is stored in this struct.\n* The message signed for Cosmos is a JSON serialized CosmosStdSignDoc containing the payload and ADR036 compliant parameters.\n* The message also contains the bech32 address of the signer. We check that the signer corresponds to the public key." - ], - "type": { - "kind": "struct", - "fields": [ - { - "name": "payload", - "type": "bytes" - }, - { - "name": "signer", - "type": "string" - } - ] - } - }, - { - "name": "DiscordMessage", - "docs": [ - "* This message (borsh-serialized) needs to be signed by the dispenser guard after\n * verifying the claimant's pubkey controls the discord account.\n * The dispenser guard key should not be used for anything else." - ], - "type": { - "kind": "struct", - "fields": [ - { - "name": "username", - "type": "string" - }, - { - "name": "claimant", - "type": "publicKey" - } - ] - } - }, - { - "name": "Ed25519InstructionHeader", - "type": { - "kind": "struct", - "fields": [ - { - "name": "numSignatures", - "type": "u8" - }, - { - "name": "padding", - "type": "u8" - }, - { - "name": "signatureOffset", - "type": "u16" - }, - { - "name": "signatureInstructionIndex", - "type": "u16" - }, - { - "name": "publicKeyOffset", - "type": "u16" - }, - { - "name": "publicKeyInstructionIndex", - "type": "u16" - }, - { - "name": "messageDataOffset", - "type": "u16" - }, - { - "name": "messageDataSize", - "type": "u16" - }, - { - "name": "messageInstructionIndex", - "type": "u16" - } - ] - } - }, - { - "name": "Secp256k1InstructionHeader", - "type": { - "kind": "struct", - "fields": [ - { - "name": "numSignatures", - "type": "u8" - }, - { - "name": "signatureOffset", - "type": "u16" - }, - { - "name": "signatureInstructionIndex", - "type": "u8" - }, - { - "name": "ethAddressOffset", - "type": "u16" - }, - { - "name": "ethAddressInstructionIndex", - "type": "u8" - }, - { - "name": "messageDataOffset", - "type": "u16" - }, - { - "name": "messageDataSize", - "type": "u16" - }, - { - "name": "messageInstructionIndex", - "type": "u8" - } - ] - } - }, - { - "name": "ClaimInfo", - "type": { - "kind": "struct", - "fields": [ - { - "name": "identity", - "type": { - "defined": "Identity" - } - }, - { - "name": "amount", - "type": "u64" - } - ] - } - }, - { - "name": "ClaimCertificate", - "type": { - "kind": "struct", - "fields": [ - { - "name": "amount", - "type": "u64" - }, - { - "name": "proofOfIdentity", - "type": { - "defined": "IdentityCertificate" - } - }, - { - "name": "proofOfInclusion", - "type": { - "vec": { - "array": ["u8", 20] - } - } - } - ] - } - }, - { - "name": "Identity", - "docs": [ - "* This is the identity that the claimant will use to claim tokens.\n * A claimant can claim tokens for 1 identity on each ecosystem.\n * Typically for a blockchain it is a public key in the blockchain's address space." - ], - "type": { - "kind": "enum", - "variants": [ - { - "name": "Discord", - "fields": [ - { - "name": "username", - "type": "string" - } - ] - }, - { - "name": "Solana", - "fields": [ - { - "name": "pubkey", - "type": { - "array": ["u8", 32] - } - } - ] - }, - { - "name": "Evm", - "fields": [ - { - "name": "pubkey", - "type": { - "array": ["u8", 20] - } - } - ] - }, - { - "name": "Sui", - "fields": [ - { - "name": "address", - "type": { - "array": ["u8", 32] - } - } - ] - }, - { - "name": "Aptos", - "fields": [ - { - "name": "address", - "type": { - "array": ["u8", 32] - } - } - ] - }, - { - "name": "Cosmwasm", - "fields": [ - { - "name": "address", - "type": "string" - } - ] - }, - { - "name": "Injective", - "fields": [ - { - "name": "address", - "type": "string" - } - ] - }, - { - "name": "Algorand", - "fields": [ - { - "name": "pubkey", - "type": { - "array": ["u8", 32] - } - } - ] - } - ] - } - }, - { - "name": "IdentityCertificate", - "type": { - "kind": "enum", - "variants": [ - { - "name": "Discord", - "fields": [ - { - "name": "username", - "type": "string" - }, - { - "name": "verification_instruction_index", - "type": "u8" - } - ] - }, - { - "name": "Evm", - "fields": [ - { - "name": "pubkey", - "type": { - "array": ["u8", 20] - } - }, - { - "name": "verification_instruction_index", - "type": "u8" - } - ] - }, - { - "name": "Solana" - }, - { - "name": "Sui", - "fields": [ - { - "name": "pubkey", - "type": { - "array": ["u8", 32] - } - }, - { - "name": "verification_instruction_index", - "type": "u8" - } - ] - }, - { - "name": "Aptos", - "fields": [ - { - "name": "pubkey", - "type": { - "array": ["u8", 32] - } - }, - { - "name": "verification_instruction_index", - "type": "u8" - } - ] - }, - { - "name": "Cosmwasm", - "fields": [ - { - "name": "chain_id", - "type": "string" - }, - { - "name": "signature", - "type": { - "array": ["u8", 64] - } - }, - { - "name": "recovery_id", - "type": "u8" - }, - { - "name": "pubkey", - "type": { - "array": ["u8", 65] - } - }, - { - "name": "message", - "type": "bytes" - } - ] - }, - { - "name": "Injective", - "fields": [ - { - "name": "pubkey", - "type": { - "array": ["u8", 20] - } - }, - { - "name": "verification_instruction_index", - "type": "u8" - } - ] - }, - { - "name": "Algorand", - "fields": [ - { - "name": "pubkey", - "type": { - "array": ["u8", 32] - } - }, - { - "name": "verification_instruction_index", - "type": "u8" - } - ] - } - ] - } - } - ], - "events": [ - { - "name": "ClaimEvent", - "fields": [ - { - "name": "remainingBalance", - "type": "u64", - "index": false - }, - { - "name": "claimant", - "type": "publicKey", - "index": false - }, - { - "name": "claimInfo", - "type": { - "defined": "ClaimInfo" - }, - "index": false - } - ] - } - ], - "errors": [ - { - "code": 6000, - "name": "AlreadyClaimed" - }, - { - "code": 6001, - "name": "InvalidInclusionProof" - }, - { - "code": 6002, - "name": "WrongPda" - }, - { - "code": 6003, - "name": "SignatureVerificationWrongProgram" - }, - { - "code": 6004, - "name": "SignatureVerificationWrongAccounts" - }, - { - "code": 6005, - "name": "SignatureVerificationWrongHeader" - }, - { - "code": 6006, - "name": "SignatureVerificationWrongPayload" - }, - { - "code": 6007, - "name": "SignatureVerificationWrongPayloadMetadata" - }, - { - "code": 6008, - "name": "SignatureVerificationWrongSigner" - }, - { - "code": 6009, - "name": "UnauthorizedCosmosChainId" - }, - { - "code": 6010, - "name": "TransferExceedsMax" - } - ] -} diff --git a/backend/src/token-dispenser.ts b/backend/src/token-dispenser.ts new file mode 100644 index 00000000..5a2f2a4b --- /dev/null +++ b/backend/src/token-dispenser.ts @@ -0,0 +1,1310 @@ +import { BorshCoder } from '@coral-xyz/anchor' + +export type TokenDispenser = { + version: '0.1.0' + name: 'token_dispenser' + instructions: [ + { + name: 'initialize' + docs: [ + 'This can only be called once and should be called right after the program is deployed.' + ] + accounts: [ + { + name: 'payer' + isMut: true + isSigner: true + }, + { + name: 'config' + isMut: true + isSigner: false + }, + { + name: 'mint' + isMut: false + isSigner: false + docs: ['Mint of the treasury'] + }, + { + name: 'treasury' + isMut: false + isSigner: false + docs: [ + 'Treasury token account. This is an externally owned token account and', + 'the owner of this account will approve the config as a delegate using the', + 'solana CLI command `spl-token approve `' + ] + }, + { + name: 'systemProgram' + isMut: false + isSigner: false + }, + { + name: 'addressLookupTable' + isMut: false + isSigner: false + } + ] + args: [ + { + name: 'merkleRoot' + type: { + array: ['u8', 20] + } + }, + { + name: 'dispenserGuard' + type: 'publicKey' + }, + { + name: 'funder' + type: 'publicKey' + }, + { + name: 'maxTransfer' + type: 'u64' + } + ] + }, + { + name: 'claim' + docs: [ + "* Claim a claimant's tokens. This instructions needs to enforce :\n * - The dispenser guard has signed the transaction - DONE\n * - The claimant is claiming no more than once per ecosystem - DONE\n * - The claimant has provided a valid proof of identity (is the owner of the wallet\n * entitled to the tokens)\n * - The claimant has provided a valid proof of inclusion (this confirm that the claimant --\n * DONE\n * - The claimant has not already claimed tokens -- DONE" + ] + accounts: [ + { + name: 'funder' + isMut: true + isSigner: true + }, + { + name: 'claimant' + isMut: false + isSigner: true + }, + { + name: 'claimantFund' + isMut: true + isSigner: false + docs: [ + "Claimant's associated token account to receive the tokens", + 'Should be initialized outside of this program.' + ] + }, + { + name: 'config' + isMut: false + isSigner: false + }, + { + name: 'mint' + isMut: false + isSigner: false + }, + { + name: 'treasury' + isMut: true + isSigner: false + }, + { + name: 'tokenProgram' + isMut: false + isSigner: false + }, + { + name: 'systemProgram' + isMut: false + isSigner: false + }, + { + name: 'sysvarInstruction' + isMut: false + isSigner: false + docs: [ + "CHECK : Anchor wants me to write this comment because I'm using AccountInfo which doesn't check for ownership and doesn't deserialize the account automatically. But it's fine because I check the address and I load it using load_instruction_at_checked." + ] + }, + { + name: 'associatedTokenProgram' + isMut: false + isSigner: false + } + ] + args: [ + { + name: 'claimCertificate' + type: { + defined: 'ClaimCertificate' + } + } + ] + } + ] + accounts: [ + { + name: 'Config' + type: { + kind: 'struct' + fields: [ + { + name: 'bump' + type: 'u8' + }, + { + name: 'merkleRoot' + type: { + array: ['u8', 20] + } + }, + { + name: 'dispenserGuard' + type: 'publicKey' + }, + { + name: 'mint' + type: 'publicKey' + }, + { + name: 'treasury' + type: 'publicKey' + }, + { + name: 'addressLookupTable' + type: 'publicKey' + }, + { + name: 'funder' + type: 'publicKey' + }, + { + name: 'maxTransfer' + type: 'u64' + } + ] + } + }, + { + name: 'Receipt' + type: { + kind: 'struct' + fields: [] + } + } + ] + types: [ + { + name: 'CosmosMessage' + docs: [ + '* An ADR036 message used in Cosmos. ADR036 is a standard for signing arbitrary data.\n* Only the message payload is stored in this struct.\n* The message signed for Cosmos is a JSON serialized CosmosStdSignDoc containing the payload and ADR036 compliant parameters.\n* The message also contains the bech32 address of the signer. We check that the signer corresponds to the public key.' + ] + type: { + kind: 'struct' + fields: [ + { + name: 'payload' + type: 'bytes' + }, + { + name: 'signer' + type: 'string' + } + ] + } + }, + { + name: 'DiscordMessage' + docs: [ + "* This message (borsh-serialized) needs to be signed by the dispenser guard after\n * verifying the claimant's pubkey controls the discord account.\n * The dispenser guard key should not be used for anything else." + ] + type: { + kind: 'struct' + fields: [ + { + name: 'username' + type: 'string' + }, + { + name: 'claimant' + type: 'publicKey' + } + ] + } + }, + { + name: 'Ed25519InstructionHeader' + type: { + kind: 'struct' + fields: [ + { + name: 'numSignatures' + type: 'u8' + }, + { + name: 'padding' + type: 'u8' + }, + { + name: 'signatureOffset' + type: 'u16' + }, + { + name: 'signatureInstructionIndex' + type: 'u16' + }, + { + name: 'publicKeyOffset' + type: 'u16' + }, + { + name: 'publicKeyInstructionIndex' + type: 'u16' + }, + { + name: 'messageDataOffset' + type: 'u16' + }, + { + name: 'messageDataSize' + type: 'u16' + }, + { + name: 'messageInstructionIndex' + type: 'u16' + } + ] + } + }, + { + name: 'Secp256k1InstructionHeader' + type: { + kind: 'struct' + fields: [ + { + name: 'numSignatures' + type: 'u8' + }, + { + name: 'signatureOffset' + type: 'u16' + }, + { + name: 'signatureInstructionIndex' + type: 'u8' + }, + { + name: 'ethAddressOffset' + type: 'u16' + }, + { + name: 'ethAddressInstructionIndex' + type: 'u8' + }, + { + name: 'messageDataOffset' + type: 'u16' + }, + { + name: 'messageDataSize' + type: 'u16' + }, + { + name: 'messageInstructionIndex' + type: 'u8' + } + ] + } + }, + { + name: 'ClaimInfo' + type: { + kind: 'struct' + fields: [ + { + name: 'identity' + type: { + defined: 'Identity' + } + }, + { + name: 'amount' + type: 'u64' + } + ] + } + }, + { + name: 'ClaimCertificate' + type: { + kind: 'struct' + fields: [ + { + name: 'amount' + type: 'u64' + }, + { + name: 'proofOfIdentity' + type: { + defined: 'IdentityCertificate' + } + }, + { + name: 'proofOfInclusion' + type: { + vec: { + array: ['u8', 20] + } + } + } + ] + } + }, + { + name: 'Identity' + docs: [ + "* This is the identity that the claimant will use to claim tokens.\n * A claimant can claim tokens for 1 identity on each ecosystem.\n * Typically for a blockchain it is a public key in the blockchain's address space." + ] + type: { + kind: 'enum' + variants: [ + { + name: 'Discord' + fields: [ + { + name: 'username' + type: 'string' + } + ] + }, + { + name: 'Solana' + fields: [ + { + name: 'pubkey' + type: { + array: ['u8', 32] + } + } + ] + }, + { + name: 'Evm' + fields: [ + { + name: 'pubkey' + type: { + array: ['u8', 20] + } + } + ] + }, + { + name: 'Sui' + fields: [ + { + name: 'address' + type: { + array: ['u8', 32] + } + } + ] + }, + { + name: 'Aptos' + fields: [ + { + name: 'address' + type: { + array: ['u8', 32] + } + } + ] + }, + { + name: 'Cosmwasm' + fields: [ + { + name: 'address' + type: 'string' + } + ] + }, + { + name: 'Injective' + fields: [ + { + name: 'address' + type: 'string' + } + ] + }, + { + name: 'Algorand' + fields: [ + { + name: 'pubkey' + type: { + array: ['u8', 32] + } + } + ] + } + ] + } + }, + { + name: 'IdentityCertificate' + type: { + kind: 'enum' + variants: [ + { + name: 'Discord' + fields: [ + { + name: 'username' + type: 'string' + }, + { + name: 'verification_instruction_index' + type: 'u8' + } + ] + }, + { + name: 'Evm' + fields: [ + { + name: 'pubkey' + type: { + array: ['u8', 20] + } + }, + { + name: 'verification_instruction_index' + type: 'u8' + } + ] + }, + { + name: 'Solana' + }, + { + name: 'Sui' + fields: [ + { + name: 'pubkey' + type: { + array: ['u8', 32] + } + }, + { + name: 'verification_instruction_index' + type: 'u8' + } + ] + }, + { + name: 'Aptos' + fields: [ + { + name: 'pubkey' + type: { + array: ['u8', 32] + } + }, + { + name: 'verification_instruction_index' + type: 'u8' + } + ] + }, + { + name: 'Cosmwasm' + fields: [ + { + name: 'chain_id' + type: 'string' + }, + { + name: 'signature' + type: { + array: ['u8', 64] + } + }, + { + name: 'recovery_id' + type: 'u8' + }, + { + name: 'pubkey' + type: { + array: ['u8', 65] + } + }, + { + name: 'message' + type: 'bytes' + } + ] + }, + { + name: 'Injective' + fields: [ + { + name: 'pubkey' + type: { + array: ['u8', 20] + } + }, + { + name: 'verification_instruction_index' + type: 'u8' + } + ] + }, + { + name: 'Algorand' + fields: [ + { + name: 'pubkey' + type: { + array: ['u8', 32] + } + }, + { + name: 'verification_instruction_index' + type: 'u8' + } + ] + } + ] + } + } + ] + events: [ + { + name: 'ClaimEvent' + fields: [ + { + name: 'remainingBalance' + type: 'u64' + index: false + }, + { + name: 'claimant' + type: 'publicKey' + index: false + }, + { + name: 'claimInfo' + type: { + defined: 'ClaimInfo' + } + index: false + } + ] + } + ] + errors: [ + { + code: 6000 + name: 'AlreadyClaimed' + }, + { + code: 6001 + name: 'InvalidInclusionProof' + }, + { + code: 6002 + name: 'WrongPda' + }, + { + code: 6003 + name: 'SignatureVerificationWrongProgram' + }, + { + code: 6004 + name: 'SignatureVerificationWrongAccounts' + }, + { + code: 6005 + name: 'SignatureVerificationWrongHeader' + }, + { + code: 6006 + name: 'SignatureVerificationWrongPayload' + }, + { + code: 6007 + name: 'SignatureVerificationWrongPayloadMetadata' + }, + { + code: 6008 + name: 'SignatureVerificationWrongSigner' + }, + { + code: 6009 + name: 'UnauthorizedCosmosChainId' + }, + { + code: 6010 + name: 'TransferExceedsMax' + } + ] +} +export const IDL: TokenDispenser = { + version: '0.1.0', + name: 'token_dispenser', + instructions: [ + { + name: 'initialize', + docs: [ + 'This can only be called once and should be called right after the program is deployed.' + ], + accounts: [ + { + name: 'payer', + isMut: true, + isSigner: true + }, + { + name: 'config', + isMut: true, + isSigner: false + }, + { + name: 'mint', + isMut: false, + isSigner: false, + docs: ['Mint of the treasury'] + }, + { + name: 'treasury', + isMut: false, + isSigner: false, + docs: [ + 'Treasury token account. This is an externally owned token account and', + 'the owner of this account will approve the config as a delegate using the', + 'solana CLI command `spl-token approve `' + ] + }, + { + name: 'systemProgram', + isMut: false, + isSigner: false + }, + { + name: 'addressLookupTable', + isMut: false, + isSigner: false + } + ], + args: [ + { + name: 'merkleRoot', + type: { + array: ['u8', 20] + } + }, + { + name: 'dispenserGuard', + type: 'publicKey' + }, + { + name: 'funder', + type: 'publicKey' + }, + { + name: 'maxTransfer', + type: 'u64' + } + ] + }, + { + name: 'claim', + docs: [ + "* Claim a claimant's tokens. This instructions needs to enforce :\n * - The dispenser guard has signed the transaction - DONE\n * - The claimant is claiming no more than once per ecosystem - DONE\n * - The claimant has provided a valid proof of identity (is the owner of the wallet\n * entitled to the tokens)\n * - The claimant has provided a valid proof of inclusion (this confirm that the claimant --\n * DONE\n * - The claimant has not already claimed tokens -- DONE" + ], + accounts: [ + { + name: 'funder', + isMut: true, + isSigner: true + }, + { + name: 'claimant', + isMut: false, + isSigner: true + }, + { + name: 'claimantFund', + isMut: true, + isSigner: false, + docs: [ + "Claimant's associated token account to receive the tokens", + 'Should be initialized outside of this program.' + ] + }, + { + name: 'config', + isMut: false, + isSigner: false + }, + { + name: 'mint', + isMut: false, + isSigner: false + }, + { + name: 'treasury', + isMut: true, + isSigner: false + }, + { + name: 'tokenProgram', + isMut: false, + isSigner: false + }, + { + name: 'systemProgram', + isMut: false, + isSigner: false + }, + { + name: 'sysvarInstruction', + isMut: false, + isSigner: false, + docs: [ + "CHECK : Anchor wants me to write this comment because I'm using AccountInfo which doesn't check for ownership and doesn't deserialize the account automatically. But it's fine because I check the address and I load it using load_instruction_at_checked." + ] + }, + { + name: 'associatedTokenProgram', + isMut: false, + isSigner: false + } + ], + args: [ + { + name: 'claimCertificate', + type: { + defined: 'ClaimCertificate' + } + } + ] + } + ], + accounts: [ + { + name: 'Config', + type: { + kind: 'struct', + fields: [ + { + name: 'bump', + type: 'u8' + }, + { + name: 'merkleRoot', + type: { + array: ['u8', 20] + } + }, + { + name: 'dispenserGuard', + type: 'publicKey' + }, + { + name: 'mint', + type: 'publicKey' + }, + { + name: 'treasury', + type: 'publicKey' + }, + { + name: 'addressLookupTable', + type: 'publicKey' + }, + { + name: 'funder', + type: 'publicKey' + }, + { + name: 'maxTransfer', + type: 'u64' + } + ] + } + }, + { + name: 'Receipt', + type: { + kind: 'struct', + fields: [] + } + } + ], + types: [ + { + name: 'CosmosMessage', + docs: [ + '* An ADR036 message used in Cosmos. ADR036 is a standard for signing arbitrary data.\n* Only the message payload is stored in this struct.\n* The message signed for Cosmos is a JSON serialized CosmosStdSignDoc containing the payload and ADR036 compliant parameters.\n* The message also contains the bech32 address of the signer. We check that the signer corresponds to the public key.' + ], + type: { + kind: 'struct', + fields: [ + { + name: 'payload', + type: 'bytes' + }, + { + name: 'signer', + type: 'string' + } + ] + } + }, + { + name: 'DiscordMessage', + docs: [ + "* This message (borsh-serialized) needs to be signed by the dispenser guard after\n * verifying the claimant's pubkey controls the discord account.\n * The dispenser guard key should not be used for anything else." + ], + type: { + kind: 'struct', + fields: [ + { + name: 'username', + type: 'string' + }, + { + name: 'claimant', + type: 'publicKey' + } + ] + } + }, + { + name: 'Ed25519InstructionHeader', + type: { + kind: 'struct', + fields: [ + { + name: 'numSignatures', + type: 'u8' + }, + { + name: 'padding', + type: 'u8' + }, + { + name: 'signatureOffset', + type: 'u16' + }, + { + name: 'signatureInstructionIndex', + type: 'u16' + }, + { + name: 'publicKeyOffset', + type: 'u16' + }, + { + name: 'publicKeyInstructionIndex', + type: 'u16' + }, + { + name: 'messageDataOffset', + type: 'u16' + }, + { + name: 'messageDataSize', + type: 'u16' + }, + { + name: 'messageInstructionIndex', + type: 'u16' + } + ] + } + }, + { + name: 'Secp256k1InstructionHeader', + type: { + kind: 'struct', + fields: [ + { + name: 'numSignatures', + type: 'u8' + }, + { + name: 'signatureOffset', + type: 'u16' + }, + { + name: 'signatureInstructionIndex', + type: 'u8' + }, + { + name: 'ethAddressOffset', + type: 'u16' + }, + { + name: 'ethAddressInstructionIndex', + type: 'u8' + }, + { + name: 'messageDataOffset', + type: 'u16' + }, + { + name: 'messageDataSize', + type: 'u16' + }, + { + name: 'messageInstructionIndex', + type: 'u8' + } + ] + } + }, + { + name: 'ClaimInfo', + type: { + kind: 'struct', + fields: [ + { + name: 'identity', + type: { + defined: 'Identity' + } + }, + { + name: 'amount', + type: 'u64' + } + ] + } + }, + { + name: 'ClaimCertificate', + type: { + kind: 'struct', + fields: [ + { + name: 'amount', + type: 'u64' + }, + { + name: 'proofOfIdentity', + type: { + defined: 'IdentityCertificate' + } + }, + { + name: 'proofOfInclusion', + type: { + vec: { + array: ['u8', 20] + } + } + } + ] + } + }, + { + name: 'Identity', + docs: [ + "* This is the identity that the claimant will use to claim tokens.\n * A claimant can claim tokens for 1 identity on each ecosystem.\n * Typically for a blockchain it is a public key in the blockchain's address space." + ], + type: { + kind: 'enum', + variants: [ + { + name: 'Discord', + fields: [ + { + name: 'username', + type: 'string' + } + ] + }, + { + name: 'Solana', + fields: [ + { + name: 'pubkey', + type: { + array: ['u8', 32] + } + } + ] + }, + { + name: 'Evm', + fields: [ + { + name: 'pubkey', + type: { + array: ['u8', 20] + } + } + ] + }, + { + name: 'Sui', + fields: [ + { + name: 'address', + type: { + array: ['u8', 32] + } + } + ] + }, + { + name: 'Aptos', + fields: [ + { + name: 'address', + type: { + array: ['u8', 32] + } + } + ] + }, + { + name: 'Cosmwasm', + fields: [ + { + name: 'address', + type: 'string' + } + ] + }, + { + name: 'Injective', + fields: [ + { + name: 'address', + type: 'string' + } + ] + }, + { + name: 'Algorand', + fields: [ + { + name: 'pubkey', + type: { + array: ['u8', 32] + } + } + ] + } + ] + } + }, + { + name: 'IdentityCertificate', + type: { + kind: 'enum', + variants: [ + { + name: 'Discord', + fields: [ + { + name: 'username', + type: 'string' + }, + { + name: 'verification_instruction_index', + type: 'u8' + } + ] + }, + { + name: 'Evm', + fields: [ + { + name: 'pubkey', + type: { + array: ['u8', 20] + } + }, + { + name: 'verification_instruction_index', + type: 'u8' + } + ] + }, + { + name: 'Solana' + }, + { + name: 'Sui', + fields: [ + { + name: 'pubkey', + type: { + array: ['u8', 32] + } + }, + { + name: 'verification_instruction_index', + type: 'u8' + } + ] + }, + { + name: 'Aptos', + fields: [ + { + name: 'pubkey', + type: { + array: ['u8', 32] + } + }, + { + name: 'verification_instruction_index', + type: 'u8' + } + ] + }, + { + name: 'Cosmwasm', + fields: [ + { + name: 'chain_id', + type: 'string' + }, + { + name: 'signature', + type: { + array: ['u8', 64] + } + }, + { + name: 'recovery_id', + type: 'u8' + }, + { + name: 'pubkey', + type: { + array: ['u8', 65] + } + }, + { + name: 'message', + type: 'bytes' + } + ] + }, + { + name: 'Injective', + fields: [ + { + name: 'pubkey', + type: { + array: ['u8', 20] + } + }, + { + name: 'verification_instruction_index', + type: 'u8' + } + ] + }, + { + name: 'Algorand', + fields: [ + { + name: 'pubkey', + type: { + array: ['u8', 32] + } + }, + { + name: 'verification_instruction_index', + type: 'u8' + } + ] + } + ] + } + } + ], + events: [ + { + name: 'ClaimEvent', + fields: [ + { + name: 'remainingBalance', + type: 'u64', + index: false + }, + { + name: 'claimant', + type: 'publicKey', + index: false + }, + { + name: 'claimInfo', + type: { + defined: 'ClaimInfo' + }, + index: false + } + ] + } + ], + errors: [ + { + code: 6000, + name: 'AlreadyClaimed' + }, + { + code: 6001, + name: 'InvalidInclusionProof' + }, + { + code: 6002, + name: 'WrongPda' + }, + { + code: 6003, + name: 'SignatureVerificationWrongProgram' + }, + { + code: 6004, + name: 'SignatureVerificationWrongAccounts' + }, + { + code: 6005, + name: 'SignatureVerificationWrongHeader' + }, + { + code: 6006, + name: 'SignatureVerificationWrongPayload' + }, + { + code: 6007, + name: 'SignatureVerificationWrongPayloadMetadata' + }, + { + code: 6008, + name: 'SignatureVerificationWrongSigner' + }, + { + code: 6009, + name: 'UnauthorizedCosmosChainId' + }, + { + code: 6010, + name: 'TransferExceedsMax' + } + ] +} + +export const coder = new BorshCoder(IDL) diff --git a/backend/src/types.ts b/backend/src/types.ts index 4d4201da..202726be 100644 --- a/backend/src/types.ts +++ b/backend/src/types.ts @@ -1,3 +1,6 @@ +import { IdlTypes } from '@coral-xyz/anchor' +import { TokenDispenser } from './token-dispenser' + export type SignedMessage = { publicKey: Uint8Array signature: Uint8Array @@ -5,3 +8,10 @@ export type SignedMessage = { recoveryId: number | undefined fullMessage: Uint8Array } + +export type ClaimCertificate = IdlTypes['ClaimCertificate'] + +export type ClaimSignature = { + sig: string + instruction: ClaimCertificate | null +} diff --git a/backend/src/utils/discord.ts b/backend/src/utils/discord.ts index 72fa88bd..d8e1df3e 100644 --- a/backend/src/utils/discord.ts +++ b/backend/src/utils/discord.ts @@ -1,8 +1,7 @@ import { Keypair, PublicKey } from '@solana/web3.js' import { SignedMessage } from '../types' import nacl from 'tweetnacl' -import IDL from '../token-dispenser.json' -import * as anchor from '@coral-xyz/anchor' +import { coder } from '../token-dispenser' import config from '../config' export async function getDiscordUser( @@ -28,10 +27,6 @@ export async function getDiscordUser( } } -// TODO: Update IDL with wormhole token dispenser program IDL -// eslint-disable-next-line @typescript-eslint/no-explicit-any -const coder = new anchor.BorshCoder(IDL as any) - function hardDriveSignDigest( fullMessage: Uint8Array, keypair: Keypair diff --git a/backend/src/utils/fund-transactions.ts b/backend/src/utils/fund-transactions.ts index 38254ad6..fee2c986 100644 --- a/backend/src/utils/fund-transactions.ts +++ b/backend/src/utils/fund-transactions.ts @@ -7,8 +7,10 @@ import { TransactionInstruction, VersionedTransaction } from '@solana/web3.js' +import { coder } from '../token-dispenser' import config from '../config' +import { ClaimCertificate } from '../types' const SET_COMPUTE_UNIT_LIMIT_DISCRIMINANT = 2 const SET_COMPUTE_UNIT_PRICE_DISCRIMINANT = 3 @@ -208,3 +210,36 @@ export async function checkTransactions( return false } } + +export function extractCallData( + versionedTx: VersionedTransaction, + programId?: string +): ClaimCertificate | null { + const tokenDispenserPid = programId || config.tokenDispenserProgramId() + if (!tokenDispenserPid) { + console.error('Token dispenser program ID not set') + throw new Error('Token dispenser program ID not set') + } + + try { + const instruction = versionedTx.message.compiledInstructions.find( + (ix) => + versionedTx.message.staticAccountKeys[ix.programIdIndex].toBase58() === + tokenDispenserPid + ) + + if (!instruction) { + return null + } + + const decoded = coder.instruction.decode( + Buffer.from(instruction.data), + 'base58' + )?.data as { claimCertificate: ClaimCertificate } + + return decoded?.claimCertificate as ClaimCertificate + } catch (err) { + console.error('Failed to extract call data', err) + return null + } +} diff --git a/backend/src/utils/persistence.ts b/backend/src/utils/persistence.ts new file mode 100644 index 00000000..92aaeb83 --- /dev/null +++ b/backend/src/utils/persistence.ts @@ -0,0 +1,128 @@ +import { InfluxDB, Point, WriteApi } from '@influxdata/influxdb-client' +import base32 from 'hi-base32' +import { rawSecp256k1PubkeyToRawAddress } from '@cosmjs/amino' +import { Secp256k1 } from '@cosmjs/crypto' +import { toBech32 } from '@cosmjs/encoding' +import config from '../config' +import { ClaimSignature } from '../types' +import { PublicKey } from '@solana/web3.js' +import { getInfluxToken } from './secrets' + +const EVM_WALLET_ADDRESS_PREFIX = '0x' +const INJECTIVE_ADDRESS_PREFIX = 'inj' + +let influxWriter: WriteApi + +export async function saveSignedTransactions( + claimSignatures: ClaimSignature[] +) { + try { + if (!influxWriter) { + influxWriter = await initInfluxWriter() + } + const points = claimSignatures.map((claimSignature) => { + const { ecosystem, subEcosystem, identity } = mapIdentity(claimSignature) + return new Point('ad_signatures') + .tag('type', 'transaction_signed') + .tag('ecosystem', ecosystem) + .tag('subecosystem', subEcosystem) + .stringField('sig', claimSignature.sig) + .stringField('identity', identity) + .floatField('amount', claimSignature.instruction?.amount?.toNumber()) + }) + influxWriter.writePoints(points) + if (config.influx.isFlushEnabled()) { + await influxWriter.flush() + } + } catch (err) { + console.error('Error saving signed transactions', err) + } +} + +function mapIdentity(claimSignature: ClaimSignature) { + const ecosystem: string = Object.keys( + claimSignature.instruction?.proofOfIdentity ?? { unknown: 'ecosystem' } + )[0] + let identity: string | undefined + let subEcosystem = ecosystem + + switch (ecosystem) { + case 'discord': { + identity = claimSignature.instruction?.proofOfIdentity?.discord?.username + break + } + case 'solana': { + identity = new PublicKey( + claimSignature.instruction?.proofOfIdentity?.solana?.pubkey ?? [] + ).toBase58() + break + } + case 'evm': { + identity = + EVM_WALLET_ADDRESS_PREFIX + + Buffer.from( + claimSignature.instruction?.proofOfIdentity?.evm?.pubkey ?? [] + ).toString('hex') + break + } + case 'cosmwasm': { + const pubkey = claimSignature.instruction?.proofOfIdentity?.cosmwasm + ?.pubkey as unknown as Uint8Array + const compressed = Secp256k1.compressPubkey(pubkey) + + const chainId = + claimSignature.instruction?.proofOfIdentity?.cosmwasm?.chainId ?? 'osmo' + identity = toBech32(chainId, rawSecp256k1PubkeyToRawAddress(compressed)) + + subEcosystem = chainId + break + } + case 'injective': { + identity = + INJECTIVE_ADDRESS_PREFIX + + Buffer.from( + claimSignature.instruction?.proofOfIdentity?.injective?.pubkey ?? [] + ).toString('hex') + break + } + case 'aptos': { + identity = + '0x' + + Buffer.from( + claimSignature.instruction?.proofOfIdentity?.aptos?.pubkey ?? [] + ).toString('hex') + break + } + case 'sui': { + identity = + '0x' + + Buffer.from( + claimSignature.instruction?.proofOfIdentity?.sui?.pubkey ?? [] + ).toString('hex') + break + } + case 'algorand': { + identity = base32.encode( + claimSignature.instruction?.proofOfIdentity?.algorand?.pubkey ?? [] + ) + break + } + default: { + identity = 'unknown' + } + } + + return { ecosystem, subEcosystem, identity } +} + +async function initInfluxWriter() { + const token = await getInfluxToken() + return new InfluxDB({ + url: config.influx.url(), + token + }).getWriteApi(config.influx.org(), config.influx.bucket(), 'ms') +} + +process.on('SIGTERM', async () => { + await influxWriter.close() +}) diff --git a/backend/src/utils/secrets.ts b/backend/src/utils/secrets.ts index c384ea3f..9939649c 100644 --- a/backend/src/utils/secrets.ts +++ b/backend/src/utils/secrets.ts @@ -9,26 +9,40 @@ const client = new SecretsManagerClient({ region: config.aws.region }) export async function getDispenserKey() { let key: string - if (config.keys.dispenserGuard.key) { + if (config.secrets.dispenserGuard.key) { console.log('Using dispenser guard key from config') - key = config.keys.dispenserGuard.key + key = config.secrets.dispenserGuard.key + } else { + key = await getSecretKey(config.secrets.dispenserGuard.secretName, 'key') } - key = await getSecretKey(config.keys.dispenserGuard.secretName, 'key') return { key: JSON.parse(key) } } export async function getFundingKey(): Promise<{ key: Uint8Array }> { let key: string - if (config.keys.funding.key) { + if (config.secrets.funding.key()) { console.log('Using funding key from config') - key = config.keys.funding.key + key = config.secrets.funding.key()! + } else { + key = await getSecretKey(config.secrets.funding.secretName, 'key') } - key = await getSecretKey(config.keys.funding.secretName, 'key') return { key: JSON.parse(key) } } +export async function getInfluxToken(): Promise { + let key: string + if (config.secrets.influx.key()) { + console.log('Using influx token from config') + key = config.secrets.influx.key()! + } else { + key = await getSecretKey(config.secrets.influx.secretName, 'key') + } + + return key +} + export async function getSecretKey(secretName: string, keyName: string) { const secret = await getSecret(secretName) return secret[keyName] diff --git a/backend/test/handlers/fund-transactions.test.ts b/backend/test/handlers/fund-transactions.test.ts index e2c0e53a..0784df04 100644 --- a/backend/test/handlers/fund-transactions.test.ts +++ b/backend/test/handlers/fund-transactions.test.ts @@ -14,23 +14,54 @@ import { TransactionMessage, VersionedTransaction } from '@solana/web3.js' -import { AnchorProvider, Program } from '@coral-xyz/anchor' +import { extractCallData } from '../../src/utils/fund-transactions' +import { AnchorProvider, IdlTypes, Program, BN } from '@coral-xyz/anchor' import NodeWallet from '@coral-xyz/anchor/dist/cjs/nodewallet' -import IDL from '../../src/token-dispenser.json' +import { IDL, TokenDispenser } from '../../src/token-dispenser' import { fundTransactions } from '../../src/handlers/fund-transactions' +import { GenericContainer, StartedTestContainer } from 'testcontainers' +import { InfluxDB } from '@influxdata/influxdb-client' const RANDOM_BLOCKHASH = 'HXq5QPm883r7834LWwDpcmEM8G8uQ9Hqm1xakCHGxprV' -const PROGRAM_ID = new Keypair().publicKey +const INFLUX_TOKEN = + 'jsNTEHNBohEjgKqWj1fR8fJjYlBvcYaRTY68-iQ5Y55X_Qr3VKGSvqJz78g4jV8mPiUTQLPYq2tLs_Dy8M--nw==' +const PROGRAM_ID = new PublicKey('Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS') const FUNDER_KEY = new Keypair() const server = setupServer() +const influx = new GenericContainer('influxdb') + let input: VersionedTransaction[] let response: APIGatewayProxyResult describe('fundTransactions integration test', () => { - beforeAll(() => { - process.env.AWS_ACCESS_KEY_ID = 'key' - process.env.AWS_SECRET_ACCESS_KEY = 'secret' + let startedInflux: StartedTestContainer + + beforeAll(async () => { + startedInflux = await influx + .withExposedPorts(8086) + .withEnvironment({ + DOCKER_INFLUXDB_INIT_MODE: 'setup', + DOCKER_INFLUXDB_INIT_USERNAME: 'admin', + DOCKER_INFLUXDB_INIT_PASSWORD: 'password', + DOCKER_INFLUXDB_INIT_ADMIN_TOKEN: INFLUX_TOKEN, + DOCKER_INFLUXDB_INIT_ORG: 'xl', + DOCKER_INFLUXDB_INIT_BUCKET: 'ad' + }) + .start() + process.env.INFLUXDB_ORG = 'xl' + process.env.INFLUXDB_BUCKET = 'ad' + process.env.INFLUXDB_TOKEN = INFLUX_TOKEN + process.env.INFLUXDB_URL = `http://${startedInflux.getHost()}:${startedInflux.getMappedPort( + 8086 + )}` + process.env.INFLUXDB_FLUSH_ENABLED = 'true' + + process.env.FUNDING_WALLET_KEY = `[${FUNDER_KEY.secretKey}]` process.env.TOKEN_DISPENSER_PROGRAM_ID = PROGRAM_ID.toString() + }, 20_000) + + afterAll(async () => { + await startedInflux.stop() }) afterEach(() => { @@ -39,18 +70,7 @@ describe('fundTransactions integration test', () => { test('should pass if all required instructions included', async () => { givenDownstreamServicesWork() - - const tokenDispenserInstruction = - await createTokenDispenserProgramInstruction() - - const instructions = [ - tokenDispenserInstruction, - createComputeUnitLimitInstruction(200), - createComputeUnitPriceInstruction(BigInt(5000)), - createSecp256k1ProgramInstruction() - ] - - input = [createTestTransactionFromInstructions(instructions)] + await givenCorrectTransaction() await whenFundTransactionsCalled() @@ -220,6 +240,29 @@ describe('fundTransactions integration test', () => { expect(response.statusCode).toBe(403) }) + + test('should extract claim info', async () => { + const versionedTx = createTestTransactionFromInstructions([ + await createTokenDispenserProgramInstruction() + ]) + + const callData = extractCallData(versionedTx, PROGRAM_ID.toBase58()) + + expect(callData).not.toBeNull() + expect(callData?.amount.toNumber()).toBe(3000000) + expect(callData?.proofOfInclusion).toBeDefined() + expect(callData?.proofOfIdentity.discord?.username).toBe('username') + }) + + test('should persist signed claims', async () => { + givenDownstreamServicesWork() + await givenCorrectTransaction() + + await whenFundTransactionsCalled() + + thenResponseIsSuccessful() + await thenDataIsAvailable() + }) }) /** @@ -233,7 +276,21 @@ const givenDownstreamServicesWork = () => { }) }) ) - server.listen() + server.listen({ onUnhandledRequest: 'bypass' }) +} + +const givenCorrectTransaction = async () => { + const tokenDispenserInstruction = + await createTokenDispenserProgramInstruction() + + const instructions = [ + tokenDispenserInstruction, + createComputeUnitLimitInstruction(200), + createComputeUnitPriceInstruction(BigInt(5000)), + createSecp256k1ProgramInstruction() + ] + + input = [createTestTransactionFromInstructions(instructions)] } const whenFundTransactionsCalled = async () => { @@ -250,6 +307,26 @@ const thenResponseIsSuccessful = () => { expect(tx.message.recentBlockhash).toBe(input[0].message.recentBlockhash) } +const thenDataIsAvailable = async () => { + let found = 0 + const reader = new InfluxDB({ + url: process.env.INFLUXDB_URL!, + token: process.env.INFLUXDB_TOKEN! + }).getQueryApi(process.env.INFLUXDB_ORG!) + for await (const { values, tableMeta } of reader.iterateRows( + 'from(bucket: "ad") |> range(start:0) |> pivot(rowKey:["_time"], columnKey: ["_field"], valueColumn: "_value")' + )) { + const row = tableMeta.toObject(values) + expect(row).toHaveProperty('amount', 3000000) + expect(row).toHaveProperty('type', 'transaction_signed') + expect(row).toHaveProperty('ecosystem', 'discord') + expect(row).toHaveProperty('subecosystem', 'discord') + expect(row).toHaveProperty('sig', expect.any(String)) + found++ + } + expect(found).toBeGreaterThan(1) +} + const createTestTransactionFromInstructions = ( instructions: TransactionInstruction[] ) => { @@ -276,7 +353,7 @@ const createTestLegacyTransactionFromInstructions = ( const createTokenDispenserProgramInstruction = async () => { const tokenDispenser = new Program( - IDL as any, + IDL, PROGRAM_ID, new AnchorProvider( new Connection('http://localhost:8899'), @@ -285,8 +362,16 @@ const createTokenDispenserProgramInstruction = async () => { ) ) + const claimCert: IdlTypes['ClaimCertificate'] = { + amount: new BN(3000000), + proofOfIdentity: { + discord: { username: 'username', verificationInstructionIndex: 0 } + }, + proofOfInclusion: [] + } + const tokenDispenserInstruction = await tokenDispenser.methods - .claim([]) + .claim(claimCert) .accounts({ funder: FUNDER_KEY.publicKey, claimant: PublicKey.unique(), diff --git a/backend/yarn.lock b/backend/yarn.lock index b00f14d5..5382da0e 100644 --- a/backend/yarn.lock +++ b/backend/yarn.lock @@ -763,6 +763,11 @@ "@babel/helper-validator-identifier" "^7.22.20" to-fast-properties "^2.0.0" +"@balena/dockerignore@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@balena/dockerignore/-/dockerignore-1.0.2.tgz#9ffe4726915251e8eb69f44ef3547e0da2c03e0d" + integrity sha512-wMue2Sy4GAVTk6Ic4tJVcnfdau+gx2EnG7S+uAEe+TWJFqE4YoWN4/H8MSLj4eYJKxGg26lZwboEniNiNwZQ6Q== + "@bcoe/v8-coverage@^0.2.3": version "0.2.3" resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" @@ -810,6 +815,50 @@ bn.js "^5.1.2" buffer-layout "^1.2.0" +"@cosmjs/amino@^0.32.3": + version "0.32.3" + resolved "https://registry.yarnpkg.com/@cosmjs/amino/-/amino-0.32.3.tgz#b81d4a2b8d61568431a1afcd871e1344a19d97ff" + integrity sha512-G4zXl+dJbqrz1sSJ56H/25l5NJEk/pAPIr8piAHgbXYw88OdAOlpA26PQvk2IbSN/rRgVbvlLTNgX2tzz1dyUA== + dependencies: + "@cosmjs/crypto" "^0.32.3" + "@cosmjs/encoding" "^0.32.3" + "@cosmjs/math" "^0.32.3" + "@cosmjs/utils" "^0.32.3" + +"@cosmjs/crypto@^0.32.3": + version "0.32.3" + resolved "https://registry.yarnpkg.com/@cosmjs/crypto/-/crypto-0.32.3.tgz#787f8e659709678722068ee1ddf379f65051a25e" + integrity sha512-niQOWJHUtlJm2GG4F00yGT7sGPKxfUwz+2qQ30uO/E3p58gOusTcH2qjiJNVxb8vScYJhFYFqpm/OA/mVqoUGQ== + dependencies: + "@cosmjs/encoding" "^0.32.3" + "@cosmjs/math" "^0.32.3" + "@cosmjs/utils" "^0.32.3" + "@noble/hashes" "^1" + bn.js "^5.2.0" + elliptic "^6.5.4" + libsodium-wrappers-sumo "^0.7.11" + +"@cosmjs/encoding@^0.32.3": + version "0.32.3" + resolved "https://registry.yarnpkg.com/@cosmjs/encoding/-/encoding-0.32.3.tgz#e245ff511fe4a0df7ba427b5187aab69e3468e5b" + integrity sha512-p4KF7hhv8jBQX3MkB3Defuhz/W0l3PwWVYU2vkVuBJ13bJcXyhU9nJjiMkaIv+XP+W2QgRceqNNgFUC5chNR7w== + dependencies: + base64-js "^1.3.0" + bech32 "^1.1.4" + readonly-date "^1.0.0" + +"@cosmjs/math@^0.32.3": + version "0.32.3" + resolved "https://registry.yarnpkg.com/@cosmjs/math/-/math-0.32.3.tgz#16e4256f4da507b9352327da12ae64056a2ba6c9" + integrity sha512-amumUtZs8hCCnV+lSBaJIiZkGabQm22QGg/IotYrhcmoOEOjt82n7hMNlNXRs7V6WLMidGrGYcswB5zcmp0Meg== + dependencies: + bn.js "^5.2.0" + +"@cosmjs/utils@^0.32.3": + version "0.32.3" + resolved "https://registry.yarnpkg.com/@cosmjs/utils/-/utils-0.32.3.tgz#5dcaee6dd7cc846cdc073e9a7a7f63242f5f7e31" + integrity sha512-WCZK4yksj2hBDz4w7xFZQTRZQ/RJhBX26uFHmmQFIcNUUVAihrLO+RerqJgk0dZqC42wstM9pEUQGtPmLcIYvg== + "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": version "4.4.0" resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" @@ -861,6 +910,11 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz#d9fae00a2d5cb40f92cfe64b47ad749fbc38f917" integrity sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw== +"@influxdata/influxdb-client@^1.33.2": + version "1.33.2" + resolved "https://registry.yarnpkg.com/@influxdata/influxdb-client/-/influxdb-client-1.33.2.tgz#c68cfcf592e4e042361003143fbab99461410172" + integrity sha512-RT5SxH+grHAazo/YK3UTuWK/frPWRM0N7vkrCUyqVprDgQzlLP+bSK4ak2Jv3QVF/pazTnsxWjvtKZdwskV5Xw== + "@inquirer/confirm@^3.0.0": version "3.1.0" resolved "https://registry.yarnpkg.com/@inquirer/confirm/-/confirm-3.1.0.tgz#526cb71ceab28ba827ea287aa81c969e437017b6" @@ -1179,7 +1233,7 @@ dependencies: "@noble/hashes" "1.4.0" -"@noble/hashes@1.4.0", "@noble/hashes@^1.3.1", "@noble/hashes@^1.3.3": +"@noble/hashes@1.4.0", "@noble/hashes@^1", "@noble/hashes@^1.3.1", "@noble/hashes@^1.3.3": version "1.4.0" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.4.0.tgz#45814aa329f30e4fe0ba49426f49dfccdd066426" integrity sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg== @@ -1863,6 +1917,22 @@ resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.6.0.tgz#eac397f28bf1d6ae0ae081363eca2f425bedf0d5" integrity sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA== +"@types/docker-modem@*": + version "3.0.6" + resolved "https://registry.yarnpkg.com/@types/docker-modem/-/docker-modem-3.0.6.tgz#1f9262fcf85425b158ca725699a03eb23cddbf87" + integrity sha512-yKpAGEuKRSS8wwx0joknWxsmLha78wNMe9R2S3UNsVOkZded8UqOrV8KoeDXoXsjndxwyF3eIhyClGbO1SEhEg== + dependencies: + "@types/node" "*" + "@types/ssh2" "*" + +"@types/dockerode@^3.3.24": + version "3.3.26" + resolved "https://registry.yarnpkg.com/@types/dockerode/-/dockerode-3.3.26.tgz#e7f5f06e985ee045c9b9643fd9c34684deb80cd1" + integrity sha512-/K+I9bGhRO2SvyIHisGeOsy/ypxnWLz8+Rde9S2tNNEKa3r91e0XMYIEq2D+kb7srm7xrmpAR0CDKfXoZOr4OA== + dependencies: + "@types/docker-modem" "*" + "@types/node" "*" + "@types/express-serve-static-core@^4.17.33": version "4.17.43" resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.43.tgz#10d8444be560cb789c4735aea5eac6e5af45df54" @@ -1968,6 +2038,13 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.55.tgz#c329cbd434c42164f846b909bd6f85b5537f6240" integrity sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ== +"@types/node@^18.11.18": + version "18.19.26" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.19.26.tgz#18991279d0a0e53675285e8cf4a0823766349729" + integrity sha512-+wiMJsIwLOYCvUqSdKTrfkS8mpTp+MPINe6+Np4TAGFWWRWiBQ5kSq9nZGCSPkzx9mvT+uEukzpX4MOSCydcvw== + dependencies: + undici-types "~5.26.4" + "@types/node@^20.11.26": version "20.11.30" resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.30.tgz#9c33467fc23167a347e73834f788f4b9f399d66f" @@ -2014,6 +2091,28 @@ "@types/mime" "*" "@types/node" "*" +"@types/ssh2-streams@*": + version "0.1.12" + resolved "https://registry.yarnpkg.com/@types/ssh2-streams/-/ssh2-streams-0.1.12.tgz#e68795ba2bf01c76b93f9c9809e1f42f0eaaec5f" + integrity sha512-Sy8tpEmCce4Tq0oSOYdfqaBpA3hDM8SoxoFh5vzFsu2oL+znzGz8oVWW7xb4K920yYMUY+PIG31qZnFMfPWNCg== + dependencies: + "@types/node" "*" + +"@types/ssh2@*": + version "1.15.0" + resolved "https://registry.yarnpkg.com/@types/ssh2/-/ssh2-1.15.0.tgz#ef698a2fe05696d898e0f9398384ad370cd35317" + integrity sha512-YcT8jP5F8NzWeevWvcyrrLB3zcneVjzYY9ZDSMAMboI+2zR1qYWFhwsyOFVzT7Jorn67vqxC0FRiw8YyG9P1ww== + dependencies: + "@types/node" "^18.11.18" + +"@types/ssh2@^0.5.48": + version "0.5.52" + resolved "https://registry.yarnpkg.com/@types/ssh2/-/ssh2-0.5.52.tgz#9dbd8084e2a976e551d5e5e70b978ed8b5965741" + integrity sha512-lbLLlXxdCZOSJMCInKH2+9V/77ET2J6NPQHpFI0kda61Dd1KglJs+fPQBchizmzYSOJBgdTajhPqBO1xxLywvg== + dependencies: + "@types/node" "*" + "@types/ssh2-streams" "*" + "@types/stack-utils@^2.0.0": version "2.0.3" resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.3.tgz#6209321eb2c1712a7e7466422b8cb1fc0d9dd5d8" @@ -2226,6 +2325,51 @@ arch@^2.1.0: resolved "https://registry.yarnpkg.com/arch/-/arch-2.2.0.tgz#1bc47818f305764f23ab3306b0bfc086c5a29d11" integrity sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ== +archiver-utils@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/archiver-utils/-/archiver-utils-2.1.0.tgz#e8a460e94b693c3e3da182a098ca6285ba9249e2" + integrity sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw== + dependencies: + glob "^7.1.4" + graceful-fs "^4.2.0" + lazystream "^1.0.0" + lodash.defaults "^4.2.0" + lodash.difference "^4.5.0" + lodash.flatten "^4.4.0" + lodash.isplainobject "^4.0.6" + lodash.union "^4.6.0" + normalize-path "^3.0.0" + readable-stream "^2.0.0" + +archiver-utils@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/archiver-utils/-/archiver-utils-3.0.4.tgz#a0d201f1cf8fce7af3b5a05aea0a337329e96ec7" + integrity sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw== + dependencies: + glob "^7.2.3" + graceful-fs "^4.2.0" + lazystream "^1.0.0" + lodash.defaults "^4.2.0" + lodash.difference "^4.5.0" + lodash.flatten "^4.4.0" + lodash.isplainobject "^4.0.6" + lodash.union "^4.6.0" + normalize-path "^3.0.0" + readable-stream "^3.6.0" + +archiver@^5.3.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/archiver/-/archiver-5.3.2.tgz#99991d5957e53bd0303a392979276ac4ddccf3b0" + integrity sha512-+25nxyyznAXF7Nef3y0EbBeqmGZgeN/BxHX29Rs39djAfaFalmQ89SE6CWyDCHzGL0yt/ycBtNOmGTW0FyGWNw== + dependencies: + archiver-utils "^2.1.0" + async "^3.2.4" + buffer-crc32 "^0.2.1" + readable-stream "^3.6.0" + readdir-glob "^1.1.2" + tar-stream "^2.2.0" + zip-stream "^4.1.0" + argparse@^1.0.7: version "1.0.10" resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" @@ -2248,6 +2392,28 @@ array-union@^2.1.0: resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== +asn1@^0.2.6: + version "0.2.6" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.6.tgz#0d3a7bb6e64e02a90c0303b31f292868ea09a08d" + integrity sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ== + dependencies: + safer-buffer "~2.1.0" + +async-lock@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/async-lock/-/async-lock-1.4.1.tgz#56b8718915a9b68b10fce2f2a9a3dddf765ef53f" + integrity sha512-Az2ZTpuytrtqENulXwO3GGv1Bztugx6TT37NIo7imr/Qo0gsYiGtSdBa2B6fsXhTpVZDNfu1Qn3pk531e3q+nQ== + +async@^3.2.4: + version "3.2.5" + resolved "https://registry.yarnpkg.com/async/-/async-3.2.5.tgz#ebd52a8fdaf7a2289a24df399f8d8485c8a46b66" + integrity sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg== + +b4a@^1.6.4: + version "1.6.6" + resolved "https://registry.yarnpkg.com/b4a/-/b4a-1.6.6.tgz#a4cc349a3851987c3c4ac2d7785c18744f6da9ba" + integrity sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg== + babel-jest@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.7.0.tgz#f4369919225b684c56085998ac63dbd05be020d5" @@ -2313,6 +2479,33 @@ balanced-match@^1.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== +bare-events@^2.0.0, bare-events@^2.2.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/bare-events/-/bare-events-2.2.2.tgz#a98a41841f98b2efe7ecc5c5468814469b018078" + integrity sha512-h7z00dWdG0PYOQEvChhOSWvOfkIKsdZGkWr083FgN/HyoQuebSew/cgirYqh9SCuy/hRvxc5Vy6Fw8xAmYHLkQ== + +bare-fs@^2.1.1: + version "2.2.2" + resolved "https://registry.yarnpkg.com/bare-fs/-/bare-fs-2.2.2.tgz#286bf54cc6f15f613bee6bb26f0c61c79fb14f06" + integrity sha512-X9IqgvyB0/VA5OZJyb5ZstoN62AzD7YxVGog13kkfYWYqJYcK0kcqLZ6TrmH5qr4/8//ejVcX4x/a0UvaogXmA== + dependencies: + bare-events "^2.0.0" + bare-os "^2.0.0" + bare-path "^2.0.0" + streamx "^2.13.0" + +bare-os@^2.0.0, bare-os@^2.1.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/bare-os/-/bare-os-2.2.1.tgz#c94a258c7a408ca6766399e44675136c0964913d" + integrity sha512-OwPyHgBBMkhC29Hl3O4/YfxW9n7mdTr2+SsO29XBWKKJsbgj3mnorDB80r5TiCQgQstgE5ga1qNYrpes6NvX2w== + +bare-path@^2.0.0, bare-path@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/bare-path/-/bare-path-2.1.0.tgz#830f17fd39842813ca77d211ebbabe238a88cb4c" + integrity sha512-DIIg7ts8bdRKwJRJrUMy/PICEaQZaPGZ26lsSx9MJSwIhSrcdHn7/C8W+XmnG/rKi6BaRcz+JO00CjZteybDtw== + dependencies: + bare-os "^2.1.0" + base-x@^3.0.2: version "3.0.9" resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.9.tgz#6349aaabb58526332de9f60995e548a53fe21320" @@ -2325,11 +2518,23 @@ base-x@^4.0.0: resolved "https://registry.yarnpkg.com/base-x/-/base-x-4.0.0.tgz#d0e3b7753450c73f8ad2389b5c018a4af7b2224a" integrity sha512-FuwxlW4H5kh37X/oW59pwTzzTKRzfrrQwhmyspRM7swOEZcHtDZSCt45U6oKgtuFE+WYPblePMVIPR4RZrh/hw== -base64-js@^1.3.1: +base64-js@^1.3.0, base64-js@^1.3.1: version "1.5.1" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== +bcrypt-pbkdf@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" + integrity sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w== + dependencies: + tweetnacl "^0.14.3" + +bech32@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/bech32/-/bech32-1.1.4.tgz#e38c9f37bf179b8eb16ae3a772b40c356d4832e9" + integrity sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ== + bigint-buffer@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/bigint-buffer/-/bigint-buffer-1.1.5.tgz#d038f31c8e4534c1f8d0015209bf34b4fa6dd442" @@ -2369,6 +2574,20 @@ bindings@^1.3.0: dependencies: file-uri-to-path "1.0.0" +bl@^4.0.3: + version "4.1.0" + resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" + integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== + dependencies: + buffer "^5.5.0" + inherits "^2.0.4" + readable-stream "^3.4.0" + +bn.js@^4.11.9: + version "4.12.0" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" + integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== + bn.js@^5.1.2, bn.js@^5.2.0, bn.js@^5.2.1: version "5.2.1" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" @@ -2428,6 +2647,11 @@ braces@^3.0.2: dependencies: fill-range "^7.0.1" +brorand@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + integrity sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w== + browserslist@^4.22.2: version "4.23.0" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.23.0.tgz#8f3acc2bbe73af7213399430890f86c63a5674ab" @@ -2459,6 +2683,11 @@ bser@2.1.1: dependencies: node-int64 "^0.4.0" +buffer-crc32@^0.2.1, buffer-crc32@^0.2.13: + version "0.2.13" + resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" + integrity sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ== + buffer-from@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" @@ -2477,6 +2706,14 @@ buffer@6.0.3, buffer@~6.0.3: base64-js "^1.3.1" ieee754 "^1.2.1" +buffer@^5.5.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" + integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.1.13" + bufferutil@^4.0.1: version "4.0.8" resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-4.0.8.tgz#1de6a71092d65d7766c4d8a522b261a6e787e8ea" @@ -2484,6 +2721,16 @@ bufferutil@^4.0.1: dependencies: node-gyp-build "^4.3.0" +buildcheck@~0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/buildcheck/-/buildcheck-0.0.6.tgz#89aa6e417cfd1e2196e3f8fe915eb709d2fe4238" + integrity sha512-8f9ZJCUXyT1M35Jx7MkBgmBMo3oHTTBIPLiY9xyL0pl3T5RwcPEY8cUHr5LBNfu/fk6c2T4DJZuVM/8ZZT2D2A== + +byline@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/byline/-/byline-5.0.0.tgz#741c5216468eadc457b03410118ad77de8c1ddb1" + integrity sha512-s6webAy+R4SR8XVuJWt2V2rGvhnrhxN+9S15GNuTK3wKPOXFF6RNc+8ug2XhH+2s4f+uudG4kUVYmYOQWL2g0Q== + bytes@3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" @@ -2560,6 +2807,11 @@ char-regex@^1.0.2: resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== +chownr@^1.1.1: + version "1.1.4" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" + integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== + ci-info@^3.2.0: version "3.9.0" resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" @@ -2645,6 +2897,16 @@ commander@^8.3.0: resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== +compress-commons@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/compress-commons/-/compress-commons-4.1.2.tgz#6542e59cb63e1f46a8b21b0e06f9a32e4c8b06df" + integrity sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg== + dependencies: + buffer-crc32 "^0.2.13" + crc32-stream "^4.0.2" + normalize-path "^3.0.0" + readable-stream "^3.6.0" + concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" @@ -2682,6 +2944,32 @@ cookie@^0.5.0: resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== +core-util-is@~1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" + integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== + +cpu-features@~0.0.9: + version "0.0.9" + resolved "https://registry.yarnpkg.com/cpu-features/-/cpu-features-0.0.9.tgz#5226b92f0f1c63122b0a3eb84cb8335a4de499fc" + integrity sha512-AKjgn2rP2yJyfbepsmLfiYcmtNn/2eUvocUyM/09yB0YDiz39HteK/5/T4Onf0pmdYDMgkBoGvRLvEguzyL7wQ== + dependencies: + buildcheck "~0.0.6" + nan "^2.17.0" + +crc-32@^1.2.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.2.tgz#3cad35a934b8bf71f25ca524b6da51fb7eace2ff" + integrity sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ== + +crc32-stream@^4.0.2: + version "4.0.3" + resolved "https://registry.yarnpkg.com/crc32-stream/-/crc32-stream-4.0.3.tgz#85dd677eb78fa7cad1ba17cc506a597d41fc6f33" + integrity sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw== + dependencies: + crc-32 "^1.2.0" + readable-stream "^3.4.0" + create-jest@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/create-jest/-/create-jest-29.7.0.tgz#a355c5b3cb1e1af02ba177fe7afd7feee49a5320" @@ -2807,6 +3095,32 @@ dir-glob@^3.0.1: dependencies: path-type "^4.0.0" +docker-compose@^0.24.6: + version "0.24.7" + resolved "https://registry.yarnpkg.com/docker-compose/-/docker-compose-0.24.7.tgz#66490508d5a08c221402108be8d5236d9567bb94" + integrity sha512-CdHl9n0S4+bl4i6MaxDQHNjqB1FdvuDirrDTzPKmdiMpheQqCjgsny0GZ2VhvN7qHTY0833lRlKWZgrkn1i6cg== + dependencies: + yaml "^2.2.2" + +docker-modem@^3.0.0: + version "3.0.8" + resolved "https://registry.yarnpkg.com/docker-modem/-/docker-modem-3.0.8.tgz#ef62c8bdff6e8a7d12f0160988c295ea8705e77a" + integrity sha512-f0ReSURdM3pcKPNS30mxOHSbaFLcknGmQjwSfmbcdOw1XWKXVhukM3NJHhr7NpY9BIyyWQb0EBo3KQvvuU5egQ== + dependencies: + debug "^4.1.1" + readable-stream "^3.5.0" + split-ca "^1.0.1" + ssh2 "^1.11.0" + +dockerode@^3.3.5: + version "3.3.5" + resolved "https://registry.yarnpkg.com/dockerode/-/dockerode-3.3.5.tgz#7ae3f40f2bec53ae5e9a741ce655fff459745629" + integrity sha512-/0YNa3ZDNeLr/tSckmD69+Gq+qVNhvKfAHNeZJBnp7EOP6RGKV8ORrJHkUn20So5wU+xxT7+1n5u8PjHbfjbSA== + dependencies: + "@balena/dockerignore" "^1.0.2" + docker-modem "^3.0.0" + tar-fs "~2.0.1" + doctrine@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" @@ -2832,6 +3146,19 @@ electron-to-chromium@^1.4.668: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.710.tgz#d0ec4ea8a97df4c5eaeb8c69d45bf81f248b3855" integrity sha512-w+9yAVHoHhysCa+gln7AzbO9CdjFcL/wN/5dd+XW/Msl2d/4+WisEaCF1nty0xbAKaxdaJfgLB2296U7zZB7BA== +elliptic@^6.5.4: + version "6.5.5" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.5.tgz#c715e09f78b6923977610d4c2346d6ce22e6dded" + integrity sha512-7EjbcmUm17NQFu4Pmgmq2olYMj8nwMnpcddByChSUjArp8F5DQWcIcpriwO4ZToLNAJig0yiyjswfyGNje/ixw== + dependencies: + bn.js "^4.11.9" + brorand "^1.1.0" + hash.js "^1.0.0" + hmac-drbg "^1.0.1" + inherits "^2.0.4" + minimalistic-assert "^1.0.1" + minimalistic-crypto-utils "^1.0.1" + emittery@^0.13.1: version "0.13.1" resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.13.1.tgz#c04b8c3457490e0847ae51fced3af52d338e3dad" @@ -2847,7 +3174,7 @@ encodeurl@~1.0.2: resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== -end-of-stream@^1.1.0: +end-of-stream@^1.1.0, end-of-stream@^1.4.1: version "1.4.4" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== @@ -3133,6 +3460,11 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== +fast-fifo@^1.1.0, fast-fifo@^1.2.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/fast-fifo/-/fast-fifo-1.3.2.tgz#286e31de96eb96d38a97899815740ba2a4f3640c" + integrity sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ== + fast-glob@^3.2.5, fast-glob@^3.2.9: version "3.3.2" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" @@ -3289,6 +3621,11 @@ fresh@0.5.2: resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== +fs-constants@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" + integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -3330,6 +3667,11 @@ get-package-type@^0.1.0: resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== +get-port@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/get-port/-/get-port-5.1.1.tgz#0469ed07563479de6efb986baf053dcd7d4e3193" + integrity sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ== + get-stream@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" @@ -3361,7 +3703,7 @@ glob-parent@^6.0.2: dependencies: is-glob "^4.0.3" -glob@^7.1.3, glob@^7.1.4: +glob@^7.1.3, glob@^7.1.4, glob@^7.2.3: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== @@ -3421,7 +3763,7 @@ got@^11.8.5: p-cancelable "^2.0.0" responselike "^2.0.0" -graceful-fs@^4.2.9: +graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.9: version "4.2.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== @@ -3463,6 +3805,14 @@ has-symbols@^1.0.3: resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== +hash.js@^1.0.0, hash.js@^1.0.3: + version "1.1.7" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" + integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.1" + hasown@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" @@ -3475,6 +3825,20 @@ headers-polyfill@^4.0.2: resolved "https://registry.yarnpkg.com/headers-polyfill/-/headers-polyfill-4.0.3.tgz#922a0155de30ecc1f785bcf04be77844ca95ad07" integrity sha512-IScLbePpkvO846sIwOtOTDjutRMWdXdJmXdMvk6gCBHxFO8d+QKOQedyZSxFTTFYRSmlgSTDtXqqq4pcenBXLQ== +hi-base32@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/hi-base32/-/hi-base32-0.5.1.tgz#1279f2ddae2673219ea5870c2121d2a33132857e" + integrity sha512-EmBBpvdYh/4XxsnUybsPag6VikPYnN30td+vQk+GI3qpahVEG9+gTkG0aXVxTjBqQ5T6ijbWIu77O+C5WFWsnA== + +hmac-drbg@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + integrity sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg== + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + html-escaper@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" @@ -3523,7 +3887,7 @@ iconv-lite@0.4.24: dependencies: safer-buffer ">= 2.1.2 < 3" -ieee754@^1.2.1: +ieee754@^1.1.13, ieee754@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== @@ -3562,7 +3926,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4, inherits@^2.0.3: +inherits@2, inherits@2.0.4, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -3636,6 +4000,11 @@ is-stream@^2.0.0: resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== +isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== + isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" @@ -4152,6 +4521,13 @@ kleur@^3.0.3: resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== +lazystream@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.1.tgz#494c831062f1f9408251ec44db1cba29242a2638" + integrity sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw== + dependencies: + readable-stream "^2.0.5" + leven@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" @@ -4165,6 +4541,18 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" +libsodium-sumo@^0.7.13: + version "0.7.13" + resolved "https://registry.yarnpkg.com/libsodium-sumo/-/libsodium-sumo-0.7.13.tgz#533b97d2be44b1277e59c1f9f60805978ac5542d" + integrity sha512-zTGdLu4b9zSNLfovImpBCbdAA4xkpkZbMnSQjP8HShyOutnGjRHmSOKlsylh1okao6QhLiz7nG98EGn+04cZjQ== + +libsodium-wrappers-sumo@^0.7.11: + version "0.7.13" + resolved "https://registry.yarnpkg.com/libsodium-wrappers-sumo/-/libsodium-wrappers-sumo-0.7.13.tgz#a33aea845a0bb56db067548f04feba28c730ab8e" + integrity sha512-lz4YdplzDRh6AhnLGF2Dj2IUj94xRN6Bh8T0HLNwzYGwPehQJX6c7iYVrFUPZ3QqxE0bqC+K0IIqqZJYWumwSQ== + dependencies: + libsodium-sumo "^0.7.13" + lines-and-columns@^1.1.6: version "1.2.4" resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" @@ -4184,11 +4572,36 @@ locate-path@^6.0.0: dependencies: p-locate "^5.0.0" +lodash.defaults@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" + integrity sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ== + +lodash.difference@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.difference/-/lodash.difference-4.5.0.tgz#9ccb4e505d486b91651345772885a2df27fd017c" + integrity sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA== + +lodash.flatten@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" + integrity sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g== + +lodash.isplainobject@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" + integrity sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA== + lodash.merge@^4.6.2: version "4.6.2" resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== +lodash.union@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88" + integrity sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw== + lower-case@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28" @@ -4302,6 +4715,16 @@ mimic-response@^3.1.0: resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9" integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ== +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + +minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== + minimatch@9.0.3, minimatch@^9.0.3: version "9.0.3" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" @@ -4316,6 +4739,23 @@ minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: dependencies: brace-expansion "^1.1.7" +minimatch@^5.1.0: + version "5.1.6" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" + integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== + dependencies: + brace-expansion "^2.0.1" + +mkdirp-classic@^0.5.2: + version "0.5.3" + resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113" + integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A== + +mkdirp@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" @@ -4359,6 +4799,11 @@ mute-stream@^1.0.0: resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-1.0.0.tgz#e31bd9fe62f0aed23520aa4324ea6671531e013e" integrity sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA== +nan@^2.17.0, nan@^2.18.0: + version "2.19.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.19.0.tgz#bb58122ad55a6c5bc973303908d5b16cfdd5a8c0" + integrity sha512-nO1xXxfh/RWNxfd/XPfbIfFk5vgLsAxUR9y5O0cHMJu/AW9U95JLXqthYHjEp+8gQ5p96K9jUp8nbVOxCdRbtw== + natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" @@ -4654,6 +5099,11 @@ pretty-format@^29.0.0, pretty-format@^29.7.0: ansi-styles "^5.0.0" react-is "^18.0.0" +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + prompts@^2.0.1: version "2.4.2" resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" @@ -4662,6 +5112,22 @@ prompts@^2.0.1: kleur "^3.0.3" sisteransi "^1.0.5" +proper-lockfile@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/proper-lockfile/-/proper-lockfile-4.1.2.tgz#c8b9de2af6b2f1601067f98e01ac66baa223141f" + integrity sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA== + dependencies: + graceful-fs "^4.2.4" + retry "^0.12.0" + signal-exit "^3.0.2" + +properties-reader@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/properties-reader/-/properties-reader-2.3.0.tgz#f3ab84224c9535a7a36e011ae489a79a13b472b2" + integrity sha512-z597WicA7nDZxK12kZqHr2TcvwNU1GCfA5UwfDY/HDp3hXPoPlb5rlEx9bwGTiJnc0OqbBTkU975jDToth8Gxw== + dependencies: + mkdirp "^1.0.4" + proxy-addr@~2.0.7: version "2.0.7" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" @@ -4705,6 +5171,11 @@ queue-microtask@^1.2.2: resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== +queue-tick@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/queue-tick/-/queue-tick-1.0.1.tgz#f6f07ac82c1fd60f82e098b417a80e52f1f4c142" + integrity sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag== + quick-lru@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" @@ -4730,7 +5201,20 @@ react-is@^18.0.0: resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== -readable-stream@^3.6.0: +readable-stream@^2.0.0, readable-stream@^2.0.5: + version "2.3.8" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" + integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.5.0, readable-stream@^3.6.0: version "3.6.2" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== @@ -4746,6 +5230,18 @@ readable-web-to-node-stream@^3.0.2: dependencies: readable-stream "^3.6.0" +readdir-glob@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/readdir-glob/-/readdir-glob-1.1.3.tgz#c3d831f51f5e7bfa62fa2ffbe4b508c640f09584" + integrity sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA== + dependencies: + minimatch "^5.1.0" + +readonly-date@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/readonly-date/-/readonly-date-1.0.0.tgz#5af785464d8c7d7c40b9d738cbde8c646f97dcd9" + integrity sha512-tMKIV7hlk0h4mO3JTmmVuIlJVXjKk3Sep9Bf5OH0O+758ruuVkUy2J9SttDLm91IEX/WHlXPSpxMGjPj4beMIQ== + regenerator-runtime@^0.14.0: version "0.14.1" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f" @@ -4799,6 +5295,11 @@ responselike@^2.0.0: dependencies: lowercase-keys "^2.0.0" +retry@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" + integrity sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow== + reusify@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" @@ -4841,7 +5342,12 @@ safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@~5.2.0: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== -"safer-buffer@>= 2.1.2 < 3": +safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +"safer-buffer@>= 2.1.2 < 3", safer-buffer@~2.1.0: version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== @@ -4950,7 +5456,7 @@ side-channel@^1.0.4: get-intrinsic "^1.2.4" object-inspect "^1.13.1" -signal-exit@^3.0.0, signal-exit@^3.0.3, signal-exit@^3.0.7: +signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: version "3.0.7" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== @@ -5018,11 +5524,35 @@ source-map@^0.7.3: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656" integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA== +split-ca@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/split-ca/-/split-ca-1.0.1.tgz#6c83aff3692fa61256e0cd197e05e9de157691a6" + integrity sha512-Q5thBSxp5t8WPTTJQS59LrGqOZqOsrhDGDVm8azCqIBjSBd7nd9o2PM+mDulQQkh8h//4U6hFZnc/mul8t5pWQ== + sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== +ssh-remote-port-forward@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/ssh-remote-port-forward/-/ssh-remote-port-forward-1.0.4.tgz#72b0c5df8ec27ca300c75805cc6b266dee07e298" + integrity sha512-x0LV1eVDwjf1gmG7TTnfqIzf+3VPRz7vrNIjX6oYLbeCrf/PeVY6hkT68Mg+q02qXxQhrLjB0jfgvhevoCRmLQ== + dependencies: + "@types/ssh2" "^0.5.48" + ssh2 "^1.4.0" + +ssh2@^1.11.0, ssh2@^1.4.0: + version "1.15.0" + resolved "https://registry.yarnpkg.com/ssh2/-/ssh2-1.15.0.tgz#2f998455036a7f89e0df5847efb5421748d9871b" + integrity sha512-C0PHgX4h6lBxYx7hcXwu3QWdh4tg6tZZsTfXcdvc5caW/EMxaB4H9dWsl7qk+F7LAW762hp8VbXOX7x4xUYvEw== + dependencies: + asn1 "^0.2.6" + bcrypt-pbkdf "^1.0.2" + optionalDependencies: + cpu-features "~0.0.9" + nan "^2.18.0" + stack-utils@^2.0.3: version "2.0.6" resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f" @@ -5035,6 +5565,16 @@ statuses@2.0.1, statuses@^2.0.1: resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== +streamx@^2.13.0, streamx@^2.15.0: + version "2.16.1" + resolved "https://registry.yarnpkg.com/streamx/-/streamx-2.16.1.tgz#2b311bd34832f08aa6bb4d6a80297c9caef89614" + integrity sha512-m9QYj6WygWyWa3H1YY69amr4nVgy61xfjys7xO7kviL5rfIEc2naf+ewFiOA+aEJD7y0JO3h2GoiUv4TDwEGzQ== + dependencies: + fast-fifo "^1.1.0" + queue-tick "^1.0.1" + optionalDependencies: + bare-events "^2.2.0" + strict-event-emitter@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/strict-event-emitter/-/strict-event-emitter-0.5.1.tgz#1602ece81c51574ca39c6815e09f1a3e8550bd93" @@ -5064,6 +5604,13 @@ string_decoder@^1.1.1: dependencies: safe-buffer "~5.2.0" +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" @@ -5145,6 +5692,47 @@ supports-preserve-symlinks-flag@^1.0.0: resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== +tar-fs@^3.0.5: + version "3.0.5" + resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-3.0.5.tgz#f954d77767e4e6edf973384e1eb95f8f81d64ed9" + integrity sha512-JOgGAmZyMgbqpLwct7ZV8VzkEB6pxXFBVErLtb+XCOqzc6w1xiWKI9GVd6bwk68EX7eJ4DWmfXVmq8K2ziZTGg== + dependencies: + pump "^3.0.0" + tar-stream "^3.1.5" + optionalDependencies: + bare-fs "^2.1.1" + bare-path "^2.1.0" + +tar-fs@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.0.1.tgz#e44086c1c60d31a4f0cf893b1c4e155dabfae9e2" + integrity sha512-6tzWDMeroL87uF/+lin46k+Q+46rAJ0SyPGz7OW7wTgblI273hsBqk2C1j0/xNadNLKDTUL9BukSjB7cwgmlPA== + dependencies: + chownr "^1.1.1" + mkdirp-classic "^0.5.2" + pump "^3.0.0" + tar-stream "^2.0.0" + +tar-stream@^2.0.0, tar-stream@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287" + integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ== + dependencies: + bl "^4.0.3" + end-of-stream "^1.4.1" + fs-constants "^1.0.0" + inherits "^2.0.3" + readable-stream "^3.1.1" + +tar-stream@^3.1.5: + version "3.1.7" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-3.1.7.tgz#24b3fb5eabada19fe7338ed6d26e5f7c482e792b" + integrity sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ== + dependencies: + b4a "^1.6.4" + fast-fifo "^1.2.0" + streamx "^2.15.0" + test-exclude@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" @@ -5154,6 +5742,27 @@ test-exclude@^6.0.0: glob "^7.1.4" minimatch "^3.0.4" +testcontainers@^10.8.0: + version "10.8.0" + resolved "https://registry.yarnpkg.com/testcontainers/-/testcontainers-10.8.0.tgz#3547d678c2d2078e736c45d325a3b26b7f2c93da" + integrity sha512-C8wXze2go5NVQyzYtI8XhTJ+iVvpojuyTiG1AWIRE1C8vojCx9Za3tQ5qEx/43WWgVGYE9UVz2Qo0u9IvLE3Hw== + dependencies: + "@balena/dockerignore" "^1.0.2" + "@types/dockerode" "^3.3.24" + archiver "^5.3.2" + async-lock "^1.4.1" + byline "^5.0.0" + debug "^4.3.4" + docker-compose "^0.24.6" + dockerode "^3.3.5" + get-port "^5.1.1" + node-fetch "^2.7.0" + proper-lockfile "^4.1.2" + properties-reader "^2.3.0" + ssh-remote-port-forward "^1.0.4" + tar-fs "^3.0.5" + tmp "^0.2.1" + text-encoding-utf-8@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz#585b62197b0ae437e3c7b5d0af27ac1021e10d13" @@ -5169,6 +5778,11 @@ text-table@^0.2.0: resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== +tmp@^0.2.1: + version "0.2.3" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.3.tgz#eb783cc22bc1e8bebd0671476d46ea4eb32a79ae" + integrity sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w== + tmpl@1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" @@ -5231,6 +5845,11 @@ tslib@^2.0.3, tslib@^2.3.1, tslib@^2.6.2: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== +tweetnacl@^0.14.3: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + integrity sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA== + tweetnacl@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596" @@ -5308,7 +5927,7 @@ utf-8-validate@^5.0.2: dependencies: node-gyp-build "^4.3.0" -util-deprecate@^1.0.1: +util-deprecate@^1.0.1, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== @@ -5437,6 +6056,11 @@ yallist@^4.0.0: resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== +yaml@^2.2.2: + version "2.4.1" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.4.1.tgz#2e57e0b5e995292c25c75d2658f0664765210eed" + integrity sha512-pIXzoImaqmfOrL7teGUBt/T7ZDnyeGBWyXQBvOVhLkWLN37GXv8NMLK406UY6dS51JfcQHsmcW5cJ441bHg6Lg== + yargs-parser@^21.1.1: version "21.1.1" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" @@ -5459,3 +6083,12 @@ yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + +zip-stream@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-4.1.1.tgz#1337fe974dbaffd2fa9a1ba09662a66932bd7135" + integrity sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ== + dependencies: + archiver-utils "^3.0.4" + compress-commons "^4.1.2" + readable-stream "^3.6.0"