From 5d7da20a5f7c01e278dff050f03a94a4776f4098 Mon Sep 17 00:00:00 2001 From: Martin Picco Date: Fri, 29 Mar 2024 17:10:16 -0300 Subject: [PATCH 01/12] Fix algorand claim info identity serialization (#56) --- frontend/claim_sdk/claim.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/claim_sdk/claim.ts b/frontend/claim_sdk/claim.ts index 7cda6bfd..a8353018 100644 --- a/frontend/claim_sdk/claim.ts +++ b/frontend/claim_sdk/claim.ts @@ -88,7 +88,7 @@ export class ClaimInfo { case 'algorand': { identityStruct = { algorand: { - address: base32decode(this.identity), + pubkey: base32decode(this.identity).subarray(0, 32), }, } break From 613ca388f318553355674bd10c1a709dad233636 Mon Sep 17 00:00:00 2001 From: Valentino Conti <41705567+valentinoConti@users.noreply.github.com> Date: Fri, 29 Mar 2024 19:05:21 -0300 Subject: [PATCH 02/12] Add message for EVM wallet selector (#59) --- frontend/components/wallets/EVM.tsx | 1 + frontend/components/wallets/WalletButton.tsx | 20 ++++++++++++++++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/frontend/components/wallets/EVM.tsx b/frontend/components/wallets/EVM.tsx index 5881ed7e..c00a4e4e 100644 --- a/frontend/components/wallets/EVM.tsx +++ b/frontend/components/wallets/EVM.tsx @@ -106,6 +106,7 @@ export function EVMWalletButton({ onSelect: () => onSelect(connector), icon: getIcon(connector.id as WalletIds), }))} + isEVM={true} walletConnectedButton={(address: string) => ( ReactElement address: string | undefined @@ -67,6 +68,7 @@ export type WalletButtonProps = { // When the wallet is connected export function WalletButton({ connected, + isEVM, isLoading, walletConnectedButton, wallets, @@ -74,7 +76,7 @@ export function WalletButton({ }: WalletButtonProps) { if (isLoading === true) return else if (connected === true) return walletConnectedButton(address!) - return + return } export type Wallet = { @@ -84,8 +86,9 @@ export type Wallet = { } export type WalletModalButtonProps = { wallets: Wallet[] + isEVM?: boolean } -export function WalletModalButton({ wallets }: WalletModalButtonProps) { +export function WalletModalButton({ wallets, isEVM }: WalletModalButtonProps) { const [modal, openModal] = useState(false) return ( @@ -99,7 +102,9 @@ export function WalletModalButton({ wallets }: WalletModalButtonProps) { Connect wallet - {modal && } + {modal && ( + + )} ) } @@ -107,13 +112,20 @@ export function WalletModalButton({ wallets }: WalletModalButtonProps) { export type WalletModalProps = { openModal: Function wallets: Wallet[] + isEVM?: boolean } -export function WalletModal({ openModal, wallets }: WalletModalProps) { +export function WalletModal({ isEVM, openModal, wallets }: WalletModalProps) { return (

Connect Your Wallet

+ {isEVM && ( +
+ If you have multiple EVM wallets active, please disable the wallets + that will not be used for eligibility verification. +
+ )}
{wallets.map((wallet) => { return ( 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 03/12] [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" From 9b3d45cf2fea8bd2223a1564a5a13a406ab1ca0a Mon Sep 17 00:00:00 2001 From: Sebastian Date: Mon, 1 Apr 2024 12:23:33 -0300 Subject: [PATCH 04/12] setup keplr as injective wallet (#55) * setup keplr as injective wallet * update signature method * run prettier --- frontend/claim_sdk/ecosystems/signatures.ts | 17 + .../components/EcosystemConnectButton.tsx | 4 +- frontend/components/wallets/Cosmos.tsx | 2 +- frontend/hooks/useGetEcosystemIdentity.ts | 8 +- frontend/hooks/useSignMessage.tsx | 39 +- frontend/utils/chain-registry.ts | 396 ++++++++++++++++++ 6 files changed, 456 insertions(+), 10 deletions(-) diff --git a/frontend/claim_sdk/ecosystems/signatures.ts b/frontend/claim_sdk/ecosystems/signatures.ts index 8a58d542..c393fb2a 100644 --- a/frontend/claim_sdk/ecosystems/signatures.ts +++ b/frontend/claim_sdk/ecosystems/signatures.ts @@ -39,6 +39,23 @@ export function evmBuildSignedMessage( } } +export function injectiveBuildSignedMessage( + publicKey: Buffer, + fullSignature: Uint8Array, + payload: string +): SignedMessage { + const fullMessage = evmGetFullMessage(payload) + const [signature, recoveryId] = splitEvmSignature( + Buffer.from(fullSignature).toString('hex') + ) + return { + publicKey, + signature, + recoveryId, + fullMessage, + } +} + export function cosmwasmBuildSignedMessage( pub_key: AminoPubkey, address: string, diff --git a/frontend/components/EcosystemConnectButton.tsx b/frontend/components/EcosystemConnectButton.tsx index 511c6699..afe86934 100644 --- a/frontend/components/EcosystemConnectButton.tsx +++ b/frontend/components/EcosystemConnectButton.tsx @@ -24,9 +24,9 @@ export function EcosystemConnectButton({ return case Ecosystem.INJECTIVE: return ( - ) case Ecosystem.TERRA: diff --git a/frontend/components/wallets/Cosmos.tsx b/frontend/components/wallets/Cosmos.tsx index db8ecab3..8036c842 100644 --- a/frontend/components/wallets/Cosmos.tsx +++ b/frontend/components/wallets/Cosmos.tsx @@ -13,7 +13,7 @@ import { WALLET_NAME, } from 'hooks/useChainWallet' -export type ChainName = 'osmosis' | 'terra' +export type ChainName = 'osmosis' | 'terra' | 'injective' type CosmosWalletProviderProps = { children: JSX.Element diff --git a/frontend/hooks/useGetEcosystemIdentity.ts b/frontend/hooks/useGetEcosystemIdentity.ts index 1e10c834..fa84563c 100644 --- a/frontend/hooks/useGetEcosystemIdentity.ts +++ b/frontend/hooks/useGetEcosystemIdentity.ts @@ -18,14 +18,13 @@ import useDiscordAuth from './useDiscordAuth' export function useGetEcosystemIdentity() { const aptosAddress = useAptosAddress() const evmAddress = useEVMAddress() + const injectiveAddress = useCosmosAddress('injective') const osmosisAddress = useCosmosAddress('osmosis') const terraAddress = useCosmosAddress('terra') const solanaAddress = useSolanaAddress() const suiAddress = useSuiAddress() const algorandAddress = useAlgorandAddress() - // TODO update logic to get discord data from lambda function execution - // const { data } = useSession() - const data = {} as any + const { profile } = useDiscordAuth() return useCallback( @@ -38,7 +37,7 @@ export function useGetEcosystemIdentity() { return evmAddress case Ecosystem.INJECTIVE: - return evmAddress ? getInjectiveAddress(evmAddress) : undefined + return injectiveAddress case Ecosystem.OSMOSIS: return osmosisAddress @@ -64,6 +63,7 @@ export function useGetEcosystemIdentity() { profile, evmAddress, osmosisAddress, + injectiveAddress, terraAddress, solanaAddress, suiAddress, diff --git a/frontend/hooks/useSignMessage.tsx b/frontend/hooks/useSignMessage.tsx index d7034ded..9b45155a 100644 --- a/frontend/hooks/useSignMessage.tsx +++ b/frontend/hooks/useSignMessage.tsx @@ -11,6 +11,7 @@ import { aptosBuildSignedMessage, suiBuildSignedMessage, algorandBuildSignedMessage, + injectiveBuildSignedMessage, } from 'claim_sdk/ecosystems/signatures' import { Ecosystem } from '@components/Ecosystem' import { fetchDiscordSignedMessage } from 'utils/api' @@ -18,6 +19,9 @@ import { useTokenDispenserProvider } from './useTokenDispenserProvider' import { ChainName } from '@components/wallets/Cosmos' import { useWallet as useAlgorandWallet } from '@components/Ecosystem/AlgorandProvider' import useDiscordAuth from './useDiscordAuth' +import { publicKey } from '@coral-xyz/anchor/dist/cjs/utils' +import { getUncompressedPubkey } from 'claim_sdk/ecosystems/cosmos' +import { uncompressedToEvmPubkey } from 'claim_sdk/ecosystems/evm' // SignMessageFn signs the message and returns it. // It will return undefined: @@ -62,6 +66,34 @@ export function useAptosSignMessage(nonce = 'nonce'): SignMessageFn { return signMessageCb } +export function useInjectiveSignMessage(): SignMessageFn { + const { address, isWalletConnected, getAccount } = useChainWallet( + 'injective', + 'keplr-extension' + ) + const signMessageCb = useCallback( + async (payload: string) => { + if (address === undefined || isWalletConnected === false) return + const account = await getAccount() + const uncompressedPublicKey = getUncompressedPubkey(account.pubkey) + const evmPubkey = uncompressedToEvmPubkey(uncompressedPublicKey) + const signature = await (window as any).keplr.signEthereum( + 'injective-1', + address, + payload, + 'message' + ) + return injectiveBuildSignedMessage( + Buffer.from(evmPubkey), + signature, + payload + ) + }, + [address, getAccount, isWalletConnected] + ) + return signMessageCb +} + // This hook returns a function to sign message for the Cosmos wallet. export function useCosmosSignMessage( chainName: ChainName, @@ -186,7 +218,7 @@ export function useDiscordSignMessage(): SignMessageFn { } // This hook returns a function to sign message for the Algorand wallet. -export function useAlgorandSignMessage(nonce = 'nonce'): SignMessageFn { +export function useAlgorandSignMessage(): SignMessageFn { const { signMessage, connected, account } = useAlgorandWallet() const signMessageCb = useCallback( @@ -201,7 +233,7 @@ export function useAlgorandSignMessage(nonce = 'nonce'): SignMessageFn { console.error(e) } }, - [connected, account, signMessage, nonce] + [connected, account, signMessage] ) return signMessageCb } @@ -210,6 +242,7 @@ export function useAlgorandSignMessage(nonce = 'nonce'): SignMessageFn { export function useSignMessage(ecosystem: Ecosystem): SignMessageFn { const aptosSignMessageFn = useAptosSignMessage() const evmSignMessageFn = useEVMSignMessage() + const injectiveSignMessageFn = useInjectiveSignMessage() const osmosisSignMessageFn = useCosmosSignMessage('osmosis') const terraSignMessageFn = useCosmosSignMessage('terra') const suiSignMessageFn = useSuiSignMessage() @@ -223,7 +256,7 @@ export function useSignMessage(ecosystem: Ecosystem): SignMessageFn { case Ecosystem.EVM: return evmSignMessageFn case Ecosystem.INJECTIVE: - return evmSignMessageFn + return injectiveSignMessageFn case Ecosystem.TERRA: return terraSignMessageFn case Ecosystem.OSMOSIS: diff --git a/frontend/utils/chain-registry.ts b/frontend/utils/chain-registry.ts index 8348ac79..f28003a1 100644 --- a/frontend/utils/chain-registry.ts +++ b/frontend/utils/chain-registry.ts @@ -69,6 +69,45 @@ export const assets = [ }, ], }, + { + $schema: '../assetlist.schema.json', + chain_name: 'injective', + assets: [ + { + description: + 'The INJ token is the native governance token for the Injective chain.', + denom_units: [ + { + denom: 'inj', + exponent: 0, + }, + { + denom: 'INJ', + exponent: 18, + }, + ], + base: 'inj', + name: 'Injective', + display: 'INJ', + symbol: 'INJ', + logo_URIs: { + png: 'https://raw.githubusercontent.com/cosmos/chain-registry/master/injective/images/inj.png', + svg: 'https://raw.githubusercontent.com/cosmos/chain-registry/master/injective/images/inj.svg', + }, + coingecko_id: 'injective-protocol', + images: [ + { + png: 'https://raw.githubusercontent.com/cosmos/chain-registry/master/injective/images/inj.png', + svg: 'https://raw.githubusercontent.com/cosmos/chain-registry/master/injective/images/inj.svg', + }, + ], + socials: { + webiste: 'https://injective.com/', + twitter: 'https://twitter.com/Injective_', + }, + }, + ], + }, ] export const chains = [ @@ -1137,4 +1176,361 @@ export const chains = [ ], keywords: ['dex'], }, + { + $schema: '../chain.schema.json', + chain_name: 'injective', + status: 'live', + network_type: 'mainnet', + website: 'https://injective.com/', + pretty_name: 'Injective', + chain_id: 'injective-1', + bech32_prefix: 'inj', + extra_codecs: ['injective'], + slip44: 60, + daemon_name: 'injectived', + node_home: '$HOME/.injectived', + fees: { + fee_tokens: [ + { + denom: 'inj', + fixed_min_gas_price: 160000000, + low_gas_price: 500000000, + average_gas_price: 700000000, + high_gas_price: 900000000, + }, + ], + }, + staking: { + staking_tokens: [ + { + denom: 'inj', + }, + ], + }, + logo_URIs: { + png: 'https://raw.githubusercontent.com/cosmos/chain-registry/master/injective/images/inj.png', + svg: 'https://raw.githubusercontent.com/cosmos/chain-registry/master/injective/images/inj.svg', + }, + description: + 'Injective’s mission is to create a truly free and inclusive financial system through decentralization.', + peers: { + seeds: [ + { + id: '38c18461209694e1f667ff2c8636ba827cc01c86', + address: '176.9.143.252:11751', + provider: 'injectivelabs.org', + }, + { + id: '4f9025feca44211eddc26cd983372114947b2e85', + address: '176.9.140.49:11751', + provider: 'injectivelabs.org', + }, + { + id: 'c98bb1b889ddb58b46e4ad3726c1382d37cd5609', + address: '65.109.51.80:11751', + provider: 'injectivelabs.org', + }, + { + id: '23d0eea9bb42316ff5ea2f8b4cd8475ef3f35209', + address: '65.109.36.70:11751', + provider: 'injectivelabs.org', + }, + { + id: 'f9ae40fb4a37b63bea573cc0509b4a63baa1a37a', + address: '15.235.114.80:11751', + provider: 'injectivelabs.org', + }, + { + id: '7f3473ddab10322b63789acb4ac58647929111ba', + address: '15.235.13.116:11751', + provider: 'injectivelabs.org', + }, + { + id: 'ade4d8bc8cbe014af6ebdf3cb7b1e9ad36f412c0', + address: 'seeds.polkachu.com:14356', + provider: 'polkachu.com', + }, + { + id: 'ebc272824924ea1a27ea3183dd0b9ba713494f83', + address: 'injective-mainnet-seed.autostake.com:26726', + provider: 'AutoStake 🛡️ Slash Protected', + }, + { + id: '20e1000e88125698264454a884812746c2eb4807', + address: 'seeds.lavenderfive.com:14356', + provider: 'Lavender.Five Nodes 🐝', + }, + { + id: '1846e76e14913124a07e231586d487a0636c0296', + address: 'tenderseed.ccvalidators.com:26007', + provider: 'ccvalidators.com', + }, + { + id: '5a1cd1a7da5aab3e3075fbae0a905c7256e48193', + address: 'seeds.goldenratiostaking.net:1635', + provider: 'Golden Ratio Staking', + }, + { + id: '8542cd7e6bf9d260fef543bc49e59be5a3fa9074', + address: 'seed.publicnode.com:26656', + provider: 'Allnodes ⚡️ Nodes & Staking', + }, + { + id: 'c28827cb96c14c905b127b92065a3fb4cd77d7f6', + address: 'seeds.whispernode.com:14356', + provider: 'WhisperNode 🤐', + }, + { + id: '858c86e2590f82934b8483ed184afd88416a7b31', + address: 'seed-injective-01.stakeflow.io:2106', + provider: 'Stakeflow', + }, + ], + persistent_peers: [ + { + id: '38c18461209694e1f667ff2c8636ba827cc01c86', + address: '176.9.143.252:11751', + provider: 'injectivelabs.org', + }, + { + id: '4f9025feca44211eddc26cd983372114947b2e85', + address: '176.9.140.49:11751', + provider: 'injectivelabs.org', + }, + { + id: 'c98bb1b889ddb58b46e4ad3726c1382d37cd5609', + address: '65.109.51.80:11751', + provider: 'injectivelabs.org', + }, + { + id: '23d0eea9bb42316ff5ea2f8b4cd8475ef3f35209', + address: '65.109.36.70:11751', + provider: 'injectivelabs.org', + }, + { + id: 'f9ae40fb4a37b63bea573cc0509b4a63baa1a37a', + address: '15.235.114.80:11751', + provider: 'injectivelabs.org', + }, + { + id: '7f3473ddab10322b63789acb4ac58647929111ba', + address: '15.235.13.116:11751', + provider: 'injectivelabs.org', + }, + { + id: 'ebc272824924ea1a27ea3183dd0b9ba713494f83', + address: 'injective-mainnet-peer.autostake.com:26726', + provider: 'AutoStake 🛡️ Slash Protected', + }, + { + id: '858c86e2590f82934b8483ed184afd88416a7b31', + address: 'peer-injective-01.stakeflow.io:2106', + provider: 'Stakeflow', + }, + ], + }, + apis: { + rpc: [ + { + address: 'https://injective-1-public-rpc.mesa.ec1-prod.newmetric.xyz', + provider: 'NewMetric', + }, + { + address: 'https://rpc-injective.goldenratiostaking.net', + provider: 'Golden Ratio Staking', + }, + { + address: 'https://injective-rpc.polkachu.com', + provider: 'Polkachu', + }, + { + address: 'https://injective-rpc.lavenderfive.com:443', + provider: 'Lavender.Five Nodes 🐝', + }, + { + address: 'https://rpc-injective-ia.cosmosia.notional.ventures/', + provider: 'Notional', + }, + { + address: 'https://injective-mainnet-rpc.autostake.com:443', + provider: 'AutoStake 🛡️ Slash Protected', + }, + { + address: 'https://rpc-injective.whispernode.com:443', + provider: 'WhisperNode 🤐', + }, + { + address: 'https://rpc-injective-01.stakeflow.io', + provider: 'Stakeflow', + }, + { + address: 'https://injective-rpc.publicnode.com:443', + provider: 'Allnodes ⚡️ Nodes & Staking', + }, + { + address: 'https://injective-rpc.highstakes.ch', + provider: 'High Stakes 🇨🇭', + }, + { + address: 'https://public.stakewolle.com/cosmos/injective/rpc', + provider: 'Stakewolle', + }, + { + address: 'https://rpc.injective.bronbro.io/', + provider: 'Bro_n_Bro', + }, + ], + rest: [ + { + address: + 'https://injective-1-public-rest.mesa.ec1-prod.newmetric.xyz', + provider: 'NewMetric', + }, + { + address: 'https://api-injective-ia.cosmosia.notional.ventures/', + provider: 'Notional', + }, + { + address: 'https://injective-api.polkachu.com', + provider: 'Polkachu', + }, + { + address: 'https://injective-api.lavenderfive.com:443', + provider: 'Lavender.Five Nodes 🐝', + }, + { + address: 'https://lcd-injective.whispernode.com:443', + provider: 'WhisperNode 🤐', + }, + { + address: 'https://api-injective-01.stakeflow.io', + provider: 'Stakeflow', + }, + { + address: 'https://rest-injective.goldenratiostaking.net', + provider: 'Golden Ratio Staking', + }, + { + address: 'https://injective-rest.publicnode.com', + provider: 'Allnodes ⚡️ Nodes & Staking', + }, + { + address: 'injective-mainnet-lcd.autostake.com:443', + provider: 'AutoStake 🛡️ Slash Protected', + }, + { + address: 'https://injective-api.highstakes.ch', + provider: 'High Stakes 🇨🇭', + }, + { + address: 'https://public.stakewolle.com/cosmos/injective/rest', + provider: 'Stakewolle', + }, + { + address: 'https://lcd.injective.bronbro.io/', + provider: 'Bro_n_Bro', + }, + ], + grpc: [ + { + address: + 'k8s-injectiv-publicin-731c880328-0f3d7889b57e31a3.elb.eu-central-1.amazonaws.com:80', + provider: 'NewMetric', + }, + { + address: 'grpc-injective-ia.cosmosia.notional.ventures:443', + provider: 'Notional', + }, + { + address: 'injective-grpc.lavenderfive.com:443', + provider: 'Lavender.Five Nodes 🐝', + }, + { + address: 'injective-grpc.polkachu.com:14390', + provider: 'Polkachu', + }, + { + address: 'injective-mainnet-grpc.autostake.com:443', + provider: 'AutoStake 🛡️ Slash Protected', + }, + { + address: 'grpc-injective.cosmos-spaces.cloud:9900', + provider: 'Cosmos Spaces', + }, + { + address: 'grpc.injective.posthuman.digital:80', + provider: 'POSTHUMAN ꝏ DVS', + }, + { + address: 'grpc-injective.architectnodes.com:1443', + provider: 'Architect Nodes', + }, + { + address: 'grpc-injective-01.stakeflow.io:2102', + provider: 'Stakeflow', + }, + { + address: 'injective-grpc.publicnode.com:443', + provider: 'Allnodes ⚡️ Nodes & Staking', + }, + { + address: 'injective-grpc.w3coins.io:14390', + provider: 'w3coins', + }, + { + address: 'grpc-injective.whispernode.com:443', + provider: 'WhisperNode 🤐', + }, + { + address: 'grpc.injective.bronbro.io:443', + provider: 'Bro_n_Bro', + }, + ], + }, + explorers: [ + { + kind: 'ezstaking', + url: 'https://ezstaking.app/injective', + tx_page: 'https://ezstaking.app/injective/txs/${txHash}', + account_page: + 'https://ezstaking.app/injective/account/${accountAddress}', + }, + { + kind: 'injectiveprotocol', + url: 'https://explorer.injective.network/', + tx_page: 'https://explorer.injective.network/transaction/${txHash}', + }, + { + kind: 'ping.pub', + url: 'https://ping.pub/injective', + tx_page: 'https://ping.pub/injective/tx/${txHash}', + }, + { + kind: 'atomscan', + url: 'https://atomscan.com/injective', + tx_page: 'https://atomscan.com/injective/transactions/${txHash}', + account_page: + 'https://atomscan.com/injective/accounts/${accountAddress}', + }, + { + kind: 'mintscan', + url: 'https://www.mintscan.io/injective', + tx_page: 'https://www.mintscan.io/injective/transactions/${txHash}', + account_page: + 'https://www.mintscan.io/injective/accounts/${accountAddress}', + }, + { + kind: 'Stakeflow', + url: 'https://stakeflow.io/injective', + account_page: + 'https://stakeflow.io/injective/accounts/${accountAddress}', + }, + ], + images: [ + { + png: 'https://raw.githubusercontent.com/cosmos/chain-registry/master/injective/images/inj.png', + svg: 'https://raw.githubusercontent.com/cosmos/chain-registry/master/injective/images/inj.svg', + }, + ], + }, ] From 12003dc761c69d7fdbc0ae21408c17f6be8399d8 Mon Sep 17 00:00:00 2001 From: Valentino Conti <41705567+valentinoConti@users.noreply.github.com> Date: Mon, 1 Apr 2024 13:50:19 -0300 Subject: [PATCH 05/12] Add OKX Wallet support (#63) --- frontend/components/wallets/EVM.tsx | 45 +++++++++++--- frontend/components/wallets/WalletButton.tsx | 2 +- frontend/images/okx.svg | 65 ++++++++++++++++++++ 3 files changed, 104 insertions(+), 8 deletions(-) create mode 100644 frontend/images/okx.svg diff --git a/frontend/components/wallets/EVM.tsx b/frontend/components/wallets/EVM.tsx index c00a4e4e..8f9270cf 100644 --- a/frontend/components/wallets/EVM.tsx +++ b/frontend/components/wallets/EVM.tsx @@ -17,10 +17,13 @@ import { publicProvider } from 'wagmi/providers/public' import { CoinbaseWalletConnector } from 'wagmi/connectors/coinbaseWallet' import { MetaMaskConnector } from 'wagmi/connectors/metaMask' import { WalletConnectConnector } from 'wagmi/connectors/walletConnect' +import { InjectedConnector } from 'wagmi/connectors/injected' import coinbase from '@images/coinbase.svg' import walletConnect from '@images/wallet-connect.svg' import metamask from '@images/metamask.svg' +import okx from '@images/okx.svg' + import { getInjectiveAddress } from '../../utils/getInjectiveAddress' // Configure chains & providers with the Alchemy provider. @@ -56,7 +59,7 @@ const config = createConfig({ webSocketPublicClient, }) -type WalletIds = 'metaMask' | 'coinbaseWallet' | 'walletConnect' +type WalletIds = 'metaMask' | 'coinbaseWallet' | 'walletConnect' | 'injected' type EVMWalletProviderProps = { children: ReactNode @@ -79,6 +82,7 @@ export function EVMWalletButton({ const { disconnect } = useDisconnect() const { address, status, isConnected, connector } = useAccount() const { connect, connectors } = useConnect() + const hasOKXWallet = typeof (window as any).okxwallet !== 'undefined' // If the wallet is connected or loadable, try to connect to it. // Else, redirect user to the wallet webpage. @@ -87,25 +91,51 @@ export function EVMWalletButton({ if (connector.name === 'MetaMask') { if (window.ethereum.isMetaMask === true) connect({ connector }) else window.open('https://metamask.io/download/', '_blank') + } else if (connector.name === 'OKX Wallet') { + if (hasOKXWallet) connect({ connector }) + else window.open('https://www.okx.com/web3', '_blank') } else { // Wallet flow is handled pretty well by coinbase and walletconnect. // We don't need to customize connect({ connector }) } }, - [connect] + [connect, hasOKXWallet] ) + const wallets = () => { + const allConnectors = connectors.map((connector) => { + return { + name: connector.name, + onSelect: () => onSelect(connector), + icon: getIcon(connector.id as WalletIds), + } + }) + + const OKX_connector = new InjectedConnector({ + chains, + options: { + name: 'OKX Wallet', + getProvider: () => + typeof window !== undefined ? (window as any).okxwallet : undefined, + }, + }) + + allConnectors.push({ + name: 'OKX Wallet', + icon: getIcon(OKX_connector.id as WalletIds), + onSelect: () => onSelect(OKX_connector), + }) + + return allConnectors + } + return ( ({ - name: connector.name, - onSelect: () => onSelect(connector), - icon: getIcon(connector.id as WalletIds), - }))} + wallets={wallets()} isEVM={true} walletConnectedButton={(address: string) => ( openModal(false)} - key={wallet.icon} + key={wallet.name} /> ) })} diff --git a/frontend/images/okx.svg b/frontend/images/okx.svg new file mode 100644 index 00000000..9e1e7754 --- /dev/null +++ b/frontend/images/okx.svg @@ -0,0 +1,65 @@ + + + + + + + + + + + From 2e63c615955211736b61ef31a7c333eb662e8d51 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Mon, 1 Apr 2024 14:54:09 -0300 Subject: [PATCH 06/12] update w decimals to 6 (#64) --- frontend/utils/toStringWithDecimals.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/utils/toStringWithDecimals.ts b/frontend/utils/toStringWithDecimals.ts index 2b8552f3..9e075134 100644 --- a/frontend/utils/toStringWithDecimals.ts +++ b/frontend/utils/toStringWithDecimals.ts @@ -1,7 +1,7 @@ import BN from 'bn.js' const TRAILING_ZEROS = new RegExp(/\.?0+$/) -const W_DECIMALS = 9 +const W_DECIMALS = 6 export function toStringWithDecimals(amount: BN) { const padded = amount.toString().padStart(W_DECIMALS + 1, '0') From 42eeea94e8374aeb33b956e12205bf0f73a29768 Mon Sep 17 00:00:00 2001 From: Andreas <41449730+nonergodic@users.noreply.github.com> Date: Mon, 1 Apr 2024 13:20:52 -0700 Subject: [PATCH 07/12] make treasury unrestricted and remove funder from config (#37) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add lookup table back to config for ease of use in sdk * manually update program IDLs in claim_sdk * formatting * fix integration tests * more integration test fixes * fix compilation by putting stub in place * formatting * adds treasury pub-key to ClaimEvent * minor fix * multi-treasury deployment * mt-02 * Treasury selection (#58) * add lookup table back to config for ease of use in sdk * manually update program IDLs in claim_sdk * formatting * fix integration tests * more integration test fixes * fix compilation by putting stub in place * formatting * adds treasury pub-key to ClaimEvent * minor fix * multi-treasury deployment * mt-02 * WIP treasury and funders pull and selection * treasury list without env * support multiple funders and use same one than frontend to sign * sign transaction in the frontend and pass the funder used to the backend * fix mayority of tests * remove injective test to be up to date with main * fix BE tests * FE prettier * BE prettier * fix linter * updated treasury addresses * fix linting * Fix algorand claim info identity serialization (#56) * Add message for EVM wallet selector (#59) * backend: modifies private key secret format We expect a list of private keys as an array of number arrays. * backend: adds types for node v18 * frontend: use `JSON.parse` to parse private key in test * backend: prettier run * all: replaces token dispenser program id env var with constant * update toStringWithDecimals from 9 to 6 * remove injective test * fix yarn.lock * fix backend prettier * frontend fix prettier * token dispenser fix prettier * run pre-commit locally * linter * added solana/web3 dep * multi-treasury deployment 03 * use tokenDispenserProgramId from same workspace * prettier * remove dep between front and back * update treasuries and funders * frontend prettier --------- Co-authored-by: nonergodic Co-authored-by: solanoe Co-authored-by: Martin Picco Co-authored-by: Valentino Conti <41705567+valentinoConti@users.noreply.github.com> Co-authored-by: Sebastián Claudio Nale --------- Co-authored-by: solanoe Co-authored-by: Brian Monroy <48845597+brianUtn98@users.noreply.github.com> Co-authored-by: Martin Picco Co-authored-by: Valentino Conti <41705567+valentinoConti@users.noreply.github.com> Co-authored-by: Sebastián Claudio Nale --- .github/workflows/frontend.yml | 3 - backend/README.md | 1 - backend/package.json | 1 + backend/src/config.ts | 2 +- backend/src/handlers/fund-transactions.ts | 43 +- backend/src/utils/fund-transactions.ts | 31 +- backend/src/utils/secrets.ts | 21 +- .../test/handlers/fund-transactions.test.ts | 27 +- backend/yarn.lock | 7 + frontend/.env.sample | 1 - frontend/claim_sdk/idl/token_dispenser.json | 30 +- frontend/claim_sdk/idl/token_dispenser.ts | 56 +- frontend/claim_sdk/solana.ts | 97 +- frontend/claim_sdk/testWallets.ts | 43 +- frontend/claim_sdk/treasury.ts | 32 + frontend/hooks/useTokenDispenserProvider.tsx | 3 +- frontend/integration/api.test.ts | 233 +- frontend/integration/api.ts | 69 +- frontend/integration/integrationTest.test.ts | 114 +- frontend/next.config.js | 1 - frontend/scripts/datadog.ts | 4 +- frontend/sections/SignAndClaim.tsx | 6 +- frontend/utils/api.ts | 17 +- frontend/utils/constants.ts | 3 + frontend/utils/isClaimAlreadySubmitted.ts | 3 +- token-dispenser/Anchor.toml | 6 +- token-dispenser/package-lock.json | 2815 +++++++++++++++++ token-dispenser/package.json | 3 +- .../token-dispenser/src/ecosystems/cosmos.rs | 70 +- .../programs/token-dispenser/src/lib.rs | 38 +- .../src/tests/dispenser_simulator.rs | 7 +- .../token-dispenser/src/tests/test_discord.rs | 1 - .../src/tests/test_happy_path.rs | 3 - .../src/tests/test_initialize.rs | 56 +- token-dispenser/scripts/create-treasuries.sh | 31 + token-dispenser/scripts/fund-treasuries.sh | 20 + token-dispenser/scripts/treasuries | 6 + token-dispenser/ts/scripts/config.ts | 22 + .../ts/scripts/create-spl-token.ts | 2 +- token-dispenser/ts/scripts/initialize.ts | 28 +- .../ts/scripts/print-config-pda.ts | 27 + .../ts/sdk/idl/token_dispenser.json | 46 +- token-dispenser/ts/sdk/idl/token_dispenser.ts | 88 +- token-dispenser/ts/sdk/token-dispenser.ts | 36 +- token-dispenser/yarn.lock | 123 +- 45 files changed, 3619 insertions(+), 657 deletions(-) create mode 100644 frontend/claim_sdk/treasury.ts create mode 100644 token-dispenser/package-lock.json create mode 100755 token-dispenser/scripts/create-treasuries.sh create mode 100755 token-dispenser/scripts/fund-treasuries.sh create mode 100644 token-dispenser/scripts/treasuries create mode 100644 token-dispenser/ts/scripts/config.ts create mode 100644 token-dispenser/ts/scripts/print-config-pda.ts diff --git a/.github/workflows/frontend.yml b/.github/workflows/frontend.yml index 9447ec15..09ac16c3 100644 --- a/.github/workflows/frontend.yml +++ b/.github/workflows/frontend.yml @@ -14,9 +14,6 @@ jobs: env: ENDPOINT: http://localhost:8899 - env: - PROGRAM_ID: WabZqXyytFA2XeXswf9DdQkQuSZuRiEgKdDmq7c5Mnp - defaults: run: working-directory: ./frontend diff --git a/backend/README.md b/backend/README.md index e68ec925..7deef69f 100644 --- a/backend/README.md +++ b/backend/README.md @@ -28,4 +28,3 @@ Following env vars are required: - `DISPENSER_KEY_SECRET_NAME`: private key of the wallet that will be used to sign the discord message - `FUNDER_WALLET_KEY_SECRET_NAME`: private key of the wallet that will be used to fund the transactions -- `TOKEN_DISPENSER_PROGRAM_ID`: the program id of the token dispenser diff --git a/backend/package.json b/backend/package.json index d79178fe..b821deae 100644 --- a/backend/package.json +++ b/backend/package.json @@ -34,6 +34,7 @@ "@types/aws-lambda": "^8.10.136", "@types/express": "^4.17.21", "@types/jest": "^29.5.12", + "@types/node": "^18", "@typescript-eslint/eslint-plugin": "^7.3.1", "@typescript-eslint/parser": "^7.3.1", "body-parser": "^1.20.2", diff --git a/backend/src/config.ts b/backend/src/config.ts index 7b44ab5b..c84775c4 100644 --- a/backend/src/config.ts +++ b/backend/src/config.ts @@ -5,7 +5,7 @@ export default { aws: { region: process.env.AWS_REGION ?? 'us-east-2' }, - tokenDispenserProgramId: () => process.env.TOKEN_DISPENSER_PROGRAM_ID, + tokenDispenserProgramId: () => 'WapFw9mSyHh8trDDRy7AamUn1V7QiGaVvtouj5AucQA', secrets: { dispenserGuard: { /** optional. mostly for local testing */ diff --git a/backend/src/handlers/fund-transactions.ts b/backend/src/handlers/fund-transactions.ts index 443ea1d7..71f02daf 100644 --- a/backend/src/handlers/fund-transactions.ts +++ b/backend/src/handlers/fund-transactions.ts @@ -1,12 +1,12 @@ import NodeWallet from '@coral-xyz/anchor/dist/cjs/nodewallet' import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda' -import { getFundingKey } from '../utils/secrets' +import { getFundingKeys } from '../utils/secrets' import { checkTransactions, deserializeTransactions, extractCallData } from '../utils/fund-transactions' -import { Keypair, VersionedTransaction } from '@solana/web3.js' +import { VersionedTransaction } from '@solana/web3.js' import bs58 from 'bs58' import { HandlerError } from '../utils/errors' import { asJsonResponse } from '../utils/response' @@ -15,7 +15,7 @@ import { saveSignedTransactions } from '../utils/persistence' export type FundTransactionRequest = Uint8Array[] -let funderWallet: NodeWallet +const funderWallets: Record = {} export const fundTransactions = async ( event: APIGatewayProxyEvent @@ -24,15 +24,29 @@ export const fundTransactions = async ( const requestBody = JSON.parse(event.body!) validateFundTransactions(requestBody) const transactions = deserializeTransactions(requestBody) - const isTransactionsValid = await checkTransactions(transactions) + const isTransactionsValid = await checkTransactions( + transactions.map((txWithFunder) => txWithFunder.transaction) + ) if (!isTransactionsValid) { return asJsonResponse(403, { error: 'Unauthorized transactions' }) } - const wallet = await loadFunderWallet() + const wallets = await loadFunderWallets() + + const signedTransactions: VersionedTransaction[] = [] + + for (const txWithFunder of transactions) { + const funderWallet = wallets[txWithFunder.funder] + if (!funderWallet) { + return asJsonResponse(403, { error: 'Unauthorized funder' }) + } + + signedTransactions.push( + await funderWallet.signTransaction(txWithFunder.transaction) + ) + } - const signedTransactions = await wallet.signAllTransactions(transactions) await saveSignedTransactions(getSignatures(signedTransactions)) return asJsonResponse( @@ -60,19 +74,18 @@ function validateFundTransactions(transactions: unknown) { } } -async function loadFunderWallet(): Promise { - if (funderWallet) { - return funderWallet +async function loadFunderWallets(): Promise> { + if (Object.keys(funderWallets).length > 0) { + return funderWallets } - const secretData = await getFundingKey() - const funderWalletKey = secretData.key + const secretData = await getFundingKeys() - const keypair = Keypair.fromSecretKey(Uint8Array.from(funderWalletKey)) + secretData.forEach((keypair) => { + funderWallets[keypair.publicKey.toBase58()] = new NodeWallet(keypair) + }) - funderWallet = new NodeWallet(keypair) - console.log('Loaded funder wallet') - return funderWallet + return funderWallets } function getSignature(tx: VersionedTransaction): string { diff --git a/backend/src/utils/fund-transactions.ts b/backend/src/utils/fund-transactions.ts index fee2c986..d744ef15 100644 --- a/backend/src/utils/fund-transactions.ts +++ b/backend/src/utils/fund-transactions.ts @@ -17,12 +17,29 @@ const SET_COMPUTE_UNIT_PRICE_DISCRIMINANT = 3 const MAX_COMPUTE_UNIT_PRICE = BigInt(1_000_000) +export type TransactionWithFunder = { + transaction: VersionedTransaction + funder: string +} + +export type SerializedTransactionWithFunder = { + tx: Uint8Array + funder: string +} + export function deserializeTransactions( transactions: unknown -): VersionedTransaction[] { +): TransactionWithFunder[] { try { - return (transactions as Uint8Array[]).map((serializedTx) => - VersionedTransaction.deserialize(Buffer.from(serializedTx)) + return (transactions as SerializedTransactionWithFunder[]).map( + (serializedTx) => { + return { + transaction: VersionedTransaction.deserialize( + Buffer.from(serializedTx.tx) + ), + funder: serializedTx.funder + } + } ) } catch (err) { console.error('Failed to deserialize transactions', err) @@ -31,14 +48,14 @@ export function deserializeTransactions( } async function loadWhitelistedProgramIds(): Promise { - const programId = config.tokenDispenserProgramId() - if (!programId) { + const tokenDispenserProgramId = config.tokenDispenserProgramId() + if (!tokenDispenserProgramId) { throw new Error('Token dispenser program ID not set') } - const PROGRAM_ID = new PublicKey(programId) + const tokenDispenserPublicKey = new PublicKey(tokenDispenserProgramId) return [ - PROGRAM_ID, + tokenDispenserPublicKey, Secp256k1Program.programId, Ed25519Program.programId, ComputeBudgetProgram.programId diff --git a/backend/src/utils/secrets.ts b/backend/src/utils/secrets.ts index 9939649c..f148c0d1 100644 --- a/backend/src/utils/secrets.ts +++ b/backend/src/utils/secrets.ts @@ -4,9 +4,14 @@ import { GetSecretValueCommand } from '@aws-sdk/client-secrets-manager' import config from '../config' +import { Keypair } from '@solana/web3.js' const client = new SecretsManagerClient({ region: config.aws.region }) +interface SecretPrivateKeys { + keys: string +} + export async function getDispenserKey() { let key: string if (config.secrets.dispenserGuard.key) { @@ -19,16 +24,12 @@ export async function getDispenserKey() { return { key: JSON.parse(key) } } -export async function getFundingKey(): Promise<{ key: Uint8Array }> { - let key: string - if (config.secrets.funding.key()) { - console.log('Using funding key from config') - key = config.secrets.funding.key()! - } else { - key = await getSecretKey(config.secrets.funding.secretName, 'key') - } - - return { key: JSON.parse(key) } +export async function getFundingKeys(): Promise { + const secret = (await getSecret( + config.secrets.funding.secretName + )) as SecretPrivateKeys + const keys = JSON.parse(secret.keys) as number[][] + return keys.map((key) => Keypair.fromSecretKey(Uint8Array.from(key))) } export async function getInfluxToken(): Promise { diff --git a/backend/test/handlers/fund-transactions.test.ts b/backend/test/handlers/fund-transactions.test.ts index 0784df04..34df093b 100644 --- a/backend/test/handlers/fund-transactions.test.ts +++ b/backend/test/handlers/fund-transactions.test.ts @@ -21,11 +21,13 @@ 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' +import config from '../../src/config' const RANDOM_BLOCKHASH = 'HXq5QPm883r7834LWwDpcmEM8G8uQ9Hqm1xakCHGxprV' +const tokenDispenserProgramId = config.tokenDispenserProgramId() +const TokenDispenserPublicKey = new PublicKey(tokenDispenserProgramId) 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') @@ -55,9 +57,9 @@ describe('fundTransactions integration test', () => { 8086 )}` process.env.INFLUXDB_FLUSH_ENABLED = 'true' - + process.env.AWS_ACCESS_KEY_ID = 'key' + process.env.AWS_SECRET_ACCESS_KEY = 'secret' process.env.FUNDING_WALLET_KEY = `[${FUNDER_KEY.secretKey}]` - process.env.TOKEN_DISPENSER_PROGRAM_ID = PROGRAM_ID.toString() }, 20_000) afterAll(async () => { @@ -230,7 +232,7 @@ describe('fundTransactions integration test', () => { const instructions = [ tokenDispenserInstruction, createComputeUnitLimitInstruction(200), - createComputeUnitPriceInstruction(BigInt(10000000)), + createComputeUnitPriceInstruction(BigInt(10_000_000)), createSecp256k1ProgramInstruction() ] @@ -246,7 +248,7 @@ describe('fundTransactions integration test', () => { await createTokenDispenserProgramInstruction() ]) - const callData = extractCallData(versionedTx, PROGRAM_ID.toBase58()) + const callData = extractCallData(versionedTx, tokenDispenserProgramId) expect(callData).not.toBeNull() expect(callData?.amount.toNumber()).toBe(3000000) @@ -272,7 +274,9 @@ const givenDownstreamServicesWork = () => { server.use( http.all('https://secretsmanager.us-east-2.amazonaws.com', () => { return HttpResponse.json({ - SecretString: JSON.stringify({ key: `[${[...FUNDER_KEY.secretKey]}]` }) + SecretString: JSON.stringify({ + keys: JSON.stringify([[...FUNDER_KEY.secretKey]]) + }) }) }) ) @@ -295,7 +299,14 @@ const givenCorrectTransaction = async () => { const whenFundTransactionsCalled = async () => { response = await fundTransactions({ - body: JSON.stringify(input.map((tx) => Buffer.from(tx.serialize()))) + body: JSON.stringify( + input.map((tx) => { + return { + tx: Buffer.from(tx.serialize()), + funder: FUNDER_KEY.publicKey + } + }) + ) } as unknown as APIGatewayProxyEvent) } @@ -354,7 +365,7 @@ const createTestLegacyTransactionFromInstructions = ( const createTokenDispenserProgramInstruction = async () => { const tokenDispenser = new Program( IDL, - PROGRAM_ID, + TokenDispenserPublicKey, new AnchorProvider( new Connection('http://localhost:8899'), new NodeWallet(new Keypair()), diff --git a/backend/yarn.lock b/backend/yarn.lock index 5382da0e..f3b086df 100644 --- a/backend/yarn.lock +++ b/backend/yarn.lock @@ -2038,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": + version "18.19.28" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.19.28.tgz#c64a2c992c8ebbf61100a4570e4eebc1934ae030" + integrity sha512-J5cOGD9n4x3YGgVuaND6khm5x07MMdAKkRyXnjVR6KFhLMNh2yONGiP7Z+4+tBOt5mK+GvDTiacTOVGGpqiecw== + dependencies: + undici-types "~5.26.4" + "@types/node@^18.11.18": version "18.19.26" resolved "https://registry.yarnpkg.com/@types/node/-/node-18.19.26.tgz#18991279d0a0e53675285e8cf4a0823766349729" diff --git a/frontend/.env.sample b/frontend/.env.sample index 0efadeea..f2d9fda0 100644 --- a/frontend/.env.sample +++ b/frontend/.env.sample @@ -31,7 +31,6 @@ FUNDER_KEYPAIR=[145,197,43,77,224,103,196,174,132,195,48,31,177,97,237,163,15,19 DEPLOYER_WALLET=[145,197,43,77,224,103,196,174,132,195,48,31,177,97,237,163,15,196,217,142,181,204,104,107,98,82,213,0,155,140,218,180,30,119,201,38,51,176,207,221,193,222,235,244,163,250,125,66,68,196,45,208,212,201,232,178,100,163,24,21,106,83,66,174] -PROGRAM_ID=WabZqXyytFA2XeXswf9DdQkQuSZuRiEgKdDmq7c5Mnp CSV_DIR=/tmp # Datadog Event Subscriber Configs diff --git a/frontend/claim_sdk/idl/token_dispenser.json b/frontend/claim_sdk/idl/token_dispenser.json index 277238a0..098c2327 100644 --- a/frontend/claim_sdk/idl/token_dispenser.json +++ b/frontend/claim_sdk/idl/token_dispenser.json @@ -21,18 +21,7 @@ { "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 `" - ] + "isSigner": false }, { "name": "systemProgram", @@ -56,10 +45,6 @@ "name": "dispenserGuard", "type": "publicKey" }, - { - "name": "funder", - "type": "publicKey" - }, { "name": "maxTransfer", "type": "u64" @@ -164,18 +149,10 @@ "name": "mint", "type": "publicKey" }, - { - "name": "treasury", - "type": "publicKey" - }, { "name": "addressLookupTable", "type": "publicKey" }, - { - "name": "funder", - "type": "publicKey" - }, { "name": "maxTransfer", "type": "u64" @@ -584,6 +561,11 @@ { "name": "ClaimEvent", "fields": [ + { + "name": "treasury", + "type": "publicKey", + "index": false + }, { "name": "remainingBalance", "type": "u64", diff --git a/frontend/claim_sdk/idl/token_dispenser.ts b/frontend/claim_sdk/idl/token_dispenser.ts index 7782a8f1..5f813551 100644 --- a/frontend/claim_sdk/idl/token_dispenser.ts +++ b/frontend/claim_sdk/idl/token_dispenser.ts @@ -22,17 +22,6 @@ export type TokenDispenser = { 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' @@ -56,10 +45,6 @@ export type TokenDispenser = { name: 'dispenserGuard' type: 'publicKey' }, - { - name: 'funder' - type: 'publicKey' - }, { name: 'maxTransfer' type: 'u64' @@ -164,18 +149,10 @@ export type TokenDispenser = { name: 'mint' type: 'publicKey' }, - { - name: 'treasury' - type: 'publicKey' - }, { name: 'addressLookupTable' type: 'publicKey' }, - { - name: 'funder' - type: 'publicKey' - }, { name: 'maxTransfer' type: 'u64' @@ -584,6 +561,11 @@ export type TokenDispenser = { { name: 'ClaimEvent' fields: [ + { + name: 'treasury' + type: 'publicKey' + index: false + }, { name: 'remainingBalance' type: 'u64' @@ -675,17 +657,6 @@ export const IDL: TokenDispenser = { 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', @@ -709,10 +680,6 @@ export const IDL: TokenDispenser = { name: 'dispenserGuard', type: 'publicKey', }, - { - name: 'funder', - type: 'publicKey', - }, { name: 'maxTransfer', type: 'u64', @@ -817,18 +784,10 @@ export const IDL: TokenDispenser = { name: 'mint', type: 'publicKey', }, - { - name: 'treasury', - type: 'publicKey', - }, { name: 'addressLookupTable', type: 'publicKey', }, - { - name: 'funder', - type: 'publicKey', - }, { name: 'maxTransfer', type: 'u64', @@ -1237,6 +1196,11 @@ export const IDL: TokenDispenser = { { name: 'ClaimEvent', fields: [ + { + name: 'treasury', + type: 'publicKey', + index: false, + }, { name: 'remainingBalance', type: 'u64', diff --git a/frontend/claim_sdk/solana.ts b/frontend/claim_sdk/solana.ts index 6d39b7b0..a079ef8f 100644 --- a/frontend/claim_sdk/solana.ts +++ b/frontend/claim_sdk/solana.ts @@ -27,6 +27,8 @@ import { TOKEN_PROGRAM_ID, Token } from '@solana/spl-token' import { SignedMessage } from './ecosystems/signatures' import { extractChainId } from './ecosystems/cosmos' import { fetchFundTransaction } from '../utils/api' +import { getClaimPayers } from './treasury' +import { inspect } from 'util' export const ERROR_SIGNING_TX = 'error: signing transaction' export const ERROR_FUNDING_TX = 'error: funding transaction' @@ -41,6 +43,11 @@ const AUTHORIZATION_PAYLOAD = [ '\nto claim my W tokens.\n', ] +export type TransactionWithPayers = { + tx: VersionedTransaction + payers: [PublicKey, PublicKey] +} + /** * This class wraps the interaction with the TokenDispenser * program for a specific claimant. The claimant will be the @@ -71,7 +78,10 @@ export class TokenDispenserProvider { provider ) as unknown as Program - this.configPda = this.getConfigPda() + this.configPda = anchor.web3.PublicKey.findProgramAddressSync( + [Buffer.from('config')], + this.programId + ) } get programId(): anchor.web3.PublicKey { @@ -91,13 +101,7 @@ export class TokenDispenserProvider { } public getConfigPda(): [anchor.web3.PublicKey, bump] { - return ( - this.configPda ?? - anchor.web3.PublicKey.findProgramAddressSync( - [Buffer.from('config')], - this.programId - ) - ) + return this.configPda } public async getConfig(): Promise['Config']> { @@ -141,36 +145,35 @@ export class TokenDispenserProvider { public async initialize( root: Buffer, mint: anchor.web3.PublicKey, - treasury: anchor.web3.PublicKey, dispenserGuard: anchor.web3.PublicKey, - funder: anchor.web3.PublicKey, + treasuries: readonly anchor.web3.PublicKey[], + funders: readonly anchor.web3.PublicKey[], maxTransfer: anchor.BN ): Promise { const addressLookupTable = await this.initAddressLookupTable( mint, - treasury, - funder + treasuries, + funders ) return this.tokenDispenserProgram.methods - .initialize(Array.from(root), dispenserGuard, funder, maxTransfer) + .initialize(Array.from(root), dispenserGuard, maxTransfer) .accounts({ config: this.getConfigPda()[0], mint, - treasury, systemProgram: anchor.web3.SystemProgram.programId, addressLookupTable, }) .rpc() } - private async initAddressLookupTable( + async initAddressLookupTable( mint: anchor.web3.PublicKey, - treasury: anchor.web3.PublicKey, - funder: anchor.web3.PublicKey + treasuries: readonly anchor.web3.PublicKey[], + funders: readonly anchor.web3.PublicKey[] ): Promise { const recentSlot = await this.provider.connection.getSlot() - const [loookupTableInstruction, lookupTableAddress] = + const [lookupTableInstruction, lookupTableAddress] = AddressLookupTableProgram.createLookupTable({ authority: this.provider.publicKey!, payer: this.provider.publicKey!, @@ -183,17 +186,17 @@ export class TokenDispenserProvider { addresses: [ this.configPda[0], mint, - treasury, TOKEN_PROGRAM_ID, SystemProgram.programId, SYSVAR_INSTRUCTIONS_PUBKEY, splToken.ASSOCIATED_TOKEN_PROGRAM_ID, - funder, + ...treasuries, + ...funders, ], }) let createLookupTableTx = new VersionedTransaction( new TransactionMessage({ - instructions: [loookupTableInstruction, extendInstruction], + instructions: [lookupTableInstruction, extendInstruction], payerKey: this.provider.publicKey!, recentBlockhash: (await this.connection.getLatestBlockhash()).blockhash, }).compileToV0Message() @@ -229,38 +232,61 @@ export class TokenDispenserProvider { signedMessage: SignedMessage | undefined }[], fetchFundTransactionFunction: ( - transactions: VersionedTransaction[] - ) => Promise = fetchFundTransaction // This argument is only used for testing where we can't call the API + transactions: TransactionWithPayers[] + ) => Promise = fetchFundTransaction, // This argument is only used for testing where we can't call the API + getPayersForClaim: ( + claimInfo: ClaimInfo + ) => [anchor.web3.PublicKey, anchor.web3.PublicKey] = getClaimPayers // This argument is only used for testing where we can't call the API ): Promise[]> { - const txs: VersionedTransaction[] = [] + const txs: TransactionWithPayers[] = [] try { for (const claim of claims) { - txs.push( - await this.generateClaimTransaction( + const [funder, treasury] = getPayersForClaim(claim.claimInfo) + + txs.push({ + tx: await this.generateClaimTransaction( + funder, + treasury, claim.claimInfo, claim.proofOfInclusion, claim.signedMessage - ) - ) + ), + payers: [funder, treasury], + }) } } catch (e) { + console.error(e) throw new Error(ERROR_CRAFTING_TX) } - let txsSignedOnce + let txsSignedOnce: VersionedTransaction[] + try { txsSignedOnce = await ( this.tokenDispenserProgram.provider as anchor.AnchorProvider - ).wallet.signAllTransactions(txs) + ).wallet.signAllTransactions(txs.map((tx) => tx.tx)) } catch (e) { + console.error(e) throw new Error(ERROR_SIGNING_TX) } + const txsSignedOnceWithPayers: TransactionWithPayers[] = txsSignedOnce.map( + (tx, index) => { + return { + tx: tx, + payers: txs[index].payers, + } + } + ) + let txsSignedTwice try { - txsSignedTwice = await fetchFundTransactionFunction(txsSignedOnce) + txsSignedTwice = await fetchFundTransactionFunction( + txsSignedOnceWithPayers + ) } catch (e) { + console.error(e) throw new Error(ERROR_FUNDING_TX) } @@ -290,6 +316,8 @@ export class TokenDispenserProvider { } public async generateClaimTransaction( + funder: PublicKey, + treasury: PublicKey, claimInfo: ClaimInfo, proofOfInclusion: Uint8Array[], signedMessage: SignedMessage | undefined @@ -320,12 +348,12 @@ export class TokenDispenserProvider { const claim_ix = await this.tokenDispenserProgram.methods .claim(claimCert) .accounts({ - funder: (await this.getConfig()).funder, + funder, claimant: this.claimant, claimantFund: await this.getClaimantFundAddress(), config: this.getConfigPda()[0], mint: (await this.getConfig()).mint, - treasury: (await this.getConfig()).treasury, + treasury, tokenProgram: TOKEN_PROGRAM_ID, systemProgram: anchor.web3.SystemProgram.programId, sysvarInstruction: anchor.web3.SYSVAR_INSTRUCTIONS_PUBKEY, @@ -348,7 +376,7 @@ export class TokenDispenserProvider { const claimTx = new VersionedTransaction( new TransactionMessage({ instructions: ixs, - payerKey: (await this.getConfig()).funder, + payerKey: funder, recentBlockhash: (await this.connection.getLatestBlockhash()).blockhash, }).compileToV0Message([lookupTableAccount!]) ) @@ -457,6 +485,7 @@ export class TokenDispenserProvider { ) } } + public async getClaimantFundAddress(): Promise { const config = await this.getConfig() const associatedTokenAccount = diff --git a/frontend/claim_sdk/testWallets.ts b/frontend/claim_sdk/testWallets.ts index c7f264b4..e91ef6ac 100644 --- a/frontend/claim_sdk/testWallets.ts +++ b/frontend/claim_sdk/testWallets.ts @@ -1,6 +1,6 @@ import path from 'path' import dotenv from 'dotenv' -import { Ecosystem } from './claim' +import { ClaimInfo, Ecosystem } from './claim' import { SignedMessage, cosmwasmBuildSignedMessage, @@ -25,6 +25,7 @@ import { getInjectiveAddress } from '../utils/getInjectiveAddress' import { algorandGetFullMessage } from './ecosystems/algorand' import { getAlgorandAddress } from '../utils/getAlgorandAddress' import nacl from 'tweetnacl' +import { inspect } from 'util' dotenv.config() // Load environment variables from .env file @@ -50,18 +51,40 @@ export function loadAnchorWallet(): NodeWallet { return new NodeWallet(keypair) } -export function loadFunderWallet(): NodeWallet { - const keypair = Keypair.fromSecretKey( - new Uint8Array( - JSON.parse( - fs.readFileSync( - path.resolve(KEY_DIR, 'funder_private_key.json'), - 'utf-8' +export function loadFunderWallets(): Record { + const result: Record = {} + let keypair: Keypair + if (process.env.FUNDER_KEYPAIR) { + keypair = Keypair.fromSecretKey( + Uint8Array.from(JSON.parse(process.env.FUNDER_KEYPAIR)) + ) + } else { + keypair = Keypair.fromSecretKey( + new Uint8Array( + JSON.parse( + fs.readFileSync( + path.resolve(KEY_DIR, 'funder_private_key.json'), + 'utf-8' + ) ) ) ) - ) - return new NodeWallet(keypair) + } + + result[keypair.publicKey.toBase58()] = new NodeWallet(keypair) + + // console.log('Funder wallets:', inspect(result, false, null, true)); + + return result +} + +export function getTestClaimPayers(treasury: PublicKey) { + return function (claimInfo: ClaimInfo): [PublicKey, PublicKey] { + const funder = Keypair.fromSecretKey( + Object.entries(loadFunderWallets())[0][1].payer.secretKey + ) + return [funder.publicKey, treasury] + } } export async function loadTestWallets(): Promise< diff --git a/frontend/claim_sdk/treasury.ts b/frontend/claim_sdk/treasury.ts new file mode 100644 index 00000000..cec841d4 --- /dev/null +++ b/frontend/claim_sdk/treasury.ts @@ -0,0 +1,32 @@ +import { ClaimInfo } from './claim' + +import { PublicKey } from '@solana/web3.js' + +export const treasuries = [ + new PublicKey('waTh9vNmRz8hHxQv1zW81ExKQ7fwaa1TR6tQT5fTkjg'), + new PublicKey('waTirsbdRyyxm8DFxH9Z9P5Pyrj74jJ7E74zqhmGX1k'), + new PublicKey('wAtMcoqwHb7obEL2USNXPqxg1CmJDSjjjsNcEm9bzCZ'), + new PublicKey('Wats1sM7W4UvxUuQPevGxexgcaFiaXMXxActKUmcvHx'), + new PublicKey('waTtgLt1WVRgoWYNZh97AYAUqoU4nN98jVThPdYQVwj'), + new PublicKey('WaTxa5w4TjYHRdHwG2zaN9ynA1c9z4J9TswsBCmzy4N'), +] + +export const funders = [ + new PublicKey('wAf15NnY6VVVQXDSdhp79LndkHXSD9BmcUhh4bqSSGp'), + new PublicKey('WafepN7ToYGS4WjaqtMV8g2q3YV1GgcoUZ4nvK4LhD8'), + new PublicKey('wAfmKAiAgtfywPhfRdLQ7uMeS2RW3kN57kodaRabX6V'), + new PublicKey('WAfN8P3NdYeTnnvFPKYUiveyqZSZtBboxUyrMSAzQc1'), + new PublicKey('wafydZpGcTLk3FYEQ5Q4wwSKJXMy3EMTngxeVEXG45e'), + new PublicKey('WafzGQMEqwABhMdNHH86yDRqzZQvK5rELK5Nrto97Va'), +] + +export function getClaimPayers(claimInfo: ClaimInfo): [PublicKey, PublicKey] { + const buffer = claimInfo.toBuffer() + const toHex = buffer.toString('hex') + const toNumber = parseInt(toHex, 16) + const funderIndex = toNumber % funders.length + + const treasuryIndex = toNumber % treasuries.length + + return [funders[funderIndex], treasuries[treasuryIndex]] +} diff --git a/frontend/hooks/useTokenDispenserProvider.tsx b/frontend/hooks/useTokenDispenserProvider.tsx index a9297ff9..5f5c221d 100644 --- a/frontend/hooks/useTokenDispenserProvider.tsx +++ b/frontend/hooks/useTokenDispenserProvider.tsx @@ -2,6 +2,7 @@ import { TokenDispenserProvider as CTokenDispenserProvider } from 'claim_sdk/sol import { useMemo } from 'react' import { useAnchorWallet } from '@solana/wallet-adapter-react' import { web3 } from '@coral-xyz/anchor' +import { tokenDispenserProgramId } from '../utils/constants' // It will return undefined if no Solana wallet is connected. export function useTokenDispenserProvider() { @@ -11,7 +12,7 @@ export function useTokenDispenserProvider() { return new CTokenDispenserProvider( process.env.ENDPOINT!, anchorWallet, - new web3.PublicKey(process.env.PROGRAM_ID!) + new web3.PublicKey(tokenDispenserProgramId) ) }, [anchorWallet]) } diff --git a/frontend/integration/api.test.ts b/frontend/integration/api.test.ts index b49af9e4..d8204c7e 100644 --- a/frontend/integration/api.test.ts +++ b/frontend/integration/api.test.ts @@ -15,7 +15,7 @@ import { import dotenv from 'dotenv' import NodeWallet from '@coral-xyz/anchor/dist/cjs/nodewallet' import { ethers } from 'ethers' -import { loadFunderWallet } from '../claim_sdk/testWallets' +import { loadFunderWallets } from '../claim_sdk/testWallets' import { mockfetchFundTransaction } from './api' import { checkAllProgramsWhitelisted, @@ -26,18 +26,27 @@ import { checkV0, countTotalSignatures, } from '../utils/verifyTransaction' +import { treasuries } from '../claim_sdk/treasury' +import { tokenDispenserProgramId } from '../utils/constants' dotenv.config() -const PROGRAM_ID = new PublicKey(process.env.PROGRAM_ID!) +const tokenDispenserPublicKey = new PublicKey(tokenDispenserProgramId) const WHITELISTED_PROGRAMS: PublicKey[] = [ - PROGRAM_ID, + tokenDispenserPublicKey, Secp256k1Program.programId, Ed25519Program.programId, ComputeBudgetProgram.programId, ] const RANDOM_BLOCKHASH = 'HXq5QPm883r7834LWwDpcmEM8G8uQ9Hqm1xakCHGxprV' -const funderPubkey = loadFunderWallet().publicKey +const funderWallets = loadFunderWallets() +const funderPubkey = Object.entries(funderWallets)[0][1].publicKey + +function getTestPayers(): [PublicKey, PublicKey] { + const wallets = loadFunderWallets() + const walletsArray = Object.entries(wallets) + return [walletsArray[0][1].publicKey, treasuries[0]] +} function createTestTransactionFromInstructions( instructions: TransactionInstruction[] @@ -55,7 +64,7 @@ describe('test fund transaction api', () => { it('tests the api', async () => { const tokenDispenser = new Program( IDL as any, - PROGRAM_ID, + tokenDispenserPublicKey, new AnchorProvider( new Connection('http://localhost:8899'), new NodeWallet(new Keypair()), @@ -162,94 +171,154 @@ describe('test fund transaction api', () => { }).compileToLegacyMessage() ) - await mockfetchFundTransaction([transactionOK1]) + await mockfetchFundTransaction([ + { + tx: transactionOK1, + payers: getTestPayers(), + }, + ]) expect( - checkTransactions([transactionOK1], PROGRAM_ID, WHITELISTED_PROGRAMS) + checkTransactions( + [transactionOK1], + tokenDispenserPublicKey, + WHITELISTED_PROGRAMS + ) ).toBe(true) - await mockfetchFundTransaction([transactionOK2]) + await mockfetchFundTransaction([ + { + tx: transactionOK2, + payers: getTestPayers(), + }, + ]) expect( - checkTransactions([transactionOK2], PROGRAM_ID, WHITELISTED_PROGRAMS) + checkTransactions( + [transactionOK2], + tokenDispenserPublicKey, + WHITELISTED_PROGRAMS + ) ).toBe(true) await expect( - mockfetchFundTransaction([transactionTooManySigs]).catch((e) => e) + mockfetchFundTransaction([ + { + tx: transactionTooManySigs, + payers: getTestPayers(), + }, + ]).catch((e) => e) ).resolves.toThrow('Unauthorized transaction') expect( checkTransactions( [transactionTooManySigs], - PROGRAM_ID, + tokenDispenserPublicKey, WHITELISTED_PROGRAMS ) ).toBe(false) await expect( - mockfetchFundTransaction([transactionBadTransfer]).catch((e) => e) + mockfetchFundTransaction([ + { + tx: transactionBadTransfer, + payers: getTestPayers(), + }, + ]).catch((e) => e) ).resolves.toThrow('Unauthorized transaction') expect( checkTransactions( [transactionBadTransfer], - PROGRAM_ID, + tokenDispenserPublicKey, WHITELISTED_PROGRAMS ) ).toBe(false) await expect( - mockfetchFundTransaction([transactionBadNoTokenDispenser]).catch((e) => e) + mockfetchFundTransaction([ + { + tx: transactionBadNoTokenDispenser, + payers: getTestPayers(), + }, + ]).catch((e) => e) ).resolves.toThrow('Unauthorized transaction') expect( checkTransactions( [transactionBadNoTokenDispenser], - PROGRAM_ID, + tokenDispenserPublicKey, WHITELISTED_PROGRAMS ) ).toBe(false) await expect( - mockfetchFundTransaction([transactionBadComputeHeap]).catch((e) => e) + mockfetchFundTransaction([ + { tx: transactionBadComputeHeap, payers: getTestPayers() }, + ]).catch((e) => e) ).resolves.toThrow('Unauthorized transaction') expect( checkTransactions( [transactionBadComputeHeap], - PROGRAM_ID, + tokenDispenserPublicKey, WHITELISTED_PROGRAMS ) ).toBe(false) await expect( - mockfetchFundTransaction([transactionBadTransfer2]).catch((e) => e) + mockfetchFundTransaction([ + { + tx: transactionBadTransfer2, + payers: getTestPayers(), + }, + ]).catch((e) => e) ).resolves.toThrow('Unauthorized transaction') expect( checkTransactions( [transactionBadTransfer2], - PROGRAM_ID, + tokenDispenserPublicKey, WHITELISTED_PROGRAMS ) ).toBe(false) await expect( - mockfetchFundTransaction([transactionBadTransfer3]).catch((e) => e) + mockfetchFundTransaction([ + { + tx: transactionBadTransfer3, + payers: getTestPayers(), + }, + ]).catch((e) => e) ).resolves.toThrow('Unauthorized transaction') expect( checkTransactions( [transactionBadTransfer3], - PROGRAM_ID, + tokenDispenserPublicKey, WHITELISTED_PROGRAMS ) ).toBe(false) await expect( - mockfetchFundTransaction([transactionLegacy]).catch((e) => e) + mockfetchFundTransaction([ + { + tx: transactionLegacy, + payers: getTestPayers(), + }, + ]).catch((e) => e) ).resolves.toThrow('Unauthorized transaction') expect( - checkTransactions([transactionLegacy], PROGRAM_ID, WHITELISTED_PROGRAMS) + checkTransactions( + [transactionLegacy], + tokenDispenserPublicKey, + WHITELISTED_PROGRAMS + ) ).toBe(false) // More granular tests expect( - checkTransaction(transactionOK1, PROGRAM_ID, WHITELISTED_PROGRAMS) + checkTransaction( + transactionOK1, + tokenDispenserPublicKey, + WHITELISTED_PROGRAMS + ) ).toBe(true) - expect(checkProgramAppears(transactionOK1, PROGRAM_ID)).toBe(true) + expect(checkProgramAppears(transactionOK1, tokenDispenserPublicKey)).toBe( + true + ) expect( checkAllProgramsWhitelisted(transactionOK1, WHITELISTED_PROGRAMS) ).toBe(true) @@ -260,9 +329,15 @@ describe('test fund transaction api', () => { expect(countTotalSignatures(transactionOK1)).toBe(2) expect( - checkTransaction(transactionOK2, PROGRAM_ID, WHITELISTED_PROGRAMS) + checkTransaction( + transactionOK2, + tokenDispenserPublicKey, + WHITELISTED_PROGRAMS + ) ).toBe(true) - expect(checkProgramAppears(transactionOK2, PROGRAM_ID)).toBe(true) + expect(checkProgramAppears(transactionOK2, tokenDispenserPublicKey)).toBe( + true + ) expect( checkAllProgramsWhitelisted(transactionOK2, WHITELISTED_PROGRAMS) ).toBe(true) @@ -273,9 +348,15 @@ describe('test fund transaction api', () => { expect(countTotalSignatures(transactionOK2)).toBe(3) expect( - checkTransaction(transactionTooManySigs, PROGRAM_ID, WHITELISTED_PROGRAMS) + checkTransaction( + transactionTooManySigs, + tokenDispenserPublicKey, + WHITELISTED_PROGRAMS + ) ).toBe(false) - expect(checkProgramAppears(transactionTooManySigs, PROGRAM_ID)).toBe(true) + expect( + checkProgramAppears(transactionTooManySigs, tokenDispenserPublicKey) + ).toBe(true) expect( checkAllProgramsWhitelisted(transactionTooManySigs, WHITELISTED_PROGRAMS) ).toBe(true) @@ -288,9 +369,15 @@ describe('test fund transaction api', () => { expect(countTotalSignatures(transactionTooManySigs)).toBe(4) expect( - checkTransaction(transactionBadTransfer, PROGRAM_ID, WHITELISTED_PROGRAMS) + checkTransaction( + transactionBadTransfer, + tokenDispenserPublicKey, + WHITELISTED_PROGRAMS + ) + ).toBe(false) + expect( + checkProgramAppears(transactionBadTransfer, tokenDispenserPublicKey) ).toBe(false) - expect(checkProgramAppears(transactionBadTransfer, PROGRAM_ID)).toBe(false) expect( checkAllProgramsWhitelisted(transactionBadTransfer, WHITELISTED_PROGRAMS) ).toBe(false) @@ -305,12 +392,15 @@ describe('test fund transaction api', () => { expect( checkTransaction( transactionBadNoTokenDispenser, - PROGRAM_ID, + tokenDispenserPublicKey, WHITELISTED_PROGRAMS ) ).toBe(false) expect( - checkProgramAppears(transactionBadNoTokenDispenser, PROGRAM_ID) + checkProgramAppears( + transactionBadNoTokenDispenser, + tokenDispenserPublicKey + ) ).toBe(false) expect( checkAllProgramsWhitelisted( @@ -329,13 +419,13 @@ describe('test fund transaction api', () => { expect( checkTransaction( transactionBadComputeHeap, - PROGRAM_ID, + tokenDispenserPublicKey, WHITELISTED_PROGRAMS ) ).toBe(false) - expect(checkProgramAppears(transactionBadComputeHeap, PROGRAM_ID)).toBe( - true - ) + expect( + checkProgramAppears(transactionBadComputeHeap, tokenDispenserPublicKey) + ).toBe(true) expect( checkAllProgramsWhitelisted( transactionBadComputeHeap, @@ -353,11 +443,13 @@ describe('test fund transaction api', () => { expect( checkTransaction( transactionBadTransfer2, - PROGRAM_ID, + tokenDispenserPublicKey, WHITELISTED_PROGRAMS ) ).toBe(false) - expect(checkProgramAppears(transactionBadTransfer2, PROGRAM_ID)).toBe(true) + expect( + checkProgramAppears(transactionBadTransfer2, tokenDispenserPublicKey) + ).toBe(true) expect( checkAllProgramsWhitelisted(transactionBadTransfer2, WHITELISTED_PROGRAMS) ).toBe(false) @@ -372,11 +464,13 @@ describe('test fund transaction api', () => { expect( checkTransaction( transactionBadTransfer3, - PROGRAM_ID, + tokenDispenserPublicKey, WHITELISTED_PROGRAMS ) ).toBe(false) - expect(checkProgramAppears(transactionBadTransfer3, PROGRAM_ID)).toBe(true) + expect( + checkProgramAppears(transactionBadTransfer3, tokenDispenserPublicKey) + ).toBe(true) expect( checkAllProgramsWhitelisted(transactionBadTransfer3, WHITELISTED_PROGRAMS) ).toBe(false) @@ -389,9 +483,15 @@ describe('test fund transaction api', () => { expect(countTotalSignatures(transactionBadTransfer3)).toBe(3) expect( - checkTransaction(transactionLegacy, PROGRAM_ID, WHITELISTED_PROGRAMS) + checkTransaction( + transactionLegacy, + tokenDispenserPublicKey, + WHITELISTED_PROGRAMS + ) ).toBe(false) - expect(checkProgramAppears(transactionLegacy, PROGRAM_ID)).toBe(true) + expect( + checkProgramAppears(transactionLegacy, tokenDispenserPublicKey) + ).toBe(true) expect( checkAllProgramsWhitelisted(transactionLegacy, WHITELISTED_PROGRAMS) ).toBe(true) @@ -402,40 +502,67 @@ describe('test fund transaction api', () => { expect(countTotalSignatures(transactionLegacy)).toBe(2) // Grouped transactions - await mockfetchFundTransaction([transactionOK1, transactionOK2]) + await mockfetchFundTransaction([ + { + tx: transactionOK1, + payers: getTestPayers(), + }, + { + tx: transactionOK2, + payers: getTestPayers(), + }, + ]) expect( checkTransactions( [transactionOK1, transactionOK2], - PROGRAM_ID, + tokenDispenserPublicKey, WHITELISTED_PROGRAMS ) ).toBe(true) await expect( mockfetchFundTransaction([ - transactionOK1, - transactionBadTransfer3, - transactionOK2, + { + tx: transactionOK1, + payers: getTestPayers(), + }, + { + tx: transactionBadTransfer3, + payers: getTestPayers(), + }, + { + tx: transactionOK2, + payers: getTestPayers(), + }, ]).catch((e) => e) ).resolves.toThrow('Unauthorized transaction') expect( checkTransactions( [transactionOK1, transactionBadTransfer3, transactionOK2], - PROGRAM_ID, + tokenDispenserPublicKey, WHITELISTED_PROGRAMS ) ).toBe(false) await expect( mockfetchFundTransaction([ - transactionOK1, - transactionOK2, - transactionBadComputeHeap, + { + tx: transactionOK1, + payers: getTestPayers(), + }, + { + tx: transactionOK2, + payers: getTestPayers(), + }, + { + tx: transactionBadComputeHeap, + payers: getTestPayers(), + }, ]).catch((e) => e) ).resolves.toThrow('Unauthorized transaction') expect( checkTransactions( [transactionOK1, transactionOK2, transactionBadComputeHeap], - PROGRAM_ID, + tokenDispenserPublicKey, WHITELISTED_PROGRAMS ) ).toBe(false) diff --git a/frontend/integration/api.ts b/frontend/integration/api.ts index 19dcb9c6..f812335a 100644 --- a/frontend/integration/api.ts +++ b/frontend/integration/api.ts @@ -1,40 +1,34 @@ -import NodeWallet from '@coral-xyz/anchor/dist/cjs/nodewallet' import { ComputeBudgetProgram, Ed25519Program, - Keypair, PublicKey, Secp256k1Program, VersionedTransaction, } from '@solana/web3.js' import { NextApiRequest, NextApiResponse } from 'next' import { + TransactionWithPayers, getFundTransactionRoute, handleAmountAndProofResponse, handleFundTransaction, } from '../utils/api' import { ClaimInfo, Ecosystem } from '../claim_sdk/claim' -import { loadFunderWallet } from '../claim_sdk/testWallets' +import { loadFunderWallets } from '../claim_sdk/testWallets' import { checkTransactions } from '../utils/verifyTransaction' -import fs from 'fs' -import path from 'path' import { getInMemoryDb } from './utils' +import { tokenDispenserProgramId } from '../utils/constants' -//import handlerAmountAndProof from '../pages/api/grant/v1/amount_and_proof' -//import handlerFundTransaction from '../pages/api/grant/v1/fund_transaction' +export type TransactionWithFunder = { + transaction: VersionedTransaction + funder: string +} -const wallet = process.env.FUNDER_KEYPAIR - ? new NodeWallet( - Keypair.fromSecretKey( - Uint8Array.from(JSON.parse(process.env.FUNDER_KEYPAIR)) - ) - ) - : loadFunderWallet() +const wallets = loadFunderWallets() -const PROGRAM_ID = new PublicKey(process.env.PROGRAM_ID!) +const tokenDispenserPublicKey = new PublicKey(tokenDispenserProgramId) const WHITELISTED_PROGRAMS: PublicKey[] = [ - PROGRAM_ID, + tokenDispenserPublicKey, Secp256k1Program.programId, Ed25519Program.programId, ComputeBudgetProgram.programId, @@ -92,7 +86,7 @@ export default async function handlerFundTransaction( } const data = req.body - let transactions: VersionedTransaction[] = [] + let transactions: TransactionWithFunder[] = [] let signedTransactions: VersionedTransaction[] = [] if (data.length >= 10) { @@ -103,18 +97,40 @@ export default async function handlerFundTransaction( try { transactions = data.map((serializedTx: any) => { - return VersionedTransaction.deserialize(Buffer.from(serializedTx)) + return { + transaction: VersionedTransaction.deserialize( + Buffer.from(serializedTx.tx) + ), + funder: serializedTx.funder, + } }) - } catch { + } catch (e) { + console.error(e) return res.status(400).json({ error: 'Failed to deserialize transactions', }) } - if (checkTransactions(transactions, PROGRAM_ID, WHITELISTED_PROGRAMS)) { + if ( + checkTransactions( + transactions.map((tx) => tx.transaction), + tokenDispenserPublicKey, + WHITELISTED_PROGRAMS + ) + ) { try { - signedTransactions = await wallet.signAllTransactions(transactions) - } catch { + for (const txWithFunder of transactions) { + const wallet = wallets[txWithFunder.funder] + if (!wallet) { + return res.status(403).json({ error: 'Unauthorized funder' }) + } + + signedTransactions.push( + await wallet.signTransaction(txWithFunder.transaction) + ) + } + } catch (e) { + console.error('Failed to sign transactions', e) return res.status(400).json({ error: 'Failed to sign transactions, make sure the transactions have the right funder', @@ -145,7 +161,7 @@ export class NextApiResponseMock { } } export async function mockfetchFundTransaction( - transactions: VersionedTransaction[] + transactions: TransactionWithPayers[] ): Promise { const req: NextApiRequest = { url: getFundTransactionRoute(), @@ -153,7 +169,12 @@ export async function mockfetchFundTransaction( headers: { 'Content-Type': 'application/json', }, - body: transactions.map((tx) => Buffer.from(tx.serialize())), + body: transactions.map((txWitPayers) => { + return { + tx: Buffer.from(txWitPayers.tx.serialize()), + funder: txWitPayers.payers[0].toBase58(), + } + }), } as unknown as NextApiRequest const res = new NextApiResponseMock() await handlerFundTransaction(req, res as unknown as NextApiResponse) diff --git a/frontend/integration/integrationTest.test.ts b/frontend/integration/integrationTest.test.ts index a21979b4..68bd9c1a 100644 --- a/frontend/integration/integrationTest.test.ts +++ b/frontend/integration/integrationTest.test.ts @@ -1,7 +1,8 @@ import * as anchor from '@coral-xyz/anchor' import { expect } from '@jest/globals' -import { Ecosystem } from '../claim_sdk/claim' +import { SignedMessage } from '../claim_sdk/ecosystems/signatures' +import { Ecosystem, ClaimInfo } from '../claim_sdk/claim' import { Token, TOKEN_PROGRAM_ID } from '@solana/spl-token' import { PublicKey, @@ -14,8 +15,9 @@ import { TokenDispenserEventSubscriber } from '../claim_sdk/eventSubscriber' import { DiscordTestWallet, TestWallet, + getTestClaimPayers, loadAnchorWallet, - loadFunderWallet, + loadFunderWallets, } from '../claim_sdk/testWallets' import { loadTestWallets } from '../claim_sdk/testWallets' import { mockFetchAmountAndProof, mockfetchFundTransaction } from './api' @@ -70,10 +72,10 @@ describe('integration test', () => { describe('token dispenser e2e', () => { const wallet = loadAnchorWallet() - const funderWallet = loadFunderWallet() + const funderWallet = Object.entries(loadFunderWallets())[0][1] const endpoint = 'http://127.0.0.1:8899' const tokenDispenserPid = new PublicKey( - 'WabZqXyytFA2XeXswf9DdQkQuSZuRiEgKdDmq7c5Mnp' + 'WapFw9mSyHh8trDDRy7AamUn1V7QiGaVvtouj5AucQA' ) const confirmOpts: anchor.web3.ConfirmOptions = { @@ -108,6 +110,17 @@ describe('integration test', () => { let mint: Token let treasury: PublicKey let expectedTreasuryBalance = new anchor.BN(1000000000) + const makeClaim = ( + claimInfo: ClaimInfo, + proofOfInclusion: Uint8Array[], + signedMessage?: SignedMessage + ) => ({ + funder: funderWallet.publicKey, + treasury, + claimInfo, + proofOfInclusion, + signedMessage, + }) beforeAll(async () => { const mintAndTreasury = await deployerTokenDispenserProvider.setupMintAndTreasury() @@ -120,9 +133,9 @@ describe('integration test', () => { await deployerTokenDispenserProvider.initialize( root, mint.publicKey, - treasury, dispenserGuard, - funderWallet.publicKey, + [treasury], + [funderWallet.publicKey], maxAmount ) @@ -131,7 +144,6 @@ describe('integration test', () => { expect(configAccount.bump).toEqual(configBump) expect(configAccount.merkleRoot).toEqual(Array.from(root)) expect(configAccount.mint).toEqual(mint.publicKey) - expect(configAccount.treasury).toEqual(treasury) expect(configAccount.dispenserGuard).toEqual(dispenserGuard) const lookupTableAddress = configAccount.addressLookupTable const lookupTableResp = @@ -176,14 +188,9 @@ describe('integration test', () => { await Promise.all( await tokenDispenserProvider.submitClaims( - [ - { - claimInfo, - proofOfInclusion, - signedMessage, - }, - ], - mockfetchFundTransaction + [makeClaim(claimInfo, proofOfInclusion, signedMessage)], + mockfetchFundTransaction, + getTestClaimPayers(treasury) ) ) @@ -238,14 +245,9 @@ describe('integration test', () => { await Promise.all( await tokenDispenserProvider.submitClaims( - [ - { - claimInfo, - proofOfInclusion, - signedMessage, - }, - ], - mockfetchFundTransaction + [makeClaim(claimInfo, proofOfInclusion, signedMessage)], + mockfetchFundTransaction, + getTestClaimPayers(treasury) ) ) @@ -297,13 +299,13 @@ describe('integration test', () => { ecosystem as Ecosystem, wallet.address() ))! - return { + return makeClaim( claimInfo, proofOfInclusion, - signedMessage: await wallet.signMessage( + await wallet.signMessage( tokenDispenserProvider.generateAuthorizationPayload() - ), - } + ) + ) }) ) @@ -322,7 +324,8 @@ describe('integration test', () => { await Promise.all( await tokenDispenserProvider.submitClaims( claims, - mockfetchFundTransaction + mockfetchFundTransaction, + getTestClaimPayers(treasury) ) ) @@ -362,14 +365,9 @@ describe('integration test', () => { await Promise.all( await tokenDispenserProvider.submitClaims( - [ - { - claimInfo, - proofOfInclusion, - signedMessage, - }, - ], - mockfetchFundTransaction + [makeClaim(claimInfo, proofOfInclusion, signedMessage)], + mockfetchFundTransaction, + getTestClaimPayers(treasury) ) ) @@ -405,14 +403,9 @@ describe('integration test', () => { await Promise.all( await tokenDispenserProvider.submitClaims( - [ - { - claimInfo, - proofOfInclusion, - signedMessage, - }, - ], - mockfetchFundTransaction + [makeClaim(claimInfo, proofOfInclusion, signedMessage)], + mockfetchFundTransaction, + getTestClaimPayers(treasury) ) ) @@ -445,14 +438,9 @@ describe('integration test', () => { await Promise.all( await tokenDispenserProvider.submitClaims( - [ - { - claimInfo, - proofOfInclusion, - signedMessage: undefined, - }, - ], - mockfetchFundTransaction + [makeClaim(claimInfo, proofOfInclusion, undefined)], + mockfetchFundTransaction, + getTestClaimPayers(treasury) ) ) @@ -486,14 +474,9 @@ describe('integration test', () => { await Promise.all( await tokenDispenserProvider.submitClaims( - [ - { - claimInfo, - proofOfInclusion, - signedMessage, - }, - ], - mockfetchFundTransaction + [makeClaim(claimInfo, proofOfInclusion, signedMessage)], + mockfetchFundTransaction, + getTestClaimPayers(treasury) ) ) @@ -534,14 +517,9 @@ describe('integration test', () => { const res = await Promise.all( await tokenDispenserProvider.submitClaims( - [ - { - claimInfo, - proofOfInclusion, - signedMessage, - }, - ], - mockfetchFundTransaction + [makeClaim(claimInfo, proofOfInclusion, signedMessage)], + mockfetchFundTransaction, + getTestClaimPayers(treasury) ) ) expect(JSON.stringify(res[0]).includes('InstructionError')).toBeTruthy() diff --git a/frontend/next.config.js b/frontend/next.config.js index 402a3a3a..4980c0f0 100644 --- a/frontend/next.config.js +++ b/frontend/next.config.js @@ -22,7 +22,6 @@ module.exports = withBundleAnalyzer({ env: { ENDPOINT: process.env.ENDPOINT, CLUSTER: process.env.CLUSTER, - PROGRAM_ID: process.env.PROGRAM_ID, }, webpack: (config, { isServer }) => { if (!isServer) { diff --git a/frontend/scripts/datadog.ts b/frontend/scripts/datadog.ts index 63b6c51d..31e109d8 100644 --- a/frontend/scripts/datadog.ts +++ b/frontend/scripts/datadog.ts @@ -20,9 +20,9 @@ import { } from '@datadog/datadog-api-client/dist/packages/datadog-api-client-v1/models/EventAlertType' import { envOrErr } from '../claim_sdk' import { BN } from '@coral-xyz/anchor' +import { tokenDispenserProgramId } from '../utils/constants' const ENDPOINT = envOrErr('ENDPOINT') -const PROGRAM_ID = envOrErr('PROGRAM_ID') const CLUSTER = envOrErr('CLUSTER') const TIME_WINDOW_SECS = Number.parseInt(envOrErr('TIME_WINDOW_SECS'), 10) const CHUNK_SIZE = Number.parseInt(envOrErr('CHUNK_SIZE'), 10) @@ -41,7 +41,7 @@ const MAX_AMOUNT_PER_ECOSYSTEM = new Map([ async function main() { const tokenDispenserEventSubscriber = new TokenDispenserEventSubscriber( ENDPOINT, - new anchor.web3.PublicKey(PROGRAM_ID), + new anchor.web3.PublicKey(tokenDispenserProgramId), TIME_WINDOW_SECS, CHUNK_SIZE, { diff --git a/frontend/sections/SignAndClaim.tsx b/frontend/sections/SignAndClaim.tsx index 6d54112b..dbc051d0 100644 --- a/frontend/sections/SignAndClaim.tsx +++ b/frontend/sections/SignAndClaim.tsx @@ -104,7 +104,11 @@ export const SignAndClaim = ({ onBack, onProceed }: SignAndClaimProps) => { let totalCoinsClaimed = new BN(0) let broadcastPromises try { - broadcastPromises = await tokenDispenser?.submitClaims(claims) + broadcastPromises = await tokenDispenser?.submitClaims( + claims.map((claim) => ({ + ...claim, + })) + ) } catch (e) { const err = e as Error let message: string diff --git a/frontend/utils/api.ts b/frontend/utils/api.ts index 633ae4d7..cf8a40ec 100644 --- a/frontend/utils/api.ts +++ b/frontend/utils/api.ts @@ -4,6 +4,7 @@ import { HASH_SIZE } from '../claim_sdk/merkleTree' import { PublicKey, VersionedTransaction } from '@solana/web3.js' import { SignedMessage } from '../claim_sdk/ecosystems/signatures' import { ECOSYSTEM_IDS } from './constants' +import { inspect } from 'util' const MERKLE_PROOFS = process.env.NEXT_PUBLIC_MERKLE_PROOFS const BACKEND_API = process.env.NEXT_PUBLIC_BACKEND_API @@ -142,15 +143,27 @@ export function handleFundTransaction( } } +export type TransactionWithPayers = { + tx: VersionedTransaction + payers: [PublicKey, PublicKey] +} + export async function fetchFundTransaction( - transactions: VersionedTransaction[] + transactions: TransactionWithPayers[] ): Promise { const response = await fetch(getFundTransactionRoute(), { method: 'POST', headers: { 'Content-Type': 'application/json', }, - body: JSON.stringify(transactions.map((tx) => Buffer.from(tx.serialize()))), + body: JSON.stringify( + transactions.map((txWithPayers) => { + return { + tx: Buffer.from(txWithPayers.tx.serialize()), + funder: txWithPayers.payers[0].toBase58(), + } + }) + ), }) return handleFundTransaction(response.status, await response.json()) diff --git a/frontend/utils/constants.ts b/frontend/utils/constants.ts index 0c19b39b..936e9207 100644 --- a/frontend/utils/constants.ts +++ b/frontend/utils/constants.ts @@ -39,3 +39,6 @@ export const EVM_CHAINS = [ ] as const export type EvmChains = typeof EVM_CHAINS[number] + +export const tokenDispenserProgramId = + 'WapFw9mSyHh8trDDRy7AamUn1V7QiGaVvtouj5AucQA' diff --git a/frontend/utils/isClaimAlreadySubmitted.ts b/frontend/utils/isClaimAlreadySubmitted.ts index 3ca234de..1331fcf0 100644 --- a/frontend/utils/isClaimAlreadySubmitted.ts +++ b/frontend/utils/isClaimAlreadySubmitted.ts @@ -3,13 +3,14 @@ import NodeWallet from '@coral-xyz/anchor/dist/cjs/nodewallet' import { Keypair } from '@solana/web3.js' import { ClaimInfo } from 'claim_sdk/claim' import { TokenDispenserProvider } from 'claim_sdk/solana' +import { tokenDispenserProgramId } from './constants' // Tokendispenser with randomly generated keypair. Since we don't need a // specific one to check if claims were already submitted const tokenDispenser = new TokenDispenserProvider( process.env.ENDPOINT!, new NodeWallet(new Keypair()), - new web3.PublicKey(process.env.PROGRAM_ID!) + new web3.PublicKey(tokenDispenserProgramId) ) // isClaimAlreadySubmitted help us check if a claim has already been submitted or not. diff --git a/token-dispenser/Anchor.toml b/token-dispenser/Anchor.toml index 28747f14..922e13cf 100644 --- a/token-dispenser/Anchor.toml +++ b/token-dispenser/Anchor.toml @@ -14,13 +14,13 @@ cluster = "devnet" wallet = "../frontend/integration/keys/funder_private_key.json" [programs.localnet] -token_dispenser = "WabZqXyytFA2XeXswf9DdQkQuSZuRiEgKdDmq7c5Mnp" +token_dispenser = "WapFw9mSyHh8trDDRy7AamUn1V7QiGaVvtouj5AucQA" [programs.mainnet] -token_dispenser = "WabZqXyytFA2XeXswf9DdQkQuSZuRiEgKdDmq7c5Mnp" +token_dispenser = "WapFw9mSyHh8trDDRy7AamUn1V7QiGaVvtouj5AucQA" [programs.devnet] -token_dispenser = "WabZqXyytFA2XeXswf9DdQkQuSZuRiEgKdDmq7c5Mnp" +token_dispenser = "WapFw9mSyHh8trDDRy7AamUn1V7QiGaVvtouj5AucQA" [scripts] test = "cargo test-bpf" diff --git a/token-dispenser/package-lock.json b/token-dispenser/package-lock.json new file mode 100644 index 00000000..ac9da631 --- /dev/null +++ b/token-dispenser/package-lock.json @@ -0,0 +1,2815 @@ +{ + "name": "token-dispenser", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "devDependencies": { + "@coral-xyz/anchor": "0.29.0", + "@solana/spl-token": "^0.4.1", + "@solana/web3.js": "^1.91.1", + "@types/bn.js": "^5.1.0", + "@types/chai": "^4.3.0", + "@types/mocha": "^9.0.0", + "@wormhole-foundation/sdk-base": "^0.5.0-beta.9", + "@xlabs-xyz/ledger-signer-solana": "^0.0.1", + "chai": "^4.3.4", + "mocha": "^9.0.3", + "prettier": "^2.6.2", + "ts-mocha": "^10.0.0", + "typescript": "^4.3.5" + } + }, + "node_modules/@babel/runtime": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.1.tgz", + "integrity": "sha512-+BIznRzyqBf+2wCTxcKE3wDjfGeCoVE61KSHGpkzqrLi8qxqFwBeUFyId2cxkTmm55fzDGnm0+yCxaxygrLUnQ==", + "dev": true, + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@coral-xyz/anchor": { + "version": "0.29.0", + "dev": true, + "license": "(MIT OR Apache-2.0)", + "dependencies": { + "@coral-xyz/borsh": "^0.29.0", + "@noble/hashes": "^1.3.1", + "@solana/web3.js": "^1.68.0", + "bn.js": "^5.1.2", + "bs58": "^4.0.1", + "buffer-layout": "^1.2.2", + "camelcase": "^6.3.0", + "cross-fetch": "^3.1.5", + "crypto-hash": "^1.3.0", + "eventemitter3": "^4.0.7", + "pako": "^2.0.3", + "snake-case": "^3.0.4", + "superstruct": "^0.15.4", + "toml": "^3.0.0" + }, + "engines": { + "node": ">=11" + } + }, + "node_modules/@coral-xyz/anchor/node_modules/superstruct": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-0.15.5.tgz", + "integrity": "sha512-4AOeU+P5UuE/4nOUkmcQdW5y7i9ndt1cQd/3iUe+LTz3RxESf/W/5lg4B74HbDMMv8PHnPnGCQFH45kBcrQYoQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@coral-xyz/borsh": { + "version": "0.29.0", + "resolved": "https://registry.npmjs.org/@coral-xyz/borsh/-/borsh-0.29.0.tgz", + "integrity": "sha512-s7VFVa3a0oqpkuRloWVPdCK7hMbAMY270geZOGfCnaqexrP5dTIpbEHL33req6IYPPJ0hYa71cdvJ1h6V55/oQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bn.js": "^5.1.2", + "buffer-layout": "^1.2.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@solana/web3.js": "^1.68.0" + } + }, + "node_modules/@ledgerhq/devices": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@ledgerhq/devices/-/devices-8.2.2.tgz", + "integrity": "sha512-SKahGA4p0mZ3ovypOJ2wa5mUvUkArE3HBrwWKYf+cRs+t/Licp3OJfhj+DHIxP3AfyH2xR6CFFWECYHeKwGsDQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@ledgerhq/errors": "^6.16.3", + "@ledgerhq/logs": "^6.12.0", + "rxjs": "^7.8.1", + "semver": "^7.3.5" + } + }, + "node_modules/@ledgerhq/errors": { + "version": "6.16.3", + "resolved": "https://registry.npmjs.org/@ledgerhq/errors/-/errors-6.16.3.tgz", + "integrity": "sha512-3w7/SJVXOPa9mpzyll7VKoKnGwDD3BzWgN1Nom8byR40DiQvOKjHX+kKQausCedTHVNBn9euzPCNsftZ9+mxfw==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@ledgerhq/hw-app-solana": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/@ledgerhq/hw-app-solana/-/hw-app-solana-7.1.4.tgz", + "integrity": "sha512-xOrCPKzF6RnqD9eRyjltJkWQDS39/Wev3GxvD4sKYuhERdZ+W8Gg0/nxKK468qGNPwhiDaRj7inPKGSMNCADqQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@ledgerhq/errors": "^6.16.2", + "@ledgerhq/hw-transport": "^6.30.4", + "bip32-path": "^0.4.2" + } + }, + "node_modules/@ledgerhq/hw-transport": { + "version": "6.30.4", + "resolved": "https://registry.npmjs.org/@ledgerhq/hw-transport/-/hw-transport-6.30.4.tgz", + "integrity": "sha512-VBcVd7UG8HDrjWMoZI5rqBDz+PBxLHTIPZOGY/fdMoEUwaBbss0Z3MxuJanMyerlfaLqnBSVuL0blz7rOyagkw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@ledgerhq/devices": "^8.2.1", + "@ledgerhq/errors": "^6.16.2", + "@ledgerhq/logs": "^6.12.0", + "events": "^3.3.0" + } + }, + "node_modules/@ledgerhq/hw-transport-node-hid": { + "version": "6.28.4", + "resolved": "https://registry.npmjs.org/@ledgerhq/hw-transport-node-hid/-/hw-transport-node-hid-6.28.4.tgz", + "integrity": "sha512-f6yQvZe4cwg6ibRn1YE9wWTdvpyT7FBIxxYHAd4RKm0l5/WFZS2G8CwdNJQwlOr89iBgGvEswWYh8EhUxM5QYA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@ledgerhq/devices": "^8.2.1", + "@ledgerhq/errors": "^6.16.2", + "@ledgerhq/hw-transport": "^6.30.4", + "@ledgerhq/hw-transport-node-hid-noevents": "^6.29.4", + "@ledgerhq/logs": "^6.12.0", + "lodash": "^4.17.21", + "node-hid": "^2.1.2", + "usb": "2.9.0" + } + }, + "node_modules/@ledgerhq/hw-transport-node-hid-noevents": { + "version": "6.29.5", + "resolved": "https://registry.npmjs.org/@ledgerhq/hw-transport-node-hid-noevents/-/hw-transport-node-hid-noevents-6.29.5.tgz", + "integrity": "sha512-KzLJtH4gzt8AROQm2x9GSPrlqH+Mf7e/UlgQI3ldLcZFJQIaXZUCVjn4EyhMMTwggqjLvczEQNDwZ0zvEiXWuA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@ledgerhq/devices": "^8.2.2", + "@ledgerhq/errors": "^6.16.3", + "@ledgerhq/hw-transport": "^6.30.5", + "@ledgerhq/logs": "^6.12.0", + "node-hid": "^2.1.2" + } + }, + "node_modules/@ledgerhq/hw-transport-node-hid-noevents/node_modules/@ledgerhq/hw-transport": { + "version": "6.30.5", + "resolved": "https://registry.npmjs.org/@ledgerhq/hw-transport/-/hw-transport-6.30.5.tgz", + "integrity": "sha512-JMl//7BgPBvWxrWyMu82jj6JEYtsQyOyhYtonWNgtxn6KUZWht3gU4gxmLpeIRr+DiS7e50mW7m3GA+EudZmmA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@ledgerhq/devices": "^8.2.2", + "@ledgerhq/errors": "^6.16.3", + "@ledgerhq/logs": "^6.12.0", + "events": "^3.3.0" + } + }, + "node_modules/@ledgerhq/logs": { + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@ledgerhq/logs/-/logs-6.12.0.tgz", + "integrity": "sha512-ExDoj1QV5eC6TEbMdLUMMk9cfvNKhhv5gXol4SmULRVCx/3iyCPhJ74nsb3S0Vb+/f+XujBEj3vQn5+cwS0fNA==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@noble/curves": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.4.0.tgz", + "integrity": "sha512-p+4cb332SFCrReJkCYe8Xzm0OWi4Jji5jVdIZRL/PmacmDkFNw6MrrV+gGpiPxLHbV+zKFRywUWbaseT+tZRXg==", + "dev": true, + "dependencies": { + "@noble/hashes": "1.4.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/hashes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", + "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/base": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.6.tgz", + "integrity": "sha512-ok9AWwhcgYuGG3Zfhyqg+zwl+Wn5uE+dwC0NV/2qQkx4dABbb/bx96vWu8NSj+BNjjSjno+JRYRjle1jV08k3g==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@solana/buffer-layout": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@solana/buffer-layout/-/buffer-layout-4.0.1.tgz", + "integrity": "sha512-E1ImOIAD1tBZFRdjeM4/pzTiTApC0AOBGwyAMS4fwIodCWArzJ3DWdoh8cKxeFM2fElkxBh2Aqts1BPC373rHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer": "~6.0.3" + }, + "engines": { + "node": ">=5.10" + } + }, + "node_modules/@solana/buffer-layout-utils": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@solana/buffer-layout-utils/-/buffer-layout-utils-0.2.0.tgz", + "integrity": "sha512-szG4sxgJGktbuZYDg2FfNmkMi0DYQoVjN2h7ta1W1hPrwzarcFLBq9UpX1UjNXsNpT9dn+chgprtWGioUAr4/g==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@solana/buffer-layout": "^4.0.0", + "@solana/web3.js": "^1.32.0", + "bigint-buffer": "^1.1.5", + "bignumber.js": "^9.0.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@solana/codecs-core": { + "version": "2.0.0-experimental.8618508", + "resolved": "https://registry.npmjs.org/@solana/codecs-core/-/codecs-core-2.0.0-experimental.8618508.tgz", + "integrity": "sha512-JCz7mKjVKtfZxkuDtwMAUgA7YvJcA2BwpZaA1NOLcted4OMC4Prwa3DUe3f3181ixPYaRyptbF0Ikq2MbDkYEA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@solana/codecs-data-structures": { + "version": "2.0.0-experimental.8618508", + "resolved": "https://registry.npmjs.org/@solana/codecs-data-structures/-/codecs-data-structures-2.0.0-experimental.8618508.tgz", + "integrity": "sha512-sLpjL9sqzaDdkloBPV61Rht1tgaKq98BCtIKRuyscIrmVPu3wu0Bavk2n/QekmUzaTsj7K1pVSniM0YqCdnEBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@solana/codecs-core": "2.0.0-experimental.8618508", + "@solana/codecs-numbers": "2.0.0-experimental.8618508" + } + }, + "node_modules/@solana/codecs-numbers": { + "version": "2.0.0-experimental.8618508", + "resolved": "https://registry.npmjs.org/@solana/codecs-numbers/-/codecs-numbers-2.0.0-experimental.8618508.tgz", + "integrity": "sha512-EXQKfzFr3CkKKNzKSZPOOOzchXsFe90TVONWsSnVkonO9z+nGKALE0/L9uBmIFGgdzhhU9QQVFvxBMclIDJo2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@solana/codecs-core": "2.0.0-experimental.8618508" + } + }, + "node_modules/@solana/codecs-strings": { + "version": "2.0.0-experimental.8618508", + "resolved": "https://registry.npmjs.org/@solana/codecs-strings/-/codecs-strings-2.0.0-experimental.8618508.tgz", + "integrity": "sha512-b2yhinr1+oe+JDmnnsV0641KQqqDG8AQ16Z/x7GVWO+AWHMpRlHWVXOq8U1yhPMA4VXxl7i+D+C6ql0VGFp0GA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@solana/codecs-core": "2.0.0-experimental.8618508", + "@solana/codecs-numbers": "2.0.0-experimental.8618508" + }, + "peerDependencies": { + "fastestsmallesttextencoderdecoder": "^1.0.22" + } + }, + "node_modules/@solana/options": { + "version": "2.0.0-experimental.8618508", + "resolved": "https://registry.npmjs.org/@solana/options/-/options-2.0.0-experimental.8618508.tgz", + "integrity": "sha512-fy/nIRAMC3QHvnKi63KEd86Xr/zFBVxNW4nEpVEU2OT0gCEKwHY4Z55YHf7XujhyuM3PNpiBKg/YYw5QlRU4vg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@solana/codecs-core": "2.0.0-experimental.8618508", + "@solana/codecs-numbers": "2.0.0-experimental.8618508" + } + }, + "node_modules/@solana/spl-token": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@solana/spl-token/-/spl-token-0.4.1.tgz", + "integrity": "sha512-DEe15GI0l+XLHwtau/3GUwGQJ9YY/VWNE0k/QuXaaGKo4adMZLEAIQUktRc/S2sRqPjvUdR5anZGxQ9p5khWZw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@solana/buffer-layout": "^4.0.0", + "@solana/buffer-layout-utils": "^0.2.0", + "@solana/spl-token-metadata": "^0.1.2", + "buffer": "^6.0.3" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "@solana/web3.js": "^1.90.0" + } + }, + "node_modules/@solana/spl-token-metadata": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@solana/spl-token-metadata/-/spl-token-metadata-0.1.2.tgz", + "integrity": "sha512-hJYnAJNkDrtkE2Q41YZhCpeOGU/0JgRFXbtrtOuGGeKc3pkEUHB9DDoxZAxx+XRno13GozUleyBi0qypz4c3bw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@solana/codecs-core": "2.0.0-experimental.8618508", + "@solana/codecs-data-structures": "2.0.0-experimental.8618508", + "@solana/codecs-numbers": "2.0.0-experimental.8618508", + "@solana/codecs-strings": "2.0.0-experimental.8618508", + "@solana/options": "2.0.0-experimental.8618508", + "@solana/spl-type-length-value": "0.1.0" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "@solana/web3.js": "^1.87.6" + } + }, + "node_modules/@solana/spl-type-length-value": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@solana/spl-type-length-value/-/spl-type-length-value-0.1.0.tgz", + "integrity": "sha512-JBMGB0oR4lPttOZ5XiUGyvylwLQjt1CPJa6qQ5oM+MBCndfjz2TKKkw0eATlLLcYmq1jBVsNlJ2cD6ns2GR7lA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "buffer": "^6.0.3" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@solana/web3.js": { + "version": "1.91.2", + "resolved": "https://registry.npmjs.org/@solana/web3.js/-/web3.js-1.91.2.tgz", + "integrity": "sha512-WXPl5VXtfNKWM2RkGj7mvX6dKcZURDKe1lWBFAt/RqDBI9Rjr9hr7Y+U+yz2+TyViMmoinfJVlkS4gk2FPDG/g==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.23.4", + "@noble/curves": "^1.2.0", + "@noble/hashes": "^1.3.3", + "@solana/buffer-layout": "^4.0.1", + "agentkeepalive": "^4.5.0", + "bigint-buffer": "^1.1.5", + "bn.js": "^5.2.1", + "borsh": "^0.7.0", + "bs58": "^4.0.1", + "buffer": "6.0.3", + "fast-stable-stringify": "^1.0.0", + "jayson": "^4.1.0", + "node-fetch": "^2.7.0", + "rpc-websockets": "^7.5.1", + "superstruct": "^0.14.2" + } + }, + "node_modules/@types/bn.js": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.1.tgz", + "integrity": "sha512-qNrYbZqMx0uJAfKnKclPh+dTwK33KfLHYqtyODwd5HnXOjnkhc4qgn3BrK6RWyGZm5+sIFE7Q7Vz6QQtJB7w7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/chai": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.5.tgz", + "integrity": "sha512-mEo1sAde+UCE6b2hxn332f1g1E8WfYRu6p5SvTKr2ZKC1f7gFJXk4h5PyGP9Dt6gCaG8y8XhwnXWC6Iy2cmBng==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/@types/mocha": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.1.tgz", + "integrity": "sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "20.2.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.2.5.tgz", + "integrity": "sha512-JJulVEQXmiY9Px5axXHeYGLSjhkZEnD+MDPDGbCbIAbMslkKwmygtZFy1X6s/075Yo94sf8GuSlFfPzysQrWZQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/w3c-web-usb": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/@types/w3c-web-usb/-/w3c-web-usb-1.0.10.tgz", + "integrity": "sha512-CHgUI5kTc/QLMP8hODUHhge0D4vx+9UiAwIGiT0sTy/B2XpdX1U5rJt6JSISgr6ikRT7vxV9EVAFeYZqUnl1gQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/ws": { + "version": "7.4.7", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz", + "integrity": "sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@ungap/promise-all-settled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", + "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", + "dev": true, + "license": "ISC" + }, + "node_modules/@wormhole-foundation/sdk-base": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@wormhole-foundation/sdk-base/-/sdk-base-0.5.1.tgz", + "integrity": "sha512-6MRcfPA9//FXyO/vlAxH756EHd1qJ6aU/UV5T84GCUkdjYdRFqooaa/QU9RDqdEMxFgMRNGK+GyIeqv87uXMGA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@scure/base": "^1.1.3" + } + }, + "node_modules/@xlabs-xyz/ledger-signer-solana": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/@xlabs-xyz/ledger-signer-solana/-/ledger-signer-solana-0.0.1.tgz", + "integrity": "sha512-2h9BNc0UYzqbV+S0GDxvh3nV6OSpUOVcbBwQGP0ckl1TAKbwgSzJ+1VYt4xVFJWHLntvfoOpH+DV4LszGWOSNA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ledgerhq/hw-app-solana": "7.1.4", + "@ledgerhq/hw-transport": "6.30.4", + "@ledgerhq/hw-transport-node-hid": "6.28.4" + } + }, + "node_modules/agentkeepalive": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz", + "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==", + "dev": true, + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/base-x": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz", + "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/bigint-buffer": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/bigint-buffer/-/bigint-buffer-1.1.5.tgz", + "integrity": "sha512-trfYco6AoZ+rKhKnxA0hgX0HAbVP/s808/EuDSe2JDzUnCp/xAsli35Orvk67UrTEcwuxZqYZDmfA2RXJgxVvA==", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "bindings": "^1.3.0" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/bignumber.js": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz", + "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, + "node_modules/bip32-path": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/bip32-path/-/bip32-path-0.4.2.tgz", + "integrity": "sha512-ZBMCELjJfcNMkz5bDuJ1WrYvjlhEF5k6mQ8vUr4N7MbVRsXei7ZOg8VhhwMfNiW68NWmLkgkc6WvTickrLGprQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bl/node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/bn.js": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/borsh": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/borsh/-/borsh-0.7.0.tgz", + "integrity": "sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bn.js": "^5.2.0", + "bs58": "^4.0.0", + "text-encoding-utf-8": "^1.0.2" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true, + "license": "ISC" + }, + "node_modules/bs58": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", + "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "base-x": "^3.0.2" + } + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/buffer-layout": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/buffer-layout/-/buffer-layout-1.2.2.tgz", + "integrity": "sha512-kWSuLN694+KTk8SrYvCqwP2WcgQjoRCiF5b4QDvkkz8EmgD+aWAIceGFKMIAdmF/pH+vpgNV3d3kAKorcdAmWA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.5" + } + }, + "node_modules/bufferutil": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.7.tgz", + "integrity": "sha512-kukuqc39WOHtdxtw4UScxF/WVnMFVSQVKhtx3AjZJzhd0RGZZldcrfSEbVsWWe6KNH253574cq5F+wpv0G9pJw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/chai": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz", + "integrity": "sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^4.1.2", + "get-func-name": "^2.0.0", + "loupe": "^2.3.1", + "pathval": "^1.1.1", + "type-detect": "^4.0.5" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true, + "license": "ISC" + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-fetch": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.6.tgz", + "integrity": "sha512-riRvo06crlE8HiqOwIpQhxwdOk4fOeR7FVM/wXoxchFEqMNUjvbs3bfo4OTgMEMHzppd4DxFBDbyySj8Cv781g==", + "dev": true, + "license": "MIT", + "dependencies": { + "node-fetch": "^2.6.11" + } + }, + "node_modules/crypto-hash": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/crypto-hash/-/crypto-hash-1.3.0.tgz", + "integrity": "sha512-lyAZ0EMyjDkVvz8WOeVnuCPvKVBXcMv1l5SVqO1yC7PzTwrD/pPje/BIRbWhMoPe436U+Y2nD7f5bFx0kt+Sbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-eql": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", + "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/delay": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/delay/-/delay-5.0.0.tgz", + "integrity": "sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/detect-libc": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", + "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es6-promise": "^4.0.3" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true, + "license": "MIT" + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "dev": true, + "license": "(MIT OR WTFPL)", + "engines": { + "node": ">=6" + } + }, + "node_modules/eyes": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", + "integrity": "sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ==", + "dev": true, + "engines": { + "node": "> 0.1.90" + } + }, + "node_modules/fast-stable-stringify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fast-stable-stringify/-/fast-stable-stringify-1.0.0.tgz", + "integrity": "sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag==", + "dev": true, + "license": "MIT" + }, + "node_modules/fastestsmallesttextencoderdecoder": { + "version": "1.0.22", + "resolved": "https://registry.npmjs.org/fastestsmallesttextencoderdecoder/-/fastestsmallesttextencoderdecoder-1.0.22.tgz", + "integrity": "sha512-Pb8d48e+oIuY4MaM64Cd7OW1gt4nxCHs7/ddPPZ/Ic3sg8yVGM7O9wDvZ7us6ScaUupzM+pfBolwtYhN1IxBIw==", + "dev": true, + "peer": true + }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "license": "BSD-3-Clause", + "bin": { + "flat": "cli.js" + } + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true, + "license": "MIT" + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", + "dev": true, + "license": "MIT" + }, + "node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.x" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "license": "MIT", + "bin": { + "he": "bin/he" + } + }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "dev": true, + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "license": "ISC" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/isomorphic-ws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz", + "integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "ws": "*" + } + }, + "node_modules/jayson": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/jayson/-/jayson-4.1.0.tgz", + "integrity": "sha512-R6JlbyLN53Mjku329XoRT2zJAE6ZgOQ8f91ucYdMCD4nkGCF9kZSrcGXpHIU4jeKj58zUZke2p+cdQchU7Ly7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/connect": "^3.4.33", + "@types/node": "^12.12.54", + "@types/ws": "^7.4.4", + "commander": "^2.20.3", + "delay": "^5.0.0", + "es6-promisify": "^5.0.0", + "eyes": "^0.1.8", + "isomorphic-ws": "^4.0.1", + "json-stringify-safe": "^5.0.1", + "JSONStream": "^1.3.5", + "uuid": "^8.3.2", + "ws": "^7.4.5" + }, + "bin": { + "jayson": "bin/jayson.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jayson/node_modules/@types/node": { + "version": "12.20.55", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", + "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "dev": true, + "license": "ISC" + }, + "node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "dev": true, + "engines": [ + "node >= 0.2.0" + ], + "license": "MIT" + }, + "node_modules/JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "dev": true, + "license": "(MIT OR Apache-2.0)", + "dependencies": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + }, + "bin": { + "JSONStream": "bin.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true, + "license": "MIT" + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/loupe": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz", + "integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-func-name": "^2.0.0" + } + }, + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC" + }, + "node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimatch": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz", + "integrity": "sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "dev": true, + "license": "MIT" + }, + "node_modules/mocha": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.2.tgz", + "integrity": "sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ungap/promise-all-settled": "1.1.2", + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.3", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "4.2.1", + "ms": "2.1.3", + "nanoid": "3.3.1", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "which": "2.0.2", + "workerpool": "6.2.0", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" + } + }, + "node_modules/mocha/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", + "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==", + "dev": true, + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/napi-build-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", + "dev": true, + "license": "MIT" + }, + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, + "node_modules/node-abi": { + "version": "3.56.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.56.0.tgz", + "integrity": "sha512-fZjdhDOeRcaS+rcpve7XuwHBmktS1nS1gzgghwKUQQ8nTy2FdSDr6ZT8k6YhvlJeHmmQMYiT/IH9hfco5zeW2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-addon-api": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", + "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-gyp-build": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.0.tgz", + "integrity": "sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ==", + "dev": true, + "license": "MIT", + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/node-hid": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/node-hid/-/node-hid-2.2.0.tgz", + "integrity": "sha512-vj48zh9j555DZzUhMc8tk/qw6xPFrDyPBH1ST1Z/hWaA/juBJw7IuSxPeOgpzNFNU36mGYj+THioRMt1xOdm/g==", + "dev": true, + "hasInstallScript": true, + "license": "(MIT OR X11)", + "dependencies": { + "bindings": "^1.5.0", + "node-addon-api": "^3.0.2", + "prebuild-install": "^7.1.1" + }, + "bin": { + "hid-showdevices": "src/show-devices.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pako": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz", + "integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==", + "dev": true, + "license": "(MIT AND Zlib)" + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/prebuild-install": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.2.tgz", + "integrity": "sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^1.0.1", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "dev": true + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/rpc-websockets": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/rpc-websockets/-/rpc-websockets-7.5.1.tgz", + "integrity": "sha512-kGFkeTsmd37pHPMaHIgN1LVKXMi0JD782v4Ds9ZKtLlwdTKjn+CxM9A9/gLT2LaOuEcEFGL98h1QWQtlOIdW0w==", + "dev": true, + "license": "LGPL-3.0-only", + "dependencies": { + "@babel/runtime": "^7.17.2", + "eventemitter3": "^4.0.7", + "uuid": "^8.3.2", + "ws": "^8.5.0" + }, + "funding": { + "type": "paypal", + "url": "https://paypal.me/kozjak" + }, + "optionalDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + } + }, + "node_modules/rpc-websockets/node_modules/ws": { + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", + "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/snake-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", + "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==", + "dev": true, + "license": "MIT", + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/superstruct": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-0.14.2.tgz", + "integrity": "sha512-nPewA6m9mR3d6k7WkZ8N8zpTWfenFH3q9pA2PkuiZxINr9DKB2+40wEQf0ixn8VaGuJ78AB6iWOtStI+/4FKZQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "dev": true, + "license": "MIT", + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "license": "MIT", + "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" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/text-encoding-utf-8": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz", + "integrity": "sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg==", + "dev": true + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toml": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/toml/-/toml-3.0.0.tgz", + "integrity": "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true, + "license": "MIT" + }, + "node_modules/ts-mocha": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/ts-mocha/-/ts-mocha-10.0.0.tgz", + "integrity": "sha512-VRfgDO+iiuJFlNB18tzOfypJ21xn2xbuZyDvJvqpTbWgkAgD17ONGr8t+Tl8rcBtOBdjXp5e/Rk+d39f7XBHRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "ts-node": "7.0.1" + }, + "bin": { + "ts-mocha": "bin/ts-mocha" + }, + "engines": { + "node": ">= 6.X.X" + }, + "optionalDependencies": { + "tsconfig-paths": "^3.5.0" + }, + "peerDependencies": { + "mocha": "^3.X.X || ^4.X.X || ^5.X.X || ^6.X.X || ^7.X.X || ^8.X.X || ^9.X.X || ^10.X.X" + } + }, + "node_modules/ts-node": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-7.0.1.tgz", + "integrity": "sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "arrify": "^1.0.0", + "buffer-from": "^1.1.0", + "diff": "^3.1.0", + "make-error": "^1.1.1", + "minimist": "^1.2.0", + "mkdirp": "^0.5.1", + "source-map-support": "^0.5.6", + "yn": "^2.0.0" + }, + "bin": { + "ts-node": "dist/bin.js" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/ts-node/node_modules/diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/tsconfig-paths": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz", + "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tslib": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.2.tgz", + "integrity": "sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA==", + "dev": true, + "license": "0BSD" + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/usb": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/usb/-/usb-2.9.0.tgz", + "integrity": "sha512-G0I/fPgfHUzWH8xo2KkDxTTFruUWfppgSFJ+bQxz/kVY2x15EQ/XDB7dqD1G432G4gBG4jYQuF3U7j/orSs5nw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "@types/w3c-web-usb": "^1.0.6", + "node-addon-api": "^6.0.0", + "node-gyp-build": "^4.5.0" + }, + "engines": { + "node": ">=10.20.0 <11.x || >=12.17.0 <13.0 || >=14.0.0" + } + }, + "node_modules/usb/node_modules/node-addon-api": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", + "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==", + "dev": true, + "license": "MIT" + }, + "node_modules/utf-8-validate": { + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz", + "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/workerpool": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz", + "integrity": "sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz", + "integrity": "sha512-uTv8J/wiWTgUTg+9vLTi//leUl5vDQS6uii/emeTb2ssY7vl6QWf2fFbIIGjnhjvbdKlU0ed7QPgY1htTC86jQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/token-dispenser/package.json b/token-dispenser/package.json index 9c6e23d8..958d5b5e 100644 --- a/token-dispenser/package.json +++ b/token-dispenser/package.json @@ -4,12 +4,13 @@ "lint": "prettier */*.js \"*/**/*{.js,.ts}\" --check" }, "devDependencies": { - "@coral-xyz/anchor": "0.27.0", + "@coral-xyz/anchor": "0.29.0", "@solana/spl-token": "^0.4.1", "@types/bn.js": "^5.1.0", "@types/chai": "^4.3.0", "@types/mocha": "^9.0.0", "@wormhole-foundation/sdk-base": "^0.5.0-beta.9", + "@solana/web3.js": "^1.91.1", "@xlabs-xyz/ledger-signer-solana": "^0.0.1", "chai": "^4.3.4", "mocha": "^9.0.3", diff --git a/token-dispenser/programs/token-dispenser/src/ecosystems/cosmos.rs b/token-dispenser/programs/token-dispenser/src/ecosystems/cosmos.rs index 706a4590..b1bef00b 100644 --- a/token-dispenser/programs/token-dispenser/src/ecosystems/cosmos.rs +++ b/token-dispenser/programs/token-dispenser/src/ecosystems/cosmos.rs @@ -46,41 +46,41 @@ pub struct CosmosMessage { } impl CosmosMessage { - pub fn parse(data: &[u8], signer: &CosmosBech32Address) -> Result { - let sign_doc: CosmosStdSignDoc = serde_json::from_slice(data) - .map_err(|_| error!(ErrorCode::SignatureVerificationWrongPayloadMetadata))?; - - if !(sign_doc.account_number == "0" - && sign_doc.chain_id.is_empty() - && sign_doc.fee.amount.is_empty() - && sign_doc.fee.gas == "0" - && sign_doc.memo.is_empty() - && sign_doc.msgs.len() == 1 - && sign_doc.sequence == "0") - { - return err!(ErrorCode::SignatureVerificationWrongPayloadMetadata); - } - - if sign_doc.msgs[0].r#type != EXPECTED_COSMOS_MESSAGE_TYPE { - return err!(ErrorCode::SignatureVerificationWrongPayloadMetadata); - } - - if sign_doc.msgs[0].value.signer != signer.0 { - return err!(ErrorCode::SignatureVerificationWrongPayloadMetadata); - } - - Ok(CosmosMessage { - payload: base64_standard_engine - .decode(sign_doc.msgs[0].value.data.as_bytes()) - .map_err(|_| error!(ErrorCode::SignatureVerificationWrongPayloadMetadata))?, - signer: CosmosBech32Address(sign_doc.msgs[0].value.signer.clone()), - }) - } - - - pub fn get_payload(&self) -> &[u8] { - self.payload.as_slice() - } + // pub fn parse(data: &[u8], signer: &CosmosBech32Address) -> Result { + // let sign_doc: CosmosStdSignDoc = serde_json::from_slice(data) + // .map_err(|_| error!(ErrorCode::SignatureVerificationWrongPayloadMetadata))?; + + // if !(sign_doc.account_number == "0" + // && sign_doc.chain_id.is_empty() + // && sign_doc.fee.amount.is_empty() + // && sign_doc.fee.gas == "0" + // && sign_doc.memo.is_empty() + // && sign_doc.msgs.len() == 1 + // && sign_doc.sequence == "0") + // { + // return err!(ErrorCode::SignatureVerificationWrongPayloadMetadata); + // } + + // if sign_doc.msgs[0].r#type != EXPECTED_COSMOS_MESSAGE_TYPE { + // return err!(ErrorCode::SignatureVerificationWrongPayloadMetadata); + // } + + // if sign_doc.msgs[0].value.signer != signer.0 { + // return err!(ErrorCode::SignatureVerificationWrongPayloadMetadata); + // } + + // Ok(CosmosMessage { + // payload: base64_standard_engine + // .decode(sign_doc.msgs[0].value.data.as_bytes()) + // .map_err(|_| error!(ErrorCode::SignatureVerificationWrongPayloadMetadata))?, + // signer: CosmosBech32Address(sign_doc.msgs[0].value.signer.clone()), + // }) + // } + + + // pub fn get_payload(&self) -> &[u8] { + // self.payload.as_slice() + // } pub fn build_message(payload: &[u8], signer: &CosmosBech32Address) -> Vec { let sign_doc: CosmosStdSignDoc = CosmosStdSignDoc { diff --git a/token-dispenser/programs/token-dispenser/src/lib.rs b/token-dispenser/programs/token-dispenser/src/lib.rs index 2b6ddc1a..3a218370 100644 --- a/token-dispenser/programs/token-dispenser/src/lib.rs +++ b/token-dispenser/programs/token-dispenser/src/lib.rs @@ -73,7 +73,7 @@ mod tests; mod ecosystems; -declare_id!("WabZqXyytFA2XeXswf9DdQkQuSZuRiEgKdDmq7c5Mnp"); +declare_id!("WapFw9mSyHh8trDDRy7AamUn1V7QiGaVvtouj5AucQA"); const CONFIG_SEED: &[u8] = b"config"; const RECEIPT_SEED: &[u8] = b"receipt"; @@ -89,7 +89,6 @@ pub mod token_dispenser { ctx: Context, merkle_root: MerkleRoot, dispenser_guard: Pubkey, - funder: Pubkey, max_transfer: u64, ) -> Result<()> { require_keys_neq!(dispenser_guard, Pubkey::default()); @@ -98,9 +97,7 @@ pub mod token_dispenser { config.merkle_root = merkle_root; config.dispenser_guard = dispenser_guard; config.mint = ctx.accounts.mint.key(); - config.treasury = ctx.accounts.treasury.key(); config.address_lookup_table = ctx.accounts.address_lookup_table.key(); - config.funder = funder; config.max_transfer = max_transfer; Ok(()) } @@ -172,6 +169,7 @@ pub mod token_dispenser { emit!(ClaimEvent { remaining_balance: treasury.amount, + treasury: ctx.accounts.treasury.key(), claimant: *ctx.accounts.claimant.key, claim_info, }); @@ -191,15 +189,9 @@ pub struct Initialize<'info> { pub payer: Signer<'info>, #[account(init, payer = payer, space = Config::LEN, seeds = [CONFIG_SEED], bump)] pub config: Account<'info, Config>, - /// Mint of the treasury pub mint: Account<'info, Mint>, - /// 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 ` - #[account( token::mint = mint )] - pub treasury: Account<'info, TokenAccount>, pub system_program: Program<'info, System>, - /// CHECK: Anchor doesn't have built-in support for address lookup table so adding this check to make sure at least the PDA owner is correct + /// CHECK: we only store this on-chain so it can be conveniently looked up off-chain #[account(owner = solana_address_lookup_table_program::id())] pub address_lookup_table: UncheckedAccount<'info>, } @@ -219,7 +211,7 @@ pub struct Claim<'info> { associated_token::mint = mint, )] pub claimant_fund: Account<'info, TokenAccount>, - #[account(seeds = [CONFIG_SEED], bump = config.bump, has_one = treasury, has_one = mint)] + #[account(seeds = [CONFIG_SEED], bump = config.bump, has_one = mint)] pub config: Account<'info, Config>, pub mint: Account<'info, Mint>, #[account(mut)] @@ -312,13 +304,16 @@ pub struct ClaimCertificate { */ #[derive(Default, Debug, Clone, PartialEq)] pub struct SolanaHasher {} +impl SolanaHasher { + const LEN: usize = 20; +} impl Hasher for SolanaHasher { - type Hash = [u8; 20]; + type Hash = [u8; Self::LEN]; fn hashv(data: &[impl AsRef<[u8]>]) -> Self::Hash { let bytes = hashv(&data.iter().map(|x| x.as_ref()).collect::>()); - let mut hash = [0u8; 20]; - hash.copy_from_slice(&bytes.as_ref()[0..20]); + let mut hash = [0u8; Self::LEN]; + hash.copy_from_slice(&bytes.as_ref()[0..Self::LEN]); hash } } @@ -330,14 +325,12 @@ pub struct Config { pub merkle_root: MerkleRoot, pub dispenser_guard: Pubkey, pub mint: Pubkey, - pub treasury: Pubkey, pub address_lookup_table: Pubkey, - pub funder: Pubkey, pub max_transfer: u64, // This is an extra safeguard to prevent the dispenser from being drained } impl Config { - pub const LEN: usize = 8 + 1 + 20 + 32 + 32 + 32 + 32 + 32 + 8; + pub const LEN: usize = 8 + 1 + SolanaHasher::LEN + 32 + 32 + 32 + 8; } #[account] @@ -635,17 +628,11 @@ pub fn get_receipt_pda(leaf: &[u8]) -> (Pubkey, u8) { } impl crate::accounts::Initialize { - pub fn populate( - payer: Pubkey, - mint: Pubkey, - treasury: Pubkey, - address_lookup_table: Pubkey, - ) -> Self { + pub fn populate(payer: Pubkey, mint: Pubkey, address_lookup_table: Pubkey) -> Self { crate::accounts::Initialize { payer, config: get_config_pda().0, mint, - treasury, system_program: system_program::System::id(), address_lookup_table, } @@ -682,6 +669,7 @@ impl crate::accounts::Claim { #[event] pub struct ClaimEvent { + pub treasury: Pubkey, pub remaining_balance: u64, pub claimant: Pubkey, pub claim_info: ClaimInfo, diff --git a/token-dispenser/programs/token-dispenser/src/tests/dispenser_simulator.rs b/token-dispenser/programs/token-dispenser/src/tests/dispenser_simulator.rs index 59fa6e90..f2b41a80 100644 --- a/token-dispenser/programs/token-dispenser/src/tests/dispenser_simulator.rs +++ b/token-dispenser/programs/token-dispenser/src/tests/dispenser_simulator.rs @@ -235,7 +235,6 @@ impl DispenserSimulator { self.banks_client.process_transaction(transaction).await } - pub async fn init_lookup_table(&mut self) -> Result { let recent_slot = self .banks_client @@ -280,20 +279,17 @@ impl DispenserSimulator { dispenser_guard: Pubkey, address_lookup_table: Pubkey, mint_pubkey_override: Option, - treasury_pubkey_override: Option, max_transfer_override: Option, ) -> Result<(), BanksClientError> { let accounts = accounts::Initialize::populate( self.genesis_keypair.pubkey(), mint_pubkey_override.unwrap_or(self.mint_keypair.pubkey()), - treasury_pubkey_override.unwrap_or(self.pyth_treasury), address_lookup_table, ) .to_account_metas(None); let instruction_data = instruction::Initialize { merkle_root, dispenser_guard, - funder: self.genesis_keypair.pubkey(), max_transfer: max_transfer_override.unwrap_or(u64::MAX), }; let instruction = @@ -347,7 +343,6 @@ impl DispenserSimulator { dispenser_guard.pubkey(), address_lookup_table, None, - None, max_transfer_override, ) .await?; @@ -427,7 +422,7 @@ impl DispenserSimulator { config.mint, claimant_fund .unwrap_or_else(|| get_associated_token_address(&claimant.pubkey(), &config.mint)), - config.treasury, + self.pyth_treasury, ) .to_account_metas(None); diff --git a/token-dispenser/programs/token-dispenser/src/tests/test_discord.rs b/token-dispenser/programs/token-dispenser/src/tests/test_discord.rs index ac68c428..a9e53597 100644 --- a/token-dispenser/programs/token-dispenser/src/tests/test_discord.rs +++ b/token-dispenser/programs/token-dispenser/src/tests/test_discord.rs @@ -53,7 +53,6 @@ pub async fn test_discord() { address_lookup_table, None, None, - None, ) .await .unwrap(); diff --git a/token-dispenser/programs/token-dispenser/src/tests/test_happy_path.rs b/token-dispenser/programs/token-dispenser/src/tests/test_happy_path.rs index 3d83b2c0..45725094 100644 --- a/token-dispenser/programs/token-dispenser/src/tests/test_happy_path.rs +++ b/token-dispenser/programs/token-dispenser/src/tests/test_happy_path.rs @@ -277,7 +277,6 @@ pub async fn test_happy_path() { address_lookup_table, None, None, - None, ) .await .unwrap(); @@ -287,9 +286,7 @@ pub async fn test_happy_path() { merkle_root: merkle_tree.root.clone(), dispenser_guard: dispenser_guard.pubkey(), mint: simulator.mint_keypair.pubkey(), - treasury, address_lookup_table, - funder: simulator.genesis_keypair.pubkey(), max_transfer: u64::MAX, }; diff --git a/token-dispenser/programs/token-dispenser/src/tests/test_initialize.rs b/token-dispenser/programs/token-dispenser/src/tests/test_initialize.rs index 09f842d3..939f1497 100644 --- a/token-dispenser/programs/token-dispenser/src/tests/test_initialize.rs +++ b/token-dispenser/programs/token-dispenser/src/tests/test_initialize.rs @@ -2,16 +2,12 @@ use { super::dispenser_simulator::DispenserSimulator, crate::{ tests::{ - dispenser_simulator::{ - copy_keypair, - IntoTransactionError, - }, + dispenser_simulator::IntoTransactionError, merkleize, test_happy_path::TestClaimCertificate, }, ClaimInfo, }, - anchor_lang::prelude::Pubkey, solana_program_test::tokio, solana_sdk::{ signature::Keypair, @@ -37,23 +33,6 @@ pub async fn test_initialize_fails_with_incorrect_accounts() { let (merkle_tree, _) = merkleize(merkle_items); - - assert_eq!( - simulator - .initialize( - merkle_tree.root.clone(), - dispenser_guard.pubkey(), - Pubkey::default(), // invalid lookup table - None, - None, - None - ) - .await - .unwrap_err() - .unwrap(), - anchor_lang::error::ErrorCode::ConstraintOwner.into_transaction_error(0) - ); - let address_lookup_table = simulator.init_lookup_table().await.unwrap(); assert_eq!( @@ -63,7 +42,6 @@ pub async fn test_initialize_fails_with_incorrect_accounts() { dispenser_guard.pubkey(), address_lookup_table, Some(Keypair::new().pubkey()), //invalid mint - None, None ) .await @@ -71,36 +49,4 @@ pub async fn test_initialize_fails_with_incorrect_accounts() { .unwrap(), anchor_lang::error::ErrorCode::AccountNotInitialized.into_transaction_error(0) ); - - let fake_mint_keypair = Keypair::new(); - simulator - .create_mint(&fake_mint_keypair, &simulator.genesis_keypair.pubkey(), 0) - .await - .unwrap(); - // create treasury (associated token account) from a different mint - let invalid_treasury = Keypair::new(); - simulator - .create_token_account( - fake_mint_keypair.pubkey(), - ©_keypair(&simulator.genesis_keypair), - &invalid_treasury, - ) - .await - .unwrap(); - - assert_eq!( - simulator - .initialize( - merkle_tree.root.clone(), - dispenser_guard.pubkey(), - address_lookup_table, - None, - Some(invalid_treasury.pubkey()), - None - ) - .await - .unwrap_err() - .unwrap(), - anchor_lang::error::ErrorCode::ConstraintTokenMint.into_transaction_error(0) - ); } diff --git a/token-dispenser/scripts/create-treasuries.sh b/token-dispenser/scripts/create-treasuries.sh new file mode 100755 index 00000000..bcfb107b --- /dev/null +++ b/token-dispenser/scripts/create-treasuries.sh @@ -0,0 +1,31 @@ + +if [[ -z $SOLANA_RPC_URL || \ + -z $LEDGER_PUB_KEY || \ + -z $LEDGER_CLI_DERIVATION_PATH || \ + -z $MINT || \ + -z $APPROVE_AMOUNT || \ + -z $CONFIG_PDA ]]; then + echo "Error: One or more required environment variables are not set." + echo "SOLANA_RPC_URL: $SOLANA_RPC_URL" + echo "LEDGER_PUB_KEY: $LEDGER_PUB_KEY" + echo "LEDGER_CLI_DERIVATION_PATH: $LEDGER_CLI_DERIVATION_PATH" + echo "MINT: $MINT" + echo "APPROVE_AMOUNT: $APPROVE_AMOUNT" + echo "CONFIG_PDA: $CONFIG_PDA" + exit 1 +fi + +while IFS= read -r TREASURY; do + spl-token -u $SOLANA_RPC_URL create-account \ + --owner $LEDGER_PUB_KEY \ + --fee-payer usb://ledger?key=$LEDGER_CLI_DERIVATION_PATH \ + $MINT \ + $TREASURY.json + + spl-token \ + --url $SOLANA_RPC_URL \ + approve \ + $TREASURY $APPROVE_AMOUNT $CONFIG_PDA \ + --fee-payer usb://ledger?key=$LEDGER_CLI_DERIVATION_PATH \ + --owner usb://ledger?key=$LEDGER_CLI_DERIVATION_PATH +done < "$(dirname "$0")/treasuries" diff --git a/token-dispenser/scripts/fund-treasuries.sh b/token-dispenser/scripts/fund-treasuries.sh new file mode 100755 index 00000000..d8d488c0 --- /dev/null +++ b/token-dispenser/scripts/fund-treasuries.sh @@ -0,0 +1,20 @@ + +if [[ -z $SOLANA_RPC_URL || \ + -z $LEDGER_PUB_KEY || \ + -z $LEDGER_CLI_DERIVATION_PATH || \ + -z $MINT || \ + -z $MINT_AMOUNT || \ + -z $CONFIG_PDA ]]; then + echo "Error: One or more required environment variables are not set." + echo "SOLANA_RPC_URL: $SOLANA_RPC_URL" + echo "LEDGER_CLI_DERIVATION_PATH: $LEDGER_CLI_DERIVATION_PATH" + echo "MINT: $MINT" + echo "MINT_AMOUNT: $MINT_AMOUNT" + exit 1 +fi + +while IFS= read -r TREASURY; do + spl-token -u $SOLANA_RPC_URL mint $MINT $MINT_AMOUNT $TREASURY \ + --fee-payer usb://ledger?key=$LEDGER_CLI_DERIVATION_PATH \ + --mint-authority usb://ledger?key=$LEDGER_CLI_DERIVATION_PATH +done < "$(dirname "$0")/treasuries" diff --git a/token-dispenser/scripts/treasuries b/token-dispenser/scripts/treasuries new file mode 100644 index 00000000..c31d9682 --- /dev/null +++ b/token-dispenser/scripts/treasuries @@ -0,0 +1,6 @@ +waTh9vNmRz8hHxQv1zW81ExKQ7fwaa1TR6tQT5fTkjg +waTirsbdRyyxm8DFxH9Z9P5Pyrj74jJ7E74zqhmGX1k +wAtMcoqwHb7obEL2USNXPqxg1CmJDSjjjsNcEm9bzCZ +Wats1sM7W4UvxUuQPevGxexgcaFiaXMXxActKUmcvHx +waTtgLt1WVRgoWYNZh97AYAUqoU4nN98jVThPdYQVwj +WaTxa5w4TjYHRdHwG2zaN9ynA1c9z4J9TswsBCmzy4N diff --git a/token-dispenser/ts/scripts/config.ts b/token-dispenser/ts/scripts/config.ts new file mode 100644 index 00000000..ec22b8a9 --- /dev/null +++ b/token-dispenser/ts/scripts/config.ts @@ -0,0 +1,22 @@ +import { PublicKey } from "@solana/web3.js"; + +export const treasuries = [ + new PublicKey("waTh9vNmRz8hHxQv1zW81ExKQ7fwaa1TR6tQT5fTkjg"), + new PublicKey("waTirsbdRyyxm8DFxH9Z9P5Pyrj74jJ7E74zqhmGX1k"), + new PublicKey("wAtMcoqwHb7obEL2USNXPqxg1CmJDSjjjsNcEm9bzCZ"), + new PublicKey("Wats1sM7W4UvxUuQPevGxexgcaFiaXMXxActKUmcvHx"), + new PublicKey("waTtgLt1WVRgoWYNZh97AYAUqoU4nN98jVThPdYQVwj"), + new PublicKey("WaTxa5w4TjYHRdHwG2zaN9ynA1c9z4J9TswsBCmzy4N"), +]; + +export const funders = [ + new PublicKey("wAf15NnY6VVVQXDSdhp79LndkHXSD9BmcUhh4bqSSGp"), + new PublicKey("WafepN7ToYGS4WjaqtMV8g2q3YV1GgcoUZ4nvK4LhD8"), + new PublicKey("wAfmKAiAgtfywPhfRdLQ7uMeS2RW3kN57kodaRabX6V"), + new PublicKey("WAfN8P3NdYeTnnvFPKYUiveyqZSZtBboxUyrMSAzQc1"), + new PublicKey("wafydZpGcTLk3FYEQ5Q4wwSKJXMy3EMTngxeVEXG45e"), + new PublicKey("WafzGQMEqwABhMdNHH86yDRqzZQvK5rELK5Nrto97Va"), +]; + +export const tokenDispenserProgramId = + "WapFw9mSyHh8trDDRy7AamUn1V7QiGaVvtouj5AucQA"; diff --git a/token-dispenser/ts/scripts/create-spl-token.ts b/token-dispenser/ts/scripts/create-spl-token.ts index 79b2fe08..28a131e4 100644 --- a/token-dispenser/ts/scripts/create-spl-token.ts +++ b/token-dispenser/ts/scripts/create-spl-token.ts @@ -17,7 +17,7 @@ console.log( (async () => { const tokenConfig = { - decimals: 9, + decimals: 6, name: "Test grant Token", symbol: "TEST_GRANT_TKN", uri: "https://thisisnot.arealurl/info.json", diff --git a/token-dispenser/ts/scripts/initialize.ts b/token-dispenser/ts/scripts/initialize.ts index 07329ba0..4ec8a5ff 100644 --- a/token-dispenser/ts/scripts/initialize.ts +++ b/token-dispenser/ts/scripts/initialize.ts @@ -8,6 +8,7 @@ import { import { TokenDispenserSdk } from "../sdk"; import { ledgerSignAndSend, ledgerSignAndSendV0 } from "./helpers"; import { connection, getSigner, getEnv } from "./env"; +import { funders, tokenDispenserProgramId, treasuries } from "./config"; import { ASSOCIATED_TOKEN_PROGRAM_ID, TOKEN_PROGRAM_ID, @@ -17,20 +18,16 @@ type InitConfig = { // Account Addresses (base58 encoded): tokenDispenser: string; mint: string; - treasury: string; dispenserGuard: string; - funder: string; merkleRoot: Buffer; maxTransfer: bigint; }; (async () => { const config: InitConfig = { - tokenDispenser: getEnv("PROGRAM_ID"), + tokenDispenser: tokenDispenserProgramId, mint: getEnv("MINT"), - treasury: getEnv("TREASURY"), dispenserGuard: getEnv("DISPENSER_GUARD"), - funder: getEnv("FUNDER"), merkleRoot: Buffer.from(getEnv("MERKLE_ROOT"), "hex"), maxTransfer: BigInt(getEnv("MAX_TRANSFER")), }; @@ -40,12 +37,11 @@ type InitConfig = { const tokenDispenser = new TokenDispenserSdk(connection, { programId: config.tokenDispenser, + payer: signerPk, }); const configPda = new PublicKey(tokenDispenser.configAccountAddress()); const mint = new PublicKey(config.mint); - const treasury = new PublicKey(config.treasury); - const funder = new PublicKey(config.funder); const dispenserGuard = new PublicKey(config.dispenserGuard); const [createAddressLookupTableIx, lookupTable] = @@ -55,7 +51,6 @@ type InitConfig = { recentSlot: await connection.getSlot(), }); - console.log("Lookup Table: ", lookupTable.toBase58()); console.log("Config PDA: ", configPda.toBase58()); const extendAddressLooupTableIx = AddressLookupTableProgram.extendLookupTable( @@ -66,12 +61,10 @@ type InitConfig = { addresses: [ configPda, mint, - treasury, TOKEN_PROGRAM_ID, SystemProgram.programId, SYSVAR_INSTRUCTIONS_PUBKEY, ASSOCIATED_TOKEN_PROGRAM_ID, - funder, ], } ); @@ -80,13 +73,24 @@ type InitConfig = { [createAddressLookupTableIx, extendAddressLooupTableIx], [] ); + console.log("Lookup Table created at address: ", lookupTable.toBase58()); + + const addFundersAndTreasuriesIx = AddressLookupTableProgram.extendLookupTable( + { + payer: signerPk, + authority: signerPk, + lookupTable, + addresses: [...funders, ...treasuries], + } + ); + + await ledgerSignAndSendV0([addFundersAndTreasuriesIx], []); + console.log("Funders and Treasuries added to lookup table"); const initializeIx = await tokenDispenser.createInitializeInstruction({ payer: signerPk, mint, - treasury, dispenserGuard, - funder, addressLookupTable: lookupTable, merkleRoot: config.merkleRoot, maxTransfer: config.maxTransfer, diff --git a/token-dispenser/ts/scripts/print-config-pda.ts b/token-dispenser/ts/scripts/print-config-pda.ts new file mode 100644 index 00000000..916ec8f7 --- /dev/null +++ b/token-dispenser/ts/scripts/print-config-pda.ts @@ -0,0 +1,27 @@ +import { PublicKey } from "@solana/web3.js"; + +import { TokenDispenserSdk } from "../sdk"; +import { connection, getSigner } from "./env"; +import { tokenDispenserProgramId } from "./config"; + +type InitConfig = { + // Account Addresses (base58 encoded): + tokenDispenser: string; +}; + +(async () => { + const config: InitConfig = { + tokenDispenser: tokenDispenserProgramId, + }; + + const signer = await getSigner(); + const signerPk = new PublicKey(await signer.getAddress()); + + const tokenDispenser = new TokenDispenserSdk(connection, { + programId: config.tokenDispenser, + payer: signerPk, + }); + + const configPda = new PublicKey(tokenDispenser.configAccountAddress()); + console.log("Config PDA: ", configPda.toBase58()); +})(); diff --git a/token-dispenser/ts/sdk/idl/token_dispenser.json b/token-dispenser/ts/sdk/idl/token_dispenser.json index 3059cd0c..098c2327 100644 --- a/token-dispenser/ts/sdk/idl/token_dispenser.json +++ b/token-dispenser/ts/sdk/idl/token_dispenser.json @@ -21,18 +21,7 @@ { "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 `" - ] + "isSigner": false }, { "name": "systemProgram", @@ -56,10 +45,6 @@ "name": "dispenserGuard", "type": "publicKey" }, - { - "name": "funder", - "type": "publicKey" - }, { "name": "maxTransfer", "type": "u64" @@ -164,18 +149,10 @@ "name": "mint", "type": "publicKey" }, - { - "name": "treasury", - "type": "publicKey" - }, { "name": "addressLookupTable", "type": "publicKey" }, - { - "name": "funder", - "type": "publicKey" - }, { "name": "maxTransfer", "type": "u64" @@ -464,7 +441,7 @@ "type": "string" }, { - "name": "verificationInstructionIndex", + "name": "verification_instruction_index", "type": "u8" } ] @@ -479,7 +456,7 @@ } }, { - "name": "verificationInstructionIndex", + "name": "verification_instruction_index", "type": "u8" } ] @@ -497,7 +474,7 @@ } }, { - "name": "verificationInstructionIndex", + "name": "verification_instruction_index", "type": "u8" } ] @@ -512,7 +489,7 @@ } }, { - "name": "verificationInstructionIndex", + "name": "verification_instruction_index", "type": "u8" } ] @@ -521,7 +498,7 @@ "name": "Cosmwasm", "fields": [ { - "name": "chainId", + "name": "chain_id", "type": "string" }, { @@ -531,7 +508,7 @@ } }, { - "name": "recoveryId", + "name": "recovery_id", "type": "u8" }, { @@ -556,7 +533,7 @@ } }, { - "name": "verificationInstructionIndex", + "name": "verification_instruction_index", "type": "u8" } ] @@ -571,7 +548,7 @@ } }, { - "name": "verificationInstructionIndex", + "name": "verification_instruction_index", "type": "u8" } ] @@ -584,6 +561,11 @@ { "name": "ClaimEvent", "fields": [ + { + "name": "treasury", + "type": "publicKey", + "index": false + }, { "name": "remainingBalance", "type": "u64", diff --git a/token-dispenser/ts/sdk/idl/token_dispenser.ts b/token-dispenser/ts/sdk/idl/token_dispenser.ts index 167cb25a..688f9694 100644 --- a/token-dispenser/ts/sdk/idl/token_dispenser.ts +++ b/token-dispenser/ts/sdk/idl/token_dispenser.ts @@ -22,17 +22,6 @@ export type TokenDispenser = { 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"; @@ -56,10 +45,6 @@ export type TokenDispenser = { name: "dispenserGuard"; type: "publicKey"; }, - { - name: "funder"; - type: "publicKey"; - }, { name: "maxTransfer"; type: "u64"; @@ -164,18 +149,10 @@ export type TokenDispenser = { name: "mint"; type: "publicKey"; }, - { - name: "treasury"; - type: "publicKey"; - }, { name: "addressLookupTable"; type: "publicKey"; }, - { - name: "funder"; - type: "publicKey"; - }, { name: "maxTransfer"; type: "u64"; @@ -464,7 +441,7 @@ export type TokenDispenser = { type: "string"; }, { - name: "verificationInstructionIndex"; + name: "verification_instruction_index"; type: "u8"; } ]; @@ -479,7 +456,7 @@ export type TokenDispenser = { }; }, { - name: "verificationInstructionIndex"; + name: "verification_instruction_index"; type: "u8"; } ]; @@ -497,7 +474,7 @@ export type TokenDispenser = { }; }, { - name: "verificationInstructionIndex"; + name: "verification_instruction_index"; type: "u8"; } ]; @@ -512,7 +489,7 @@ export type TokenDispenser = { }; }, { - name: "verificationInstructionIndex"; + name: "verification_instruction_index"; type: "u8"; } ]; @@ -521,7 +498,7 @@ export type TokenDispenser = { name: "Cosmwasm"; fields: [ { - name: "chainId"; + name: "chain_id"; type: "string"; }, { @@ -531,7 +508,7 @@ export type TokenDispenser = { }; }, { - name: "recoveryId"; + name: "recovery_id"; type: "u8"; }, { @@ -556,7 +533,7 @@ export type TokenDispenser = { }; }, { - name: "verificationInstructionIndex"; + name: "verification_instruction_index"; type: "u8"; } ]; @@ -571,7 +548,7 @@ export type TokenDispenser = { }; }, { - name: "verificationInstructionIndex"; + name: "verification_instruction_index"; type: "u8"; } ]; @@ -584,6 +561,11 @@ export type TokenDispenser = { { name: "ClaimEvent"; fields: [ + { + name: "treasury"; + type: "publicKey"; + index: false; + }, { name: "remainingBalance"; type: "u64"; @@ -675,17 +657,6 @@ export const IDL: TokenDispenser = { 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", @@ -709,10 +680,6 @@ export const IDL: TokenDispenser = { name: "dispenserGuard", type: "publicKey", }, - { - name: "funder", - type: "publicKey", - }, { name: "maxTransfer", type: "u64", @@ -817,18 +784,10 @@ export const IDL: TokenDispenser = { name: "mint", type: "publicKey", }, - { - name: "treasury", - type: "publicKey", - }, { name: "addressLookupTable", type: "publicKey", }, - { - name: "funder", - type: "publicKey", - }, { name: "maxTransfer", type: "u64", @@ -1117,7 +1076,7 @@ export const IDL: TokenDispenser = { type: "string", }, { - name: "verificationInstructionIndex", + name: "verification_instruction_index", type: "u8", }, ], @@ -1132,7 +1091,7 @@ export const IDL: TokenDispenser = { }, }, { - name: "verificationInstructionIndex", + name: "verification_instruction_index", type: "u8", }, ], @@ -1150,7 +1109,7 @@ export const IDL: TokenDispenser = { }, }, { - name: "verificationInstructionIndex", + name: "verification_instruction_index", type: "u8", }, ], @@ -1165,7 +1124,7 @@ export const IDL: TokenDispenser = { }, }, { - name: "verificationInstructionIndex", + name: "verification_instruction_index", type: "u8", }, ], @@ -1174,7 +1133,7 @@ export const IDL: TokenDispenser = { name: "Cosmwasm", fields: [ { - name: "chainId", + name: "chain_id", type: "string", }, { @@ -1184,7 +1143,7 @@ export const IDL: TokenDispenser = { }, }, { - name: "recoveryId", + name: "recovery_id", type: "u8", }, { @@ -1209,7 +1168,7 @@ export const IDL: TokenDispenser = { }, }, { - name: "verificationInstructionIndex", + name: "verification_instruction_index", type: "u8", }, ], @@ -1224,7 +1183,7 @@ export const IDL: TokenDispenser = { }, }, { - name: "verificationInstructionIndex", + name: "verification_instruction_index", type: "u8", }, ], @@ -1237,6 +1196,11 @@ export const IDL: TokenDispenser = { { name: "ClaimEvent", fields: [ + { + name: "treasury", + type: "publicKey", + index: false, + }, { name: "remainingBalance", type: "u64", diff --git a/token-dispenser/ts/sdk/token-dispenser.ts b/token-dispenser/ts/sdk/token-dispenser.ts index 94bf87b1..d43ae437 100644 --- a/token-dispenser/ts/sdk/token-dispenser.ts +++ b/token-dispenser/ts/sdk/token-dispenser.ts @@ -1,5 +1,4 @@ -import { Program, BN, Address } from "@coral-xyz/anchor"; - +import { Program, BN, Address, web3, AnchorProvider } from "@coral-xyz/anchor"; import { TokenDispenser } from "./idl/token_dispenser"; import IDL from "./idl/token_dispenser.json"; import { PublicKey, Connection } from "@solana/web3.js"; @@ -16,11 +15,31 @@ export class TokenDispenserSdk { connection: Connection, args: { programId: string; + payer: PublicKey; } ) { - this.program = new Program(IDL as any, new PublicKey(args.programId), { + const wallet = { + publicKey: args.payer, + signTransaction: async function (): Promise { + throw new Error("ilegal call"); + }, + signAllTransactions: async function (...args: any[]): Promise { + throw new Error("ilegal call"); + }, + // payer: args.payer, + }; + const provider = new AnchorProvider( connection, - }); + wallet, + AnchorProvider.defaultOptions() + ); + + // this.program = new Program(IDL as any, new PublicKey(args.programId), provider); + this.program = new Program( + IDL as any, + new PublicKey(args.programId), + provider + ); } // Acounts: @@ -32,9 +51,7 @@ export class TokenDispenserSdk { async createInitializeInstruction(args: { payer: PublicKey; mint: PublicKey; - treasury: PublicKey; dispenserGuard: PublicKey; - funder: PublicKey; addressLookupTable: PublicKey; merkleRoot: Buffer; maxTransfer: bigint; @@ -43,15 +60,14 @@ export class TokenDispenserSdk { .initialize( Array.from(args.merkleRoot), args.dispenserGuard, - args.funder, new BN(args.maxTransfer.toString()) ) .accounts({ - payer: args.payer, - mint: args.mint, - treasury: args.treasury, config: new PublicKey(this.configAccountAddress()), + mint: args.mint, + systemProgram: web3.SystemProgram.programId, addressLookupTable: args.addressLookupTable, + payer: args.payer, }) .instruction(); } diff --git a/token-dispenser/yarn.lock b/token-dispenser/yarn.lock index 6757e456..34f9d04a 100644 --- a/token-dispenser/yarn.lock +++ b/token-dispenser/yarn.lock @@ -2,23 +2,16 @@ # yarn lockfile v1 -"@babel/runtime@^7.12.5", "@babel/runtime@^7.17.2": - version "7.22.3" - resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.3.tgz" - integrity sha512-XsDuspWKLUsxwCp6r7EhsExHtYfbe5oAGQ19kqngTdCPUoPQzOPdUbD/pB9PJiwb2ptYKQDjSJT3R6dC+EPqfQ== - dependencies: - regenerator-runtime "^0.13.11" - -"@babel/runtime@^7.23.4": +"@babel/runtime@^7.17.2", "@babel/runtime@^7.23.4": version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.1.tgz#431f9a794d173b53720e69a6464abc6f0e2a5c57" + resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.1.tgz" integrity sha512-+BIznRzyqBf+2wCTxcKE3wDjfGeCoVE61KSHGpkzqrLi8qxqFwBeUFyId2cxkTmm55fzDGnm0+yCxaxygrLUnQ== dependencies: regenerator-runtime "^0.14.0" -"@coral-xyz/anchor@^0.29.0": +"@coral-xyz/anchor@0.29.0": version "0.29.0" - resolved "https://registry.npmjs.org/@coral-xyz/anchor/-/anchor-0.29.0.tgz" + resolved "https://registry.yarnpkg.com/@coral-xyz/anchor/-/anchor-0.29.0.tgz#bd0be95bedfb30a381c3e676e5926124c310ff12" integrity sha512-eny6QNG0WOwqV0zQ7cs/b1tIuzZGmP7U7EcH+ogt4Gdbl8HDmIYVMh/9aTmYZPaFWjtUaI8qSn73uYEXWfATdA== dependencies: "@coral-xyz/borsh" "^0.29.0" @@ -118,26 +111,14 @@ resolved "https://registry.npmjs.org/@ledgerhq/logs/-/logs-6.12.0.tgz" integrity sha512-ExDoj1QV5eC6TEbMdLUMMk9cfvNKhhv5gXol4SmULRVCx/3iyCPhJ74nsb3S0Vb+/f+XujBEj3vQn5+cwS0fNA== -"@noble/curves@^1.0.0": - version "1.0.0" - resolved "https://registry.npmjs.org/@noble/curves/-/curves-1.0.0.tgz" - integrity sha512-2upgEu0iLiDVDZkNLeFV2+ht0BAVgQnEmCk6JsOch9Rp8xfkMCbvbAZlA2pBHQc73dbl+vFOXfqkf4uemdn0bw== - dependencies: - "@noble/hashes" "1.3.0" - "@noble/curves@^1.2.0": version "1.4.0" - resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.4.0.tgz#f05771ef64da724997f69ee1261b2417a49522d6" + resolved "https://registry.npmjs.org/@noble/curves/-/curves-1.4.0.tgz" integrity sha512-p+4cb332SFCrReJkCYe8Xzm0OWi4Jji5jVdIZRL/PmacmDkFNw6MrrV+gGpiPxLHbV+zKFRywUWbaseT+tZRXg== dependencies: "@noble/hashes" "1.4.0" -"@noble/hashes@1.3.0": - version "1.3.0" - resolved "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.0.tgz" - integrity sha512-ilHEACi9DwqJB0pw7kv+Apvh50jiiSyR/cQ3y4W7lOR5mhvn/50FLUfsnfJz0BDZtl/RR16kXvptiv6q1msYZg== - -"@noble/hashes@1.4.0", "@noble/hashes@^1.3.0", "@noble/hashes@^1.3.1", "@noble/hashes@^1.3.3": +"@noble/hashes@1.4.0", "@noble/hashes@^1.3.1", "@noble/hashes@^1.3.3": version "1.4.0" resolved "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz" integrity sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg== @@ -149,7 +130,7 @@ "@solana/buffer-layout-utils@^0.2.0": version "0.2.0" - resolved "https://registry.yarnpkg.com/@solana/buffer-layout-utils/-/buffer-layout-utils-0.2.0.tgz#b45a6cab3293a2eb7597cceb474f229889d875ca" + resolved "https://registry.npmjs.org/@solana/buffer-layout-utils/-/buffer-layout-utils-0.2.0.tgz" integrity sha512-szG4sxgJGktbuZYDg2FfNmkMi0DYQoVjN2h7ta1W1hPrwzarcFLBq9UpX1UjNXsNpT9dn+chgprtWGioUAr4/g== dependencies: "@solana/buffer-layout" "^4.0.0" @@ -166,12 +147,12 @@ "@solana/codecs-core@2.0.0-experimental.8618508": version "2.0.0-experimental.8618508" - resolved "https://registry.yarnpkg.com/@solana/codecs-core/-/codecs-core-2.0.0-experimental.8618508.tgz#4f6709dd50e671267f3bea7d09209bc6471b7ad0" + resolved "https://registry.npmjs.org/@solana/codecs-core/-/codecs-core-2.0.0-experimental.8618508.tgz" integrity sha512-JCz7mKjVKtfZxkuDtwMAUgA7YvJcA2BwpZaA1NOLcted4OMC4Prwa3DUe3f3181ixPYaRyptbF0Ikq2MbDkYEA== "@solana/codecs-data-structures@2.0.0-experimental.8618508": version "2.0.0-experimental.8618508" - resolved "https://registry.yarnpkg.com/@solana/codecs-data-structures/-/codecs-data-structures-2.0.0-experimental.8618508.tgz#c16a704ac0f743a2e0bf73ada42d830b3402d848" + resolved "https://registry.npmjs.org/@solana/codecs-data-structures/-/codecs-data-structures-2.0.0-experimental.8618508.tgz" integrity sha512-sLpjL9sqzaDdkloBPV61Rht1tgaKq98BCtIKRuyscIrmVPu3wu0Bavk2n/QekmUzaTsj7K1pVSniM0YqCdnEBw== dependencies: "@solana/codecs-core" "2.0.0-experimental.8618508" @@ -179,14 +160,14 @@ "@solana/codecs-numbers@2.0.0-experimental.8618508": version "2.0.0-experimental.8618508" - resolved "https://registry.yarnpkg.com/@solana/codecs-numbers/-/codecs-numbers-2.0.0-experimental.8618508.tgz#d84f9ed0521b22e19125eefc7d51e217fcaeb3e4" + resolved "https://registry.npmjs.org/@solana/codecs-numbers/-/codecs-numbers-2.0.0-experimental.8618508.tgz" integrity sha512-EXQKfzFr3CkKKNzKSZPOOOzchXsFe90TVONWsSnVkonO9z+nGKALE0/L9uBmIFGgdzhhU9QQVFvxBMclIDJo2Q== dependencies: "@solana/codecs-core" "2.0.0-experimental.8618508" "@solana/codecs-strings@2.0.0-experimental.8618508": version "2.0.0-experimental.8618508" - resolved "https://registry.yarnpkg.com/@solana/codecs-strings/-/codecs-strings-2.0.0-experimental.8618508.tgz#72457b884d9be80b59b263bcce73892b081e9402" + resolved "https://registry.npmjs.org/@solana/codecs-strings/-/codecs-strings-2.0.0-experimental.8618508.tgz" integrity sha512-b2yhinr1+oe+JDmnnsV0641KQqqDG8AQ16Z/x7GVWO+AWHMpRlHWVXOq8U1yhPMA4VXxl7i+D+C6ql0VGFp0GA== dependencies: "@solana/codecs-core" "2.0.0-experimental.8618508" @@ -194,7 +175,7 @@ "@solana/options@2.0.0-experimental.8618508": version "2.0.0-experimental.8618508" - resolved "https://registry.yarnpkg.com/@solana/options/-/options-2.0.0-experimental.8618508.tgz#95385340e85f9e8a81b2bfba089404a61c8e9520" + resolved "https://registry.npmjs.org/@solana/options/-/options-2.0.0-experimental.8618508.tgz" integrity sha512-fy/nIRAMC3QHvnKi63KEd86Xr/zFBVxNW4nEpVEU2OT0gCEKwHY4Z55YHf7XujhyuM3PNpiBKg/YYw5QlRU4vg== dependencies: "@solana/codecs-core" "2.0.0-experimental.8618508" @@ -202,7 +183,7 @@ "@solana/spl-token-metadata@^0.1.2": version "0.1.2" - resolved "https://registry.yarnpkg.com/@solana/spl-token-metadata/-/spl-token-metadata-0.1.2.tgz#876e13432bd2960bd3cac16b9b0af63e69e37719" + resolved "https://registry.npmjs.org/@solana/spl-token-metadata/-/spl-token-metadata-0.1.2.tgz" integrity sha512-hJYnAJNkDrtkE2Q41YZhCpeOGU/0JgRFXbtrtOuGGeKc3pkEUHB9DDoxZAxx+XRno13GozUleyBi0qypz4c3bw== dependencies: "@solana/codecs-core" "2.0.0-experimental.8618508" @@ -214,7 +195,7 @@ "@solana/spl-token@^0.4.1": version "0.4.1" - resolved "https://registry.yarnpkg.com/@solana/spl-token/-/spl-token-0.4.1.tgz#7302c8052803f63012bd8189d42ca7d74d7917a5" + resolved "https://registry.npmjs.org/@solana/spl-token/-/spl-token-0.4.1.tgz" integrity sha512-DEe15GI0l+XLHwtau/3GUwGQJ9YY/VWNE0k/QuXaaGKo4adMZLEAIQUktRc/S2sRqPjvUdR5anZGxQ9p5khWZw== dependencies: "@solana/buffer-layout" "^4.0.0" @@ -224,15 +205,15 @@ "@solana/spl-type-length-value@0.1.0": version "0.1.0" - resolved "https://registry.yarnpkg.com/@solana/spl-type-length-value/-/spl-type-length-value-0.1.0.tgz#b5930cf6c6d8f50c7ff2a70463728a4637a2f26b" + resolved "https://registry.npmjs.org/@solana/spl-type-length-value/-/spl-type-length-value-0.1.0.tgz" integrity sha512-JBMGB0oR4lPttOZ5XiUGyvylwLQjt1CPJa6qQ5oM+MBCndfjz2TKKkw0eATlLLcYmq1jBVsNlJ2cD6ns2GR7lA== dependencies: buffer "^6.0.3" -"@solana/web3.js@^1.32.0": - version "1.91.1" - resolved "https://registry.yarnpkg.com/@solana/web3.js/-/web3.js-1.91.1.tgz#d49d2f982b52070be3b987fd8d892fcbddd064b5" - integrity sha512-cPgjZXm688oM9cULvJ8u2VH6Qp5rvptE1N1VODVxn2mAbpZsWrvWNPjmASkMYT/HzyrtqFkPvFdSHg8Xjt7aQA== +"@solana/web3.js@^1.32.0", "@solana/web3.js@^1.68.0", "@solana/web3.js@^1.91.1": + version "1.91.2" + resolved "https://registry.npmjs.org/@solana/web3.js/-/web3.js-1.91.2.tgz" + integrity sha512-WXPl5VXtfNKWM2RkGj7mvX6dKcZURDKe1lWBFAt/RqDBI9Rjr9hr7Y+U+yz2+TyViMmoinfJVlkS4gk2FPDG/g== dependencies: "@babel/runtime" "^7.23.4" "@noble/curves" "^1.2.0" @@ -250,27 +231,6 @@ rpc-websockets "^7.5.1" superstruct "^0.14.2" -"@solana/web3.js@^1.68.0": - version "1.77.3" - resolved "https://registry.npmjs.org/@solana/web3.js/-/web3.js-1.77.3.tgz" - integrity sha512-PHaO0BdoiQRPpieC1p31wJsBaxwIOWLh8j2ocXNKX8boCQVldt26Jqm2tZE4KlrvnCIV78owPLv1pEUgqhxZ3w== - dependencies: - "@babel/runtime" "^7.12.5" - "@noble/curves" "^1.0.0" - "@noble/hashes" "^1.3.0" - "@solana/buffer-layout" "^4.0.0" - agentkeepalive "^4.2.1" - bigint-buffer "^1.1.5" - bn.js "^5.0.0" - borsh "^0.7.0" - bs58 "^4.0.1" - buffer "6.0.3" - fast-stable-stringify "^1.0.0" - jayson "^4.1.0" - node-fetch "^2.6.7" - rpc-websockets "^7.5.1" - superstruct "^0.14.2" - "@types/bn.js@^5.1.0": version "5.1.1" resolved "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.1.tgz" @@ -351,18 +311,9 @@ JSONStream@^1.3.5: jsonparse "^1.2.0" through ">=2.2.7 <3" -agentkeepalive@^4.2.1: - version "4.3.0" - resolved "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.3.0.tgz" - integrity sha512-7Epl1Blf4Sy37j4v9f9FjICCh4+KAQOyXgHEwlyBiAQLbhKdq/i2QQU3amQalS/wPhdPzDXPL5DMR5bkn+YeWg== - dependencies: - debug "^4.1.0" - depd "^2.0.0" - humanize-ms "^1.2.1" - agentkeepalive@^4.5.0: version "4.5.0" - resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.5.0.tgz#2673ad1389b3c418c5a20c5d7364f93ca04be923" + resolved "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz" integrity sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew== dependencies: humanize-ms "^1.2.1" @@ -433,7 +384,7 @@ bigint-buffer@^1.1.5: bignumber.js@^9.0.1: version "9.1.2" - resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.1.2.tgz#b7c4242259c008903b13707983b5f4bbd31eda0c" + resolved "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz" integrity sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug== binary-extensions@^2.0.0: @@ -462,7 +413,7 @@ bl@^4.0.3: inherits "^2.0.4" readable-stream "^3.4.0" -bn.js@^5.0.0, bn.js@^5.1.2, bn.js@^5.2.0, bn.js@^5.2.1: +bn.js@^5.1.2, bn.js@^5.2.0, bn.js@^5.2.1: version "5.2.1" resolved "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz" integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== @@ -637,13 +588,6 @@ debug@4.3.3: dependencies: ms "2.1.2" -debug@^4.1.0: - version "4.3.4" - resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== - dependencies: - ms "2.1.2" - decamelize@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz" @@ -673,11 +617,6 @@ delay@^5.0.0: resolved "https://registry.npmjs.org/delay/-/delay-5.0.0.tgz" integrity sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw== -depd@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz" - integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== - detect-libc@^2.0.0: version "2.0.3" resolved "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz" @@ -1127,16 +1066,9 @@ node-addon-api@^6.0.0: resolved "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz" integrity sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA== -node-fetch@^2.6.11, node-fetch@^2.6.7: - version "2.6.11" - resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz" - integrity sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w== - dependencies: - whatwg-url "^5.0.0" - -node-fetch@^2.7.0: +node-fetch@^2.6.11, node-fetch@^2.7.0: version "2.7.0" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" + resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz" integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== dependencies: whatwg-url "^5.0.0" @@ -1270,14 +1202,9 @@ readdirp@~3.6.0: dependencies: picomatch "^2.2.1" -regenerator-runtime@^0.13.11: - version "0.13.11" - resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz" - integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== - regenerator-runtime@^0.14.0: version "0.14.1" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f" + resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz" integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== require-directory@^2.1.1: From b47300b16abea78b7eff8d1ff12fb2965e5d0173 Mon Sep 17 00:00:00 2001 From: Andreas <41449730+nonergodic@users.noreply.github.com> Date: Mon, 1 Apr 2024 14:50:20 -0700 Subject: [PATCH 08/12] estimate and set CU budget and priortiy fee (#44) * first stab at better CU cost calculation * further optimize on compute budget * fix: rearrange instructions and set correct verify ix index * formatting * determine and set remaining cu numbers * formatting * Fix backend tests * Move signature verification instruction to the top of the instructions list * Fix backend whitelist --------- Co-authored-by: Abhishek Rajput Co-authored-by: M-Picco --- backend/package.json | 1 + backend/src/utils/fund-transactions.ts | 6 +- backend/yarn.lock | 184 +++++- frontend/claim_sdk/claim.ts | 41 +- frontend/claim_sdk/cu_estimate.ts.txt | 883 +++++++++++++++++++++++++ frontend/claim_sdk/solana.ts | 159 +++-- frontend/integration/api.test.ts | 2 + frontend/integration/api.ts | 2 + frontend/utils/verifyTransaction.ts | 2 +- 9 files changed, 1203 insertions(+), 77 deletions(-) create mode 100644 frontend/claim_sdk/cu_estimate.ts.txt diff --git a/backend/package.json b/backend/package.json index b821deae..b002259e 100644 --- a/backend/package.json +++ b/backend/package.json @@ -19,6 +19,7 @@ "@cosmjs/crypto": "^0.32.3", "@cosmjs/encoding": "^0.32.3", "@influxdata/influxdb-client": "^1.33.2", + "@solana/spl-token": "^0.4.3", "@solana/web3.js": "^1.91.1", "bs58": "^5.0.0", "hi-base32": "^0.5.1", diff --git a/backend/src/utils/fund-transactions.ts b/backend/src/utils/fund-transactions.ts index d744ef15..b2775dcd 100644 --- a/backend/src/utils/fund-transactions.ts +++ b/backend/src/utils/fund-transactions.ts @@ -7,6 +7,7 @@ import { TransactionInstruction, VersionedTransaction } from '@solana/web3.js' +import * as splToken from '@solana/spl-token' import { coder } from '../token-dispenser' import config from '../config' @@ -58,7 +59,8 @@ async function loadWhitelistedProgramIds(): Promise { tokenDispenserPublicKey, Secp256k1Program.programId, Ed25519Program.programId, - ComputeBudgetProgram.programId + ComputeBudgetProgram.programId, + splToken.ASSOCIATED_TOKEN_PROGRAM_ID ] } @@ -140,7 +142,7 @@ export function checkSetComputeBudgetInstructionsAreSetComputeUnitPrice( const priorityFee = ComputeBudgetInstruction.decodeSetComputeUnitPrice( legacTransactionInstruction ) - if (priorityFee.microLamports >= MAX_COMPUTE_UNIT_PRICE) { + if (priorityFee.microLamports > MAX_COMPUTE_UNIT_PRICE) { console.error('Priority fee set is too high') return false } diff --git a/backend/yarn.lock b/backend/yarn.lock index f3b086df..978921c0 100644 --- a/backend/yarn.lock +++ b/backend/yarn.lock @@ -1679,13 +1679,178 @@ "@smithy/util-buffer-from" "^2.2.0" tslib "^2.6.2" -"@solana/buffer-layout@^4.0.1": +"@solana/buffer-layout-utils@^0.2.0": + version "0.2.0" + resolved "https://registry.yarnpkg.com/@solana/buffer-layout-utils/-/buffer-layout-utils-0.2.0.tgz#b45a6cab3293a2eb7597cceb474f229889d875ca" + integrity sha512-szG4sxgJGktbuZYDg2FfNmkMi0DYQoVjN2h7ta1W1hPrwzarcFLBq9UpX1UjNXsNpT9dn+chgprtWGioUAr4/g== + dependencies: + "@solana/buffer-layout" "^4.0.0" + "@solana/web3.js" "^1.32.0" + bigint-buffer "^1.1.5" + bignumber.js "^9.0.1" + +"@solana/buffer-layout@^4.0.0", "@solana/buffer-layout@^4.0.1": version "4.0.1" resolved "https://registry.yarnpkg.com/@solana/buffer-layout/-/buffer-layout-4.0.1.tgz#b996235eaec15b1e0b5092a8ed6028df77fa6c15" integrity sha512-E1ImOIAD1tBZFRdjeM4/pzTiTApC0AOBGwyAMS4fwIodCWArzJ3DWdoh8cKxeFM2fElkxBh2Aqts1BPC373rHA== dependencies: buffer "~6.0.3" +"@solana/codecs-core@2.0.0-experimental.8618508": + version "2.0.0-experimental.8618508" + resolved "https://registry.yarnpkg.com/@solana/codecs-core/-/codecs-core-2.0.0-experimental.8618508.tgz#4f6709dd50e671267f3bea7d09209bc6471b7ad0" + integrity sha512-JCz7mKjVKtfZxkuDtwMAUgA7YvJcA2BwpZaA1NOLcted4OMC4Prwa3DUe3f3181ixPYaRyptbF0Ikq2MbDkYEA== + +"@solana/codecs-core@2.0.0-preview.2": + version "2.0.0-preview.2" + resolved "https://registry.yarnpkg.com/@solana/codecs-core/-/codecs-core-2.0.0-preview.2.tgz#689784d032fbc1fedbde40bb25d76cdcecf6553b" + integrity sha512-gLhCJXieSCrAU7acUJjbXl+IbGnqovvxQLlimztPoGgfLQ1wFYu+XJswrEVQqknZYK1pgxpxH3rZ+OKFs0ndQg== + dependencies: + "@solana/errors" "2.0.0-preview.2" + +"@solana/codecs-data-structures@2.0.0-experimental.8618508": + version "2.0.0-experimental.8618508" + resolved "https://registry.yarnpkg.com/@solana/codecs-data-structures/-/codecs-data-structures-2.0.0-experimental.8618508.tgz#c16a704ac0f743a2e0bf73ada42d830b3402d848" + integrity sha512-sLpjL9sqzaDdkloBPV61Rht1tgaKq98BCtIKRuyscIrmVPu3wu0Bavk2n/QekmUzaTsj7K1pVSniM0YqCdnEBw== + dependencies: + "@solana/codecs-core" "2.0.0-experimental.8618508" + "@solana/codecs-numbers" "2.0.0-experimental.8618508" + +"@solana/codecs-data-structures@2.0.0-preview.2": + version "2.0.0-preview.2" + resolved "https://registry.yarnpkg.com/@solana/codecs-data-structures/-/codecs-data-structures-2.0.0-preview.2.tgz#e82cb1b6d154fa636cd5c8953ff3f32959cc0370" + integrity sha512-Xf5vIfromOZo94Q8HbR04TbgTwzigqrKII0GjYr21K7rb3nba4hUW2ir8kguY7HWFBcjHGlU5x3MevKBOLp3Zg== + dependencies: + "@solana/codecs-core" "2.0.0-preview.2" + "@solana/codecs-numbers" "2.0.0-preview.2" + "@solana/errors" "2.0.0-preview.2" + +"@solana/codecs-numbers@2.0.0-experimental.8618508": + version "2.0.0-experimental.8618508" + resolved "https://registry.yarnpkg.com/@solana/codecs-numbers/-/codecs-numbers-2.0.0-experimental.8618508.tgz#d84f9ed0521b22e19125eefc7d51e217fcaeb3e4" + integrity sha512-EXQKfzFr3CkKKNzKSZPOOOzchXsFe90TVONWsSnVkonO9z+nGKALE0/L9uBmIFGgdzhhU9QQVFvxBMclIDJo2Q== + dependencies: + "@solana/codecs-core" "2.0.0-experimental.8618508" + +"@solana/codecs-numbers@2.0.0-preview.2": + version "2.0.0-preview.2" + resolved "https://registry.yarnpkg.com/@solana/codecs-numbers/-/codecs-numbers-2.0.0-preview.2.tgz#56995c27396cd8ee3bae8bd055363891b630bbd0" + integrity sha512-aLZnDTf43z4qOnpTcDsUVy1Ci9im1Md8thWipSWbE+WM9ojZAx528oAql+Cv8M8N+6ALKwgVRhPZkto6E59ARw== + dependencies: + "@solana/codecs-core" "2.0.0-preview.2" + "@solana/errors" "2.0.0-preview.2" + +"@solana/codecs-strings@2.0.0-experimental.8618508": + version "2.0.0-experimental.8618508" + resolved "https://registry.yarnpkg.com/@solana/codecs-strings/-/codecs-strings-2.0.0-experimental.8618508.tgz#72457b884d9be80b59b263bcce73892b081e9402" + integrity sha512-b2yhinr1+oe+JDmnnsV0641KQqqDG8AQ16Z/x7GVWO+AWHMpRlHWVXOq8U1yhPMA4VXxl7i+D+C6ql0VGFp0GA== + dependencies: + "@solana/codecs-core" "2.0.0-experimental.8618508" + "@solana/codecs-numbers" "2.0.0-experimental.8618508" + +"@solana/codecs-strings@2.0.0-preview.2": + version "2.0.0-preview.2" + resolved "https://registry.yarnpkg.com/@solana/codecs-strings/-/codecs-strings-2.0.0-preview.2.tgz#8bd01a4e48614d5289d72d743c3e81305d445c46" + integrity sha512-EgBwY+lIaHHgMJIqVOGHfIfpdmmUDNoNO/GAUGeFPf+q0dF+DtwhJPEMShhzh64X2MeCZcmSO6Kinx0Bvmmz2g== + dependencies: + "@solana/codecs-core" "2.0.0-preview.2" + "@solana/codecs-numbers" "2.0.0-preview.2" + "@solana/errors" "2.0.0-preview.2" + +"@solana/codecs@2.0.0-preview.2": + version "2.0.0-preview.2" + resolved "https://registry.yarnpkg.com/@solana/codecs/-/codecs-2.0.0-preview.2.tgz#d6615fec98f423166fb89409f9a4ad5b74c10935" + integrity sha512-4HHzCD5+pOSmSB71X6w9ptweV48Zj1Vqhe732+pcAQ2cMNnN0gMPMdDq7j3YwaZDZ7yrILVV/3+HTnfT77t2yA== + dependencies: + "@solana/codecs-core" "2.0.0-preview.2" + "@solana/codecs-data-structures" "2.0.0-preview.2" + "@solana/codecs-numbers" "2.0.0-preview.2" + "@solana/codecs-strings" "2.0.0-preview.2" + "@solana/options" "2.0.0-preview.2" + +"@solana/errors@2.0.0-preview.2": + version "2.0.0-preview.2" + resolved "https://registry.yarnpkg.com/@solana/errors/-/errors-2.0.0-preview.2.tgz#e0ea8b008c5c02528d5855bc1903e5e9bbec322e" + integrity sha512-H2DZ1l3iYF5Rp5pPbJpmmtCauWeQXRJapkDg8epQ8BJ7cA2Ut/QEtC3CMmw/iMTcuS6uemFNLcWvlOfoQhvQuA== + dependencies: + chalk "^5.3.0" + commander "^12.0.0" + +"@solana/options@2.0.0-experimental.8618508": + version "2.0.0-experimental.8618508" + resolved "https://registry.yarnpkg.com/@solana/options/-/options-2.0.0-experimental.8618508.tgz#95385340e85f9e8a81b2bfba089404a61c8e9520" + integrity sha512-fy/nIRAMC3QHvnKi63KEd86Xr/zFBVxNW4nEpVEU2OT0gCEKwHY4Z55YHf7XujhyuM3PNpiBKg/YYw5QlRU4vg== + dependencies: + "@solana/codecs-core" "2.0.0-experimental.8618508" + "@solana/codecs-numbers" "2.0.0-experimental.8618508" + +"@solana/options@2.0.0-preview.2": + version "2.0.0-preview.2" + resolved "https://registry.yarnpkg.com/@solana/options/-/options-2.0.0-preview.2.tgz#13ff008bf43a5056ef9a091dc7bb3f39321e867e" + integrity sha512-FAHqEeH0cVsUOTzjl5OfUBw2cyT8d5Oekx4xcn5hn+NyPAfQJgM3CEThzgRD6Q/4mM5pVUnND3oK/Mt1RzSE/w== + dependencies: + "@solana/codecs-core" "2.0.0-preview.2" + "@solana/codecs-numbers" "2.0.0-preview.2" + +"@solana/spl-token-group@^0.0.2": + version "0.0.2" + resolved "https://registry.yarnpkg.com/@solana/spl-token-group/-/spl-token-group-0.0.2.tgz#23f754fd535a4df5e2b80293a03aabd58bd99167" + integrity sha512-vLePrFvT9+PfK2KZaddPebTWtRykXUR+060gqomFUcBk/2UPpZtsJGW+xshI9z9Ryrx7FieprZEUCApw34BwrQ== + dependencies: + "@solana/codecs" "2.0.0-preview.2" + "@solana/spl-type-length-value" "0.1.0" + +"@solana/spl-token-metadata@^0.1.2": + version "0.1.2" + resolved "https://registry.yarnpkg.com/@solana/spl-token-metadata/-/spl-token-metadata-0.1.2.tgz#876e13432bd2960bd3cac16b9b0af63e69e37719" + integrity sha512-hJYnAJNkDrtkE2Q41YZhCpeOGU/0JgRFXbtrtOuGGeKc3pkEUHB9DDoxZAxx+XRno13GozUleyBi0qypz4c3bw== + dependencies: + "@solana/codecs-core" "2.0.0-experimental.8618508" + "@solana/codecs-data-structures" "2.0.0-experimental.8618508" + "@solana/codecs-numbers" "2.0.0-experimental.8618508" + "@solana/codecs-strings" "2.0.0-experimental.8618508" + "@solana/options" "2.0.0-experimental.8618508" + "@solana/spl-type-length-value" "0.1.0" + +"@solana/spl-token@^0.4.3": + version "0.4.3" + resolved "https://registry.yarnpkg.com/@solana/spl-token/-/spl-token-0.4.3.tgz#cb923184fcba3f875f5914a440a68d7f537d0bac" + integrity sha512-mRjJJE9CIBejsg9WAmDp369pWeObm42K2fwsZ4dkJAMCt1KBPb5Eb1vzM5+AYfV/BUTy3QP2oFx8kV+8Doa1xQ== + dependencies: + "@solana/buffer-layout" "^4.0.0" + "@solana/buffer-layout-utils" "^0.2.0" + "@solana/spl-token-group" "^0.0.2" + "@solana/spl-token-metadata" "^0.1.2" + buffer "^6.0.3" + +"@solana/spl-type-length-value@0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@solana/spl-type-length-value/-/spl-type-length-value-0.1.0.tgz#b5930cf6c6d8f50c7ff2a70463728a4637a2f26b" + integrity sha512-JBMGB0oR4lPttOZ5XiUGyvylwLQjt1CPJa6qQ5oM+MBCndfjz2TKKkw0eATlLLcYmq1jBVsNlJ2cD6ns2GR7lA== + dependencies: + buffer "^6.0.3" + +"@solana/web3.js@^1.32.0": + version "1.91.3" + resolved "https://registry.yarnpkg.com/@solana/web3.js/-/web3.js-1.91.3.tgz#25b8b9dfd88bfa6441c0c02bbdb67abd32bfa0f4" + integrity sha512-Z6FZyW8SWm7RXW5ZSyr1kmpR+eH/F4DhgxV4WPaq5AbAAMnCiiGm36Jb7ACHFXtWzq1a24hBkJ1wnVANjsmdPA== + dependencies: + "@babel/runtime" "^7.23.4" + "@noble/curves" "^1.2.0" + "@noble/hashes" "^1.3.3" + "@solana/buffer-layout" "^4.0.1" + agentkeepalive "^4.5.0" + bigint-buffer "^1.1.5" + bn.js "^5.2.1" + borsh "^0.7.0" + bs58 "^4.0.1" + buffer "6.0.3" + fast-stable-stringify "^1.0.0" + jayson "^4.1.0" + node-fetch "^2.7.0" + rpc-websockets "^7.5.1" + superstruct "^0.14.2" + "@solana/web3.js@^1.68.0", "@solana/web3.js@^1.91.1": version "1.91.1" resolved "https://registry.yarnpkg.com/@solana/web3.js/-/web3.js-1.91.1.tgz#d49d2f982b52070be3b987fd8d892fcbddd064b5" @@ -2549,6 +2714,11 @@ bigint-buffer@^1.1.5: dependencies: bindings "^1.3.0" +bignumber.js@^9.0.1: + version "9.1.2" + resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.1.2.tgz#b7c4242259c008903b13707983b5f4bbd31eda0c" + integrity sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug== + bin-check@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/bin-check/-/bin-check-4.1.0.tgz#fc495970bdc88bb1d5a35fc17e65c4a149fc4a49" @@ -2705,7 +2875,7 @@ buffer-layout@^1.2.0, buffer-layout@^1.2.2: resolved "https://registry.yarnpkg.com/buffer-layout/-/buffer-layout-1.2.2.tgz#b9814e7c7235783085f9ca4966a0cfff112259d5" integrity sha512-kWSuLN694+KTk8SrYvCqwP2WcgQjoRCiF5b4QDvkkz8EmgD+aWAIceGFKMIAdmF/pH+vpgNV3d3kAKorcdAmWA== -buffer@6.0.3, buffer@~6.0.3: +buffer@6.0.3, buffer@^6.0.3, buffer@~6.0.3: version "6.0.3" resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== @@ -2809,6 +2979,11 @@ chalk@^4.0.0, chalk@^4.1.2: ansi-styles "^4.1.0" supports-color "^7.1.0" +chalk@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.3.0.tgz#67c20a7ebef70e7f3970a01f90fa210cb6860385" + integrity sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w== + char-regex@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" @@ -2894,6 +3069,11 @@ colorette@^2.0.20: resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== +commander@^12.0.0: + version "12.0.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-12.0.0.tgz#b929db6df8546080adfd004ab215ed48cf6f2592" + integrity sha512-MwVNWlYjDTtOjX5PiD7o5pK0UrFU/OYgcJfjjK4RaHZETNtjJqrZa9Y9ds88+A+f+d5lv+561eZ+yCKoS3gbAA== + commander@^2.20.3: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" diff --git a/frontend/claim_sdk/claim.ts b/frontend/claim_sdk/claim.ts index a8353018..fce8d12e 100644 --- a/frontend/claim_sdk/claim.ts +++ b/frontend/claim_sdk/claim.ts @@ -5,17 +5,7 @@ import { ethers } from 'ethers' import { base32decode, removeLeading0x } from './index' // Must be kept in line with the database types and the on-chain program -export type Ecosystem = - | 'discord' - | 'solana' - | 'evm' - | 'sui' - | 'algorand' - | 'aptos' - | 'terra' - | 'osmosis' - | 'injective' -export const Ecosystems: Ecosystem[] = [ +export const Ecosystems = [ 'discord', 'solana', 'evm', @@ -25,7 +15,8 @@ export const Ecosystems: Ecosystem[] = [ 'terra', 'osmosis', 'injective', -] +] as const +export type Ecosystem = typeof Ecosystems[number] export class ClaimInfo { constructor( @@ -56,16 +47,11 @@ export class ClaimInfo { } break } - case 'osmosis': - case 'terra': { - identityStruct = { - cosmwasm: { address: this.identity }, - } - break - } - case 'injective': { + case 'sui': { identityStruct = { - injective: { address: this.identity }, + sui: { + address: Buffer.from(removeLeading0x(this.identity), 'hex'), + }, } break } @@ -77,11 +63,16 @@ export class ClaimInfo { } break } - case 'sui': { + case 'terra': + case 'osmosis': { identityStruct = { - sui: { - address: Buffer.from(removeLeading0x(this.identity), 'hex'), - }, + cosmwasm: { address: this.identity }, + } + break + } + case 'injective': { + identityStruct = { + injective: { address: this.identity }, } break } diff --git a/frontend/claim_sdk/cu_estimate.ts.txt b/frontend/claim_sdk/cu_estimate.ts.txt new file mode 100644 index 00000000..87e30ed7 --- /dev/null +++ b/frontend/claim_sdk/cu_estimate.ts.txt @@ -0,0 +1,883 @@ +//csv data that derives the actual compute cost numbers +// Saved with formulas - can be loaded into open office. +// Uses typescript code below to determine bumps and subtracts bump derivation +// costs to estimate raw program execution costs. +// This file represents an 80-20 clean-up. It's just clean enough so one can +// go back and figure out how things were derived in the first place without +// spending any additional time/energy on it now. +// +// ,ata init in prog,only deriv,ata creation,,separate,normal deriv,,,Program +// 255,33220,7246,20460,=B2-C2,=B2-C2+806,0,,1,waNTLJXETasWVTP1qj84Zs6h7XY8qvzqmKd1QWqxyLB +// =A2-1,=B2+4500,=C2+1500,=D2+1500,=B3-C3,=F2+4500,=G2+1500,,2,WA6TpiY1gcAxRAjz5rQeVeZzgHtJKSnRZsJoocFCEGU +// =A3-1,=B3+4500,=C3+1500,=D3+1500,=B4-C4,=F3+4500,=G3+1500,,3,WAPGu4AoTGCYbp1iXnZTpBn89VkJNJX3jY7uPuUZAv7 +// =A4-1,=B4+4500,=C4+1500,=D4+1500,=B5-C5,=F4+4500,=G4+1500,,, +// =A5-1,=B5+4500,=C5+1500,=D5+1500,=B6-C6,=F5+4500,=G5+1500,,, +// =A6-1,=B6+4500,=C6+1500,=D6+1500,=B7-C7,=F6+4500,=G6+1500,,, +// =A7-1,=B7+4500,=C7+1500,=D7+1500,=B8-C8,=F7+4500,=G7+1500,,, +// =A8-1,=B8+4500,=C8+1500,=D8+1500,=B9-C9,=F8+4500,=G8+1500,,, +// =A9-1,=B9+4500,=C9+1500,=D9+1500,=B10-C10,=F9+4500,=G9+1500,,, +// =A10-1,=B10+4500,=C10+1500,=D10+1500,=B11-C11,=F10+4500,=G10+1500,,, +// ,,,,,col above is empirical,,,, +// program,discord:,,,,,,,, +// 1,88876,=F6,=G2,=B14-C14-D14,3PYnssaWxjCXRQYBZHXsowJSCEaYHd1McH2GT3v5Jk7GaxbMCNRC54FF5qnpoPt1dkik8GgzJEhyJG4RQcd5mSCi,,,, +// 1,72451,=F2,=G3,=B15-C15-D15,U2zuQn7sDkNz6NZMVrEqTjPqNHG4zWDLqHh8CVuhqGutCr8WZ5eqqmLhTjZmhkMCZNLxRjJ3RhR7fTUGkJAHd1E,,,, +// 1,76954,=F3,=G3,=B16-C16-D16,573ui4vx3Avd8WpANYeUYwNdhcyj4FfY5P6QYRKPfrWNsqTaYRjzh2259J3tAQA6g1EctTfCsT5vzLtQNQhCQko4,,,, +// 1,47036,0,3000,=B17-C17-D17,4ERr2CdGa4ZmmVv4He8wmQXRzxjeGqpvEWFfSFoPbB7ohxGozJBc2vs9hZrKwWDXSQstint9LWc7poLYUuEt6GUu,,,, +// ,,,,,,,,, +// ,evm:,,,,,,,, +// 1,67976,0,=G3,=B20-C20-D20,3w4NM3fqxn2AfDa6c3P2kHsa2WzqQzbN3zH1wAVh63VYiFuHmKWDDk94Scgbjx6YGRJANVXStytXa9DjYRKVWpwZ,,,, +// 1,68024,0,=G3,=B21-C21-D21,2ZoVWD1ToZVswUtkRDkPRAHzZGVGwgH66tfxLbswrJxnCcZjhYwsFCaZEsV2BWPBueh9TKB1UAFmkm82DKPKRoo9,,,, +// 1,68021,0,=G3,=B22-C22-D22,jucMMWFaafZD3F8MRutRJVkoqMfgzW53VHxRf5Jh79aBDGX7uwEDW1R4uDkSy3aVvRzoigSSRbatYDw5RijTDqp,,,, +// 1,75482,0,=G8,=B23-C23-D23,3vyc2UPgCiPT67mHTDjpiKmHPLQukGtp44GbmBpVVKV85nZyTba2xKtN9ZKRJdxVTuLSJuHwA1u1kwKWBRJsiFXT,,,, +// 1,93346,=F2,=G2,=B24-C24-D24,4BfPPiHHm7Neq2utLb4zqKqAXWnz6nzAi8quRAwpRaaNXrcvQo3Ny99PzRjSULYmxNc8gzcYRS66FL1hVRjSG8bk,,,, +// 1,66446,0,=G2,=B25-C25-D25,4zKUWGufk9WZpGpNxVSU9QFTo44QKAQsM6Qf5YEBRg4fNZqJc1eckQUUjue3LXA8WAAAEECQth8KKrkHTMsHcFQX,,,, +// 1,93265,=F2,=G2,=B26-C26-D26,2W39xBYrMkuPYfBtuYizp9FmWzWQduwhF7xn8nfgtD534z5bmkcX8YyyGRzyehg1uiaDfgJ5o3YnL4k7yNjHKVbS,,,, +// 2,93239,=F2,=G2,=B27-C27-D27,5YjAyoDd8m8bmc7zD17imJWYRc4dg2HeyVWSL48i3647moJfontGmJwU7snpDTc4MqiqQx6AdMEW7rGeUQfzgW6e,,,, +// 2,96106,=F2,=G4,=B28-C28-D28,hPruXEKJXFiwDNuLKqQuHt1BsygbdZHST4LXh9E52Bv2MusCzmC3S3ZAFvANjfjKkXBV7fedP3iMeDUpp8N5K52,,,, +// 2,93294,=F2,=G2,=B29-C29-D29,ouVLq5CMmrU76jghoEYFGjSivzf6noiVLqegUfjYEurgb9rRdnqqjzNcVXQUyWXttuuhoW9pV6yFVFBkjcNUMpr,,,, +// 2,97651,=F2,=G5,=B30-C30-D30,4zG76KQU3QZdpZEvfHQwfSwtN45LhM3ipPqxd58BTmvBdVxAGSMBs5QwL7dTHmBrksn9wp7z28GPMKhKBTf3skfp,,,, +// 2,102278,=F4,=G2,=B31-C31-D31,3pfztkbaUsHgpdNqwoAdAHksbs86y3odDn3tmyWjNRk5nyuHESCrYWddmqursKZStb94FQ7DrUg4wfgi1tuUMPgC,,,, +// 2,117200,=F7,=G3,=B32-C32-D32,3KoMAff3MuuoMRP2jhZCaCvBRfKHumaWG8Mmc1xbpQQYHwDkF28PphiWxS3tc5wTnwP1nT67LvNGYd6UdJeRbFXH,,,, +// ,,,,,,,,, +// ,solana:,,,,,,,, +// 2,73225,=F3,=G3,=B35-C35-D35,D1G125KsundqAvP9yGvbh5mr2tkYFik3o41kAQJTkQmz9GtVFKC6HK4Qd22sA7RRA3uWVGvRkr4PRZXUHnitMEZ,,,, +// 2,47945,0,=G7,=B36-C36-D36,3C4UNJLx71GSRCiJQ5b4LyW2DJrmvXsaNH7tidWdwZYrLQ2z7yufzTY8ssfV9asDzyzgpe4XkEicLqdL9pLyGPwx,,,, +// 2,44948,=G4,=G3,=B37-C37-D37,4uWbYwSZ5g3mBC2doAQVQJ9foRuBgXUf9sa1SteLdaU5zWB9WhvBmpPXgji2u8RBKfa3xLhPJmJLEdxx6YabL4Gw,,,, +// 2,50948,=G7,=G4,=B38-C38-D38,34vrzPudC4kZ4rsPSjjZG9pZRxxgeeV9KmSbbufMuwTXowoFcS7QuEtMDQwMNF4cygxRnB8uCGpvKBwF8ELpgcin,,,, +// 2,67222,=F2,=G2,=B39-C39-D39,5UURwBtJW8G4dQQh6qh6B4WmNP8NsiiCDVYuz4ydy5pyfqbBp3SWCXbAzZhVWygVnZsju5n4ZyT8BucebRz5UaUs,,,, +// 2,82225,=F4,=G6,=B40-C40-D40,5KkvmT5PrGv2xUmNyw1te6rJtjMQdNHEA8dydEsY2ECD9yubGoyLgUe1tEb8f7wfzgMveNbsPfyPKpbvti44bHMa,,,, +// ,,,,,,,,, +// ,aptos:,,,,,,,, +// 1,78710,=G2,=G2,=B43-C43-D43,58e2fgsMAtwxNvv3wVRWbJuJdnwFx2thXxyEdtF5ZgeHq5g5FMD5m5fCbbhjEV4BpZD8kkt3wy1Nj1FuTAsyJehP,,,, +// 2,81645,=G4,=G2,=B44-C44-D44,bGbB8ugagCavqPFBSvTCat9GCD8Kqz3J317dYW2STAmzPs9xMkXLgehUyr1PSutT3H5PoZZyyUayPTJHaS3eNUs,,,, +// 2,87570,=G7,=G3,=B45-C45-D45,3w5hkXCKY2uy4tATGu457An8uBrZ1hB85Vw2hcmULqgESBZdX81WqNCuFzVH7v2Wc7EmQz8PeyuguSFBReH918nR,,,, +// ,,,,,,,,, +// ,sui:,,,,,,,, +// 2,88122,=G4,=G6,=B48-C48-D48,5zy8wHfF3GMdPu9kLvyTBg46TszMxuRAoeBrcfYjbuxpnKw1TdEqnRFak7H9AKy523J653PEcHXjF2AmdMgh6sQf,,,, +// 3,79025,=G2,=G2,=B49-C49-D49,3JQapHPhJAvfEq2UV9ywnmaSLPDrzQtNrJPudqSmXBpUmf6N5svAQWWKTbKVHYNp4ZoEAnY1hr3ibfvB2WpBkABD,,,, +// ,,,,,,,,, +// ,cosmos:,,,,,,,, +// 1,116139,0,=G4,=B52-C52-D52,3be6wQGM8FdDLMZm63r9YSMeXTZsAskrKvLKopDDCX8EHmCnjc9GGM28ArJRFRcs6uov7i3nSeKod4HsjtQ6swUS,,,, +// 2,117609,=G4,=G3,=B53-C53-D53,3tqaAQBYmvHS2Dri9q1Fcg5SPBTBvaqWxqcMKiGyuuE8DJJXBZfH8dpxv1FGz5SYJV6SKoU75M7VtNLBkteCQn15,,,, +// 2,116074,=G4,=G2,=B54-C54-D54,4m5Lm9PcLY9r5RdYrFfpVdn9H9bxYSRnXrZxjoK4L3PL5j5WQfbm2fLNt8JRUVSQSCruT98eUdooTmbg4JAk7vxP,,,, +// 3,144331,=F2,=G5,=B55-C55-D55,5i7xkSQjnar5vNTKddSdL6aVxuYD44Q1etYynfJuV2VFsQqcTGpfPeeo6qJqkWfDSGfP6fX9XWhaN6p8wTBiAfcF,,,, +// ,,,,,,,,, +// ,terra:,,,,,,,, +// 1,113377,=G2,=G2,=B58-C58-D58,258c3CH8aHktZUUCtJHR8QNqEv5L1QaJB39YPs64dpt6ByeH84mB4xWw9tMEkJD6dcnys4iUuasnJfhpMED7Ge6z,,,, +// 1,141381,=F2,=G3,=B59-C59-D59,23HfzzuQBjSUDkLtM1VXeji3oT7ymDm6i8psudVuyxhkgedKEiVzqrpzsGT68ut5d9Qn2EdHNvT5aoaXQoQwRaDm,,,, +// 2,116350,=G4,=G2,=B60-C60-D60,wLcgmj3mhtrjjdinCJJgbYioiaiuNnrTWqTiKpDpC9x6AvSMn6KzTEWXB89VoPk7D5vCEcQvTwyWwkRCaqCHWgm,,,, +// 2,117853,=G4,=G3,=B61-C61-D61,4P65T1mw1YYgY53Xcyuu373MMoFCDzro8j2YWjMx6anY86XQ6F1qvrpZtLK5a1fAntyB7bBdfZ2NryAs8jBttn2J,,,, +// ,,,,,,,,, +// ,injective:,,,,,,,, +// 1,73155,0,=G3,=B64-C64-D64,5R1GrqETt7Cr5ebNhzAVX9SgvmToo8ZoL7t3n2nZUoCDnMFC7yRsp7sjqF9UVX6zug8fKS2PADZaTMFKSt2Ltawf,,,, +// 2,76147,=G4,=G3,=B65-C65-D65,5xRyfymFQBL6hKgACFfsxkhEy9Jbxmja236P7VgwKHgVgNAZqmw3yLwST4CiADWKTkA75iuLc8YJN3Tsm8XfkMRm,,,, +// ,,,,,,,,, +// ,algorand,,,,,,,, +// 3,70590,=G2,=G2,=B68-C68-D68,2LCat1JPttHvrzTUUXwLz4YGx5gWszQpoHcz9cQuXpuFX1b6pFdfx3CV9yyexrwv4gZh5YnSUJiaGyoFEU5TaQnN,,,, + +//############################################################################# + +// program output: + +// tx: 3PYnssaWxjCXRQYBZHXsowJSCEaYHd1McH2GT3v5Jk7GaxbMCNRC54FF5qnpoPt1dkik8GgzJEhyJG4RQcd5mSCi +// program: waNTLJXETasWVTP1qj84Zs6h7XY8qvzqmKd1QWqxyLB +// ata: 9DSf7q55crkvaCMKFNh6MkFy3K9ab2TAxCPxpkoHLu2m +// xpct: 9DSf7q55crkvaCMKFNh6MkFy3K9ab2TAxCPxpkoHLu2m +// bump: 251 +// rPda: MuNQAviUg6ZFvWp9Ft5PHchiMHeWE99mqw5zyMQzm7x +// xpct: MuNQAviUg6ZFvWp9Ft5PHchiMHeWE99mqw5zyMQzm7x +// bump: 255 +// ================================================================================ +// tx: U2zuQn7sDkNz6NZMVrEqTjPqNHG4zWDLqHh8CVuhqGutCr8WZ5eqqmLhTjZmhkMCZNLxRjJ3RhR7fTUGkJAHd1E +// program: waNTLJXETasWVTP1qj84Zs6h7XY8qvzqmKd1QWqxyLB +// ata: 3xwGBStS3QX5hGmxweKaZgPK7QTLcEJG7YV2XYKGB3jr +// xpct: 3xwGBStS3QX5hGmxweKaZgPK7QTLcEJG7YV2XYKGB3jr +// bump: 255 +// rPda: BoSoN8zrkjva2BqaPnoshkhLB1AxLz6oe76x1zMo87X5 +// xpct: BoSoN8zrkjva2BqaPnoshkhLB1AxLz6oe76x1zMo87X5 +// bump: 254 +// ================================================================================ +// tx: 573ui4vx3Avd8WpANYeUYwNdhcyj4FfY5P6QYRKPfrWNsqTaYRjzh2259J3tAQA6g1EctTfCsT5vzLtQNQhCQko4 +// program: waNTLJXETasWVTP1qj84Zs6h7XY8qvzqmKd1QWqxyLB +// ata: qYSg66vZNiAEy8k2SXBgxjnwiR8MR8N6vSP6YJWg73n +// xpct: qYSg66vZNiAEy8k2SXBgxjnwiR8MR8N6vSP6YJWg73n +// bump: 254 +// rPda: G9cpkCBzMcp7h3dZN6wLT8mRX8iDB4m8gd4T3cumHLdw +// xpct: G9cpkCBzMcp7h3dZN6wLT8mRX8iDB4m8gd4T3cumHLdw +// bump: 254 +// ================================================================================ +// tx: 4ERr2CdGa4ZmmVv4He8wmQXRzxjeGqpvEWFfSFoPbB7ohxGozJBc2vs9hZrKwWDXSQstint9LWc7poLYUuEt6GUu +// program: waNTLJXETasWVTP1qj84Zs6h7XY8qvzqmKd1QWqxyLB +// ata: 27VpCTrNdKAcsWE72gxxBPBFXAGcAMLgbPaLLyQXfzHk +// xpct: 27VpCTrNdKAcsWE72gxxBPBFXAGcAMLgbPaLLyQXfzHk +// bump: 255 +// rPda: 2FSYp5oRWcUtCjBrij49YL7BZXiugknE2pEdFJAgdWdr +// xpct: 2FSYp5oRWcUtCjBrij49YL7BZXiugknE2pEdFJAgdWdr +// bump: 253 +// ================================================================================ +// tx: 3w4NM3fqxn2AfDa6c3P2kHsa2WzqQzbN3zH1wAVh63VYiFuHmKWDDk94Scgbjx6YGRJANVXStytXa9DjYRKVWpwZ +// program: waNTLJXETasWVTP1qj84Zs6h7XY8qvzqmKd1QWqxyLB +// ata: 8zfuxc7A4qw6UBYTU8nnmymfAPzxyQPiMNcTfea8oS3 +// xpct: 8zfuxc7A4qw6UBYTU8nnmymfAPzxyQPiMNcTfea8oS3 +// bump: 255 +// rPda: 3yqmGaXpcGfavuL4SVwrffAuH48kL9oS2bLAN86TQ58Q +// xpct: 3yqmGaXpcGfavuL4SVwrffAuH48kL9oS2bLAN86TQ58Q +// bump: 254 +// ================================================================================ +// tx: 2ZoVWD1ToZVswUtkRDkPRAHzZGVGwgH66tfxLbswrJxnCcZjhYwsFCaZEsV2BWPBueh9TKB1UAFmkm82DKPKRoo9 +// program: waNTLJXETasWVTP1qj84Zs6h7XY8qvzqmKd1QWqxyLB +// ata: G8P8sNvyZeSurzntNEBKUdYuhfZXDGyZLhQqNF3SY2sD +// xpct: G8P8sNvyZeSurzntNEBKUdYuhfZXDGyZLhQqNF3SY2sD +// bump: 255 +// rPda: 4yhfTbWg7cyucVRPzftSoyhqetv9urjpJwgFBNrpvdRG +// xpct: 4yhfTbWg7cyucVRPzftSoyhqetv9urjpJwgFBNrpvdRG +// bump: 254 +// ================================================================================ +// tx: jucMMWFaafZD3F8MRutRJVkoqMfgzW53VHxRf5Jh79aBDGX7uwEDW1R4uDkSy3aVvRzoigSSRbatYDw5RijTDqp +// program: waNTLJXETasWVTP1qj84Zs6h7XY8qvzqmKd1QWqxyLB +// ata: G8P8sNvyZeSurzntNEBKUdYuhfZXDGyZLhQqNF3SY2sD +// xpct: G8P8sNvyZeSurzntNEBKUdYuhfZXDGyZLhQqNF3SY2sD +// bump: 255 +// rPda: 7yXVeoRk7C5HV6vMWrbtRr73kREviv79YPUAcSKQC3Bc +// xpct: 7yXVeoRk7C5HV6vMWrbtRr73kREviv79YPUAcSKQC3Bc +// bump: 254 +// ================================================================================ +// tx: 3vyc2UPgCiPT67mHTDjpiKmHPLQukGtp44GbmBpVVKV85nZyTba2xKtN9ZKRJdxVTuLSJuHwA1u1kwKWBRJsiFXT +// program: waNTLJXETasWVTP1qj84Zs6h7XY8qvzqmKd1QWqxyLB +// ata: 8zfuxc7A4qw6UBYTU8nnmymfAPzxyQPiMNcTfea8oS3 +// xpct: 8zfuxc7A4qw6UBYTU8nnmymfAPzxyQPiMNcTfea8oS3 +// bump: 255 +// rPda: 9jVoQgUwrKAeQ864jKd2onJ87c6WB34GcZ2D6PaQo28f +// xpct: 9jVoQgUwrKAeQ864jKd2onJ87c6WB34GcZ2D6PaQo28f +// bump: 249 +// ================================================================================ +// tx: 4BfPPiHHm7Neq2utLb4zqKqAXWnz6nzAi8quRAwpRaaNXrcvQo3Ny99PzRjSULYmxNc8gzcYRS66FL1hVRjSG8bk +// program: waNTLJXETasWVTP1qj84Zs6h7XY8qvzqmKd1QWqxyLB +// ata: G8P8sNvyZeSurzntNEBKUdYuhfZXDGyZLhQqNF3SY2sD +// xpct: G8P8sNvyZeSurzntNEBKUdYuhfZXDGyZLhQqNF3SY2sD +// bump: 255 +// rPda: F59qKVTV3cQLpc6PBE9fMDDRtbEx4LHQXbrS6ERF3NLs +// xpct: F59qKVTV3cQLpc6PBE9fMDDRtbEx4LHQXbrS6ERF3NLs +// bump: 255 +// ================================================================================ +// tx: 4zKUWGufk9WZpGpNxVSU9QFTo44QKAQsM6Qf5YEBRg4fNZqJc1eckQUUjue3LXA8WAAAEECQth8KKrkHTMsHcFQX +// program: waNTLJXETasWVTP1qj84Zs6h7XY8qvzqmKd1QWqxyLB +// ata: 27VpCTrNdKAcsWE72gxxBPBFXAGcAMLgbPaLLyQXfzHk +// xpct: 27VpCTrNdKAcsWE72gxxBPBFXAGcAMLgbPaLLyQXfzHk +// bump: 255 +// rPda: 2iDPhgaeiY6XCiHqMJUwhotd1F14bWV61ub6MuHyupCq +// xpct: 2iDPhgaeiY6XCiHqMJUwhotd1F14bWV61ub6MuHyupCq +// bump: 255 +// ================================================================================ +// tx: 2W39xBYrMkuPYfBtuYizp9FmWzWQduwhF7xn8nfgtD534z5bmkcX8YyyGRzyehg1uiaDfgJ5o3YnL4k7yNjHKVbS +// program: waNTLJXETasWVTP1qj84Zs6h7XY8qvzqmKd1QWqxyLB +// ata: 27VpCTrNdKAcsWE72gxxBPBFXAGcAMLgbPaLLyQXfzHk +// xpct: 27VpCTrNdKAcsWE72gxxBPBFXAGcAMLgbPaLLyQXfzHk +// bump: 255 +// rPda: 6PLAcgp3vin44ov4JTcpbUcD512UpN42wFDKHV8yzAfG +// xpct: 6PLAcgp3vin44ov4JTcpbUcD512UpN42wFDKHV8yzAfG +// bump: 255 +// ================================================================================ +// tx: 58e2fgsMAtwxNvv3wVRWbJuJdnwFx2thXxyEdtF5ZgeHq5g5FMD5m5fCbbhjEV4BpZD8kkt3wy1Nj1FuTAsyJehP +// program: waNTLJXETasWVTP1qj84Zs6h7XY8qvzqmKd1QWqxyLB +// ata: G8P8sNvyZeSurzntNEBKUdYuhfZXDGyZLhQqNF3SY2sD +// xpct: G8P8sNvyZeSurzntNEBKUdYuhfZXDGyZLhQqNF3SY2sD +// bump: 255 +// rPda: AfMmHhKn5WNyD4FhpswpHYMS1a4w9wZGP435GmdCNSjU +// xpct: AfMmHhKn5WNyD4FhpswpHYMS1a4w9wZGP435GmdCNSjU +// bump: 255 +// ================================================================================ +// tx: 3be6wQGM8FdDLMZm63r9YSMeXTZsAskrKvLKopDDCX8EHmCnjc9GGM28ArJRFRcs6uov7i3nSeKod4HsjtQ6swUS +// program: waNTLJXETasWVTP1qj84Zs6h7XY8qvzqmKd1QWqxyLB +// ata: G8P8sNvyZeSurzntNEBKUdYuhfZXDGyZLhQqNF3SY2sD +// xpct: G8P8sNvyZeSurzntNEBKUdYuhfZXDGyZLhQqNF3SY2sD +// bump: 255 +// rPda: 3Rz3KUin6XQ7L7oa8eG7mHnb2jaKTcbzWcyQz63GLtE5 +// xpct: 3Rz3KUin6XQ7L7oa8eG7mHnb2jaKTcbzWcyQz63GLtE5 +// bump: 253 +// ================================================================================ +// tx: 258c3CH8aHktZUUCtJHR8QNqEv5L1QaJB39YPs64dpt6ByeH84mB4xWw9tMEkJD6dcnys4iUuasnJfhpMED7Ge6z +// program: waNTLJXETasWVTP1qj84Zs6h7XY8qvzqmKd1QWqxyLB +// ata: 8zfuxc7A4qw6UBYTU8nnmymfAPzxyQPiMNcTfea8oS3 +// xpct: 8zfuxc7A4qw6UBYTU8nnmymfAPzxyQPiMNcTfea8oS3 +// bump: 255 +// rPda: G2ETsQseMyKRr4AHqC9CjVgHMhQmNjKs5TazY9gm4G7q +// xpct: G2ETsQseMyKRr4AHqC9CjVgHMhQmNjKs5TazY9gm4G7q +// bump: 255 +// ================================================================================ +// tx: 23HfzzuQBjSUDkLtM1VXeji3oT7ymDm6i8psudVuyxhkgedKEiVzqrpzsGT68ut5d9Qn2EdHNvT5aoaXQoQwRaDm +// program: waNTLJXETasWVTP1qj84Zs6h7XY8qvzqmKd1QWqxyLB +// ata: 8zfuxc7A4qw6UBYTU8nnmymfAPzxyQPiMNcTfea8oS3 +// xpct: 8zfuxc7A4qw6UBYTU8nnmymfAPzxyQPiMNcTfea8oS3 +// bump: 255 +// rPda: 3vT15aYxTQrmNtkQjShQBjNrNvVe8Ya6mypz6gem1QB9 +// xpct: 3vT15aYxTQrmNtkQjShQBjNrNvVe8Ya6mypz6gem1QB9 +// bump: 254 +// ================================================================================ +// tx: 5R1GrqETt7Cr5ebNhzAVX9SgvmToo8ZoL7t3n2nZUoCDnMFC7yRsp7sjqF9UVX6zug8fKS2PADZaTMFKSt2Ltawf +// program: waNTLJXETasWVTP1qj84Zs6h7XY8qvzqmKd1QWqxyLB +// ata: 8zfuxc7A4qw6UBYTU8nnmymfAPzxyQPiMNcTfea8oS3 +// xpct: 8zfuxc7A4qw6UBYTU8nnmymfAPzxyQPiMNcTfea8oS3 +// bump: 255 +// rPda: 6NpXeEjWCPD447ii9x2qFSv2Mhmq19xmYKqTqXtFx5sJ +// xpct: 6NpXeEjWCPD447ii9x2qFSv2Mhmq19xmYKqTqXtFx5sJ +// bump: 254 +// ================================================================================ +// tx: 5YjAyoDd8m8bmc7zD17imJWYRc4dg2HeyVWSL48i3647moJfontGmJwU7snpDTc4MqiqQx6AdMEW7rGeUQfzgW6e +// program: WA6TpiY1gcAxRAjz5rQeVeZzgHtJKSnRZsJoocFCEGU +// ata: 5UxD8NmcV9oLLUuKDqU15npkzuCPfbcXS4nWQGAbg7VG +// xpct: 5UxD8NmcV9oLLUuKDqU15npkzuCPfbcXS4nWQGAbg7VG +// bump: 255 +// rPda: CJzucTLaguyM3m6RWiCQYgYUt8XXEAvQeCGRzQK5LPCa +// xpct: CJzucTLaguyM3m6RWiCQYgYUt8XXEAvQeCGRzQK5LPCa +// bump: 255 +// ================================================================================ +// tx: hPruXEKJXFiwDNuLKqQuHt1BsygbdZHST4LXh9E52Bv2MusCzmC3S3ZAFvANjfjKkXBV7fedP3iMeDUpp8N5K52 +// program: WA6TpiY1gcAxRAjz5rQeVeZzgHtJKSnRZsJoocFCEGU +// ata: FXfJuWZryWAK2WTBGoqjuYSGqHAKbb4vfuRFD8UctCaZ +// xpct: FXfJuWZryWAK2WTBGoqjuYSGqHAKbb4vfuRFD8UctCaZ +// bump: 255 +// rPda: CRLwFwFpWcACmKCKQfJx98WH16iynjq51DwxadXkczAe +// xpct: CRLwFwFpWcACmKCKQfJx98WH16iynjq51DwxadXkczAe +// bump: 253 +// ================================================================================ +// tx: ouVLq5CMmrU76jghoEYFGjSivzf6noiVLqegUfjYEurgb9rRdnqqjzNcVXQUyWXttuuhoW9pV6yFVFBkjcNUMpr +// program: WA6TpiY1gcAxRAjz5rQeVeZzgHtJKSnRZsJoocFCEGU +// ata: EWfpdfTnnAdSKifqQprmCrG1VmoTYi9aDZkaW6JsxBWZ +// xpct: EWfpdfTnnAdSKifqQprmCrG1VmoTYi9aDZkaW6JsxBWZ +// bump: 255 +// rPda: A9TieXKjC7rbVHwHEf8hLwx73vPTR1Wo5oyQnD74vxb +// xpct: A9TieXKjC7rbVHwHEf8hLwx73vPTR1Wo5oyQnD74vxb +// bump: 255 +// ================================================================================ +// tx: 3pfztkbaUsHgpdNqwoAdAHksbs86y3odDn3tmyWjNRk5nyuHESCrYWddmqursKZStb94FQ7DrUg4wfgi1tuUMPgC +// program: WA6TpiY1gcAxRAjz5rQeVeZzgHtJKSnRZsJoocFCEGU +// ata: 9aUgQeZ3ZABcyBPRodU7Z3pSUZva1xPVviavTLLBG4T5 +// xpct: 9aUgQeZ3ZABcyBPRodU7Z3pSUZva1xPVviavTLLBG4T5 +// bump: 253 +// rPda: BsSvBXZjhYtBdtrLoy7JQayrTJGgaN6adXqwGdTRSQV9 +// xpct: BsSvBXZjhYtBdtrLoy7JQayrTJGgaN6adXqwGdTRSQV9 +// bump: 255 +// ================================================================================ +// tx: 3KoMAff3MuuoMRP2jhZCaCvBRfKHumaWG8Mmc1xbpQQYHwDkF28PphiWxS3tc5wTnwP1nT67LvNGYd6UdJeRbFXH +// program: WA6TpiY1gcAxRAjz5rQeVeZzgHtJKSnRZsJoocFCEGU +// ata: Ho62P3iPQ5W5et98dcMqGA8YwEqhqAFqfaiHGZL62Lha +// xpct: Ho62P3iPQ5W5et98dcMqGA8YwEqhqAFqfaiHGZL62Lha +// bump: 250 +// rPda: BaaKy8BM6zWBZr2NjinqGdPEjEuw8XyqUUVTWcmANW8u +// xpct: BaaKy8BM6zWBZr2NjinqGdPEjEuw8XyqUUVTWcmANW8u +// bump: 254 +// ================================================================================ +// tx: 4zG76KQU3QZdpZEvfHQwfSwtN45LhM3ipPqxd58BTmvBdVxAGSMBs5QwL7dTHmBrksn9wp7z28GPMKhKBTf3skfp +// program: WA6TpiY1gcAxRAjz5rQeVeZzgHtJKSnRZsJoocFCEGU +// ata: CWR8XKuSXHjMsyB9TBTMov7DboNYAMVpXbEVEHd5at67 +// xpct: CWR8XKuSXHjMsyB9TBTMov7DboNYAMVpXbEVEHd5at67 +// bump: 255 +// rPda: 9pq3NZ88s4y4JYPg59QRPpt82KxJhefCsLvZGYzCdyk5 +// xpct: 9pq3NZ88s4y4JYPg59QRPpt82KxJhefCsLvZGYzCdyk5 +// bump: 252 +// ================================================================================ +// tx: D1G125KsundqAvP9yGvbh5mr2tkYFik3o41kAQJTkQmz9GtVFKC6HK4Qd22sA7RRA3uWVGvRkr4PRZXUHnitMEZ +// program: WA6TpiY1gcAxRAjz5rQeVeZzgHtJKSnRZsJoocFCEGU +// ata: 5RLGgSF8azFHcKUaJbF4kKjqEtbviW2hbrmvhbL1nvfm +// xpct: 5RLGgSF8azFHcKUaJbF4kKjqEtbviW2hbrmvhbL1nvfm +// bump: 254 +// rPda: 5e8CC6qhMfYnRTLM7Ay4bKNcajaJhfjCFPhng5SZvPrT +// xpct: 5e8CC6qhMfYnRTLM7Ay4bKNcajaJhfjCFPhng5SZvPrT +// bump: 254 +// ================================================================================ +// tx: 3C4UNJLx71GSRCiJQ5b4LyW2DJrmvXsaNH7tidWdwZYrLQ2z7yufzTY8ssfV9asDzyzgpe4XkEicLqdL9pLyGPwx +// program: WA6TpiY1gcAxRAjz5rQeVeZzgHtJKSnRZsJoocFCEGU +// ata: CWR8XKuSXHjMsyB9TBTMov7DboNYAMVpXbEVEHd5at67 +// xpct: CWR8XKuSXHjMsyB9TBTMov7DboNYAMVpXbEVEHd5at67 +// bump: 255 +// rPda: E8KBxNHwo33zBHozUH9nxKWxCbd5bsDrMyz4p7UzPuwk +// xpct: E8KBxNHwo33zBHozUH9nxKWxCbd5bsDrMyz4p7UzPuwk +// bump: 250 +// ================================================================================ +// tx: 4uWbYwSZ5g3mBC2doAQVQJ9foRuBgXUf9sa1SteLdaU5zWB9WhvBmpPXgji2u8RBKfa3xLhPJmJLEdxx6YabL4Gw +// program: WA6TpiY1gcAxRAjz5rQeVeZzgHtJKSnRZsJoocFCEGU +// ata: 9aUgQeZ3ZABcyBPRodU7Z3pSUZva1xPVviavTLLBG4T5 +// xpct: 9aUgQeZ3ZABcyBPRodU7Z3pSUZva1xPVviavTLLBG4T5 +// bump: 253 +// rPda: 9VqJfhmY16uWUF19g68kvVLCmje8KhR8qnxQhcG7ysnF +// xpct: 9VqJfhmY16uWUF19g68kvVLCmje8KhR8qnxQhcG7ysnF +// bump: 254 +// ================================================================================ +// tx: 34vrzPudC4kZ4rsPSjjZG9pZRxxgeeV9KmSbbufMuwTXowoFcS7QuEtMDQwMNF4cygxRnB8uCGpvKBwF8ELpgcin +// program: WA6TpiY1gcAxRAjz5rQeVeZzgHtJKSnRZsJoocFCEGU +// ata: Ho62P3iPQ5W5et98dcMqGA8YwEqhqAFqfaiHGZL62Lha +// xpct: Ho62P3iPQ5W5et98dcMqGA8YwEqhqAFqfaiHGZL62Lha +// bump: 250 +// rPda: BeQ4xQAYV8wVNw6Mz17YLkJS5KPC7zMn6BJAW5yhDRFi +// xpct: BeQ4xQAYV8wVNw6Mz17YLkJS5KPC7zMn6BJAW5yhDRFi +// bump: 253 +// ================================================================================ +// tx: 5UURwBtJW8G4dQQh6qh6B4WmNP8NsiiCDVYuz4ydy5pyfqbBp3SWCXbAzZhVWygVnZsju5n4ZyT8BucebRz5UaUs +// program: WA6TpiY1gcAxRAjz5rQeVeZzgHtJKSnRZsJoocFCEGU +// ata: 5tFV7xjFWwSY4sJnPP2eMwV8rPRod3qSNXixCRdQoC3G +// xpct: 5tFV7xjFWwSY4sJnPP2eMwV8rPRod3qSNXixCRdQoC3G +// bump: 255 +// rPda: 8JUDRRrpmZejSbUn56yZjj6yBkmt2Aadb9EsjdYBx42f +// xpct: 8JUDRRrpmZejSbUn56yZjj6yBkmt2Aadb9EsjdYBx42f +// bump: 255 +// ================================================================================ +// tx: 5KkvmT5PrGv2xUmNyw1te6rJtjMQdNHEA8dydEsY2ECD9yubGoyLgUe1tEb8f7wfzgMveNbsPfyPKpbvti44bHMa +// program: WA6TpiY1gcAxRAjz5rQeVeZzgHtJKSnRZsJoocFCEGU +// ata: HF216CXtEVVPUneQh8FS5ZD6nwn2fiNtoqpBQDgocpdM +// xpct: HF216CXtEVVPUneQh8FS5ZD6nwn2fiNtoqpBQDgocpdM +// bump: 253 +// rPda: 2hMFR5WrT7YAY7Ep4XqYHYbcE7CRMCusqzMFGhDjgghF +// xpct: 2hMFR5WrT7YAY7Ep4XqYHYbcE7CRMCusqzMFGhDjgghF +// bump: 251 +// ================================================================================ +// tx: 5zy8wHfF3GMdPu9kLvyTBg46TszMxuRAoeBrcfYjbuxpnKw1TdEqnRFak7H9AKy523J653PEcHXjF2AmdMgh6sQf +// program: WA6TpiY1gcAxRAjz5rQeVeZzgHtJKSnRZsJoocFCEGU +// ata: 9aUgQeZ3ZABcyBPRodU7Z3pSUZva1xPVviavTLLBG4T5 +// xpct: 9aUgQeZ3ZABcyBPRodU7Z3pSUZva1xPVviavTLLBG4T5 +// bump: 253 +// rPda: 52cs96YUEoThSCXoZnwHJzPDcPScXbn3JKFWTLNTwPYh +// xpct: 52cs96YUEoThSCXoZnwHJzPDcPScXbn3JKFWTLNTwPYh +// bump: 251 +// ================================================================================ +// tx: bGbB8ugagCavqPFBSvTCat9GCD8Kqz3J317dYW2STAmzPs9xMkXLgehUyr1PSutT3H5PoZZyyUayPTJHaS3eNUs +// program: WA6TpiY1gcAxRAjz5rQeVeZzgHtJKSnRZsJoocFCEGU +// ata: 9aUgQeZ3ZABcyBPRodU7Z3pSUZva1xPVviavTLLBG4T5 +// xpct: 9aUgQeZ3ZABcyBPRodU7Z3pSUZva1xPVviavTLLBG4T5 +// bump: 253 +// rPda: 3Y7y5txWMnxBmbaBLo7ViTwL26EDxxH15L2HcX9sxk2V +// xpct: 3Y7y5txWMnxBmbaBLo7ViTwL26EDxxH15L2HcX9sxk2V +// bump: 255 +// ================================================================================ +// tx: 3w5hkXCKY2uy4tATGu457An8uBrZ1hB85Vw2hcmULqgESBZdX81WqNCuFzVH7v2Wc7EmQz8PeyuguSFBReH918nR +// program: WA6TpiY1gcAxRAjz5rQeVeZzgHtJKSnRZsJoocFCEGU +// ata: Ho62P3iPQ5W5et98dcMqGA8YwEqhqAFqfaiHGZL62Lha +// xpct: Ho62P3iPQ5W5et98dcMqGA8YwEqhqAFqfaiHGZL62Lha +// bump: 250 +// rPda: DRLkkZhrG7LnzAXpsxNnVCE64S8SX4SJSgMBJHUJUYRQ +// xpct: DRLkkZhrG7LnzAXpsxNnVCE64S8SX4SJSgMBJHUJUYRQ +// bump: 254 +// ================================================================================ +// tx: 3tqaAQBYmvHS2Dri9q1Fcg5SPBTBvaqWxqcMKiGyuuE8DJJXBZfH8dpxv1FGz5SYJV6SKoU75M7VtNLBkteCQn15 +// program: WA6TpiY1gcAxRAjz5rQeVeZzgHtJKSnRZsJoocFCEGU +// ata: 9aUgQeZ3ZABcyBPRodU7Z3pSUZva1xPVviavTLLBG4T5 +// xpct: 9aUgQeZ3ZABcyBPRodU7Z3pSUZva1xPVviavTLLBG4T5 +// bump: 253 +// rPda: A7YceyRVvMu8UcyQG4zmavmVbvnR9xXugr6gC3teQhos +// xpct: A7YceyRVvMu8UcyQG4zmavmVbvnR9xXugr6gC3teQhos +// bump: 254 +// ================================================================================ +// tx: 4m5Lm9PcLY9r5RdYrFfpVdn9H9bxYSRnXrZxjoK4L3PL5j5WQfbm2fLNt8JRUVSQSCruT98eUdooTmbg4JAk7vxP +// program: WA6TpiY1gcAxRAjz5rQeVeZzgHtJKSnRZsJoocFCEGU +// ata: 9aUgQeZ3ZABcyBPRodU7Z3pSUZva1xPVviavTLLBG4T5 +// xpct: 9aUgQeZ3ZABcyBPRodU7Z3pSUZva1xPVviavTLLBG4T5 +// bump: 253 +// rPda: 32Uv9RSN56AL574gYx71hh8KFo9b5kAZjvwPpDUWd6ay +// xpct: 32Uv9RSN56AL574gYx71hh8KFo9b5kAZjvwPpDUWd6ay +// bump: 255 +// ================================================================================ +// tx: 4P65T1mw1YYgY53Xcyuu373MMoFCDzro8j2YWjMx6anY86XQ6F1qvrpZtLK5a1fAntyB7bBdfZ2NryAs8jBttn2J +// program: WA6TpiY1gcAxRAjz5rQeVeZzgHtJKSnRZsJoocFCEGU +// ata: 9aUgQeZ3ZABcyBPRodU7Z3pSUZva1xPVviavTLLBG4T5 +// xpct: 9aUgQeZ3ZABcyBPRodU7Z3pSUZva1xPVviavTLLBG4T5 +// bump: 253 +// rPda: 4kUMgybdWSimouGckVdSqrD1acGMBUhrufyxjmbWyjT7 +// xpct: 4kUMgybdWSimouGckVdSqrD1acGMBUhrufyxjmbWyjT7 +// bump: 254 +// ================================================================================ +// tx: wLcgmj3mhtrjjdinCJJgbYioiaiuNnrTWqTiKpDpC9x6AvSMn6KzTEWXB89VoPk7D5vCEcQvTwyWwkRCaqCHWgm +// program: WA6TpiY1gcAxRAjz5rQeVeZzgHtJKSnRZsJoocFCEGU +// ata: 9aUgQeZ3ZABcyBPRodU7Z3pSUZva1xPVviavTLLBG4T5 +// xpct: 9aUgQeZ3ZABcyBPRodU7Z3pSUZva1xPVviavTLLBG4T5 +// bump: 253 +// rPda: s6z6UwVvQQNLV8fji2vGovfm7WkkKENQUKxRSTDBjDZ +// xpct: s6z6UwVvQQNLV8fji2vGovfm7WkkKENQUKxRSTDBjDZ +// bump: 255 +// ================================================================================ +// tx: 5xRyfymFQBL6hKgACFfsxkhEy9Jbxmja236P7VgwKHgVgNAZqmw3yLwST4CiADWKTkA75iuLc8YJN3Tsm8XfkMRm +// program: WA6TpiY1gcAxRAjz5rQeVeZzgHtJKSnRZsJoocFCEGU +// ata: 9aUgQeZ3ZABcyBPRodU7Z3pSUZva1xPVviavTLLBG4T5 +// xpct: 9aUgQeZ3ZABcyBPRodU7Z3pSUZva1xPVviavTLLBG4T5 +// bump: 253 +// rPda: AbYxsUnMoA7x2boxAkjW3ZAVBUGmTDbTUuG9JgB9PUV1 +// xpct: AbYxsUnMoA7x2boxAkjW3ZAVBUGmTDbTUuG9JgB9PUV1 +// bump: 254 +// ================================================================================ +// tx: 3JQapHPhJAvfEq2UV9ywnmaSLPDrzQtNrJPudqSmXBpUmf6N5svAQWWKTbKVHYNp4ZoEAnY1hr3ibfvB2WpBkABD +// program: WAPGu4AoTGCYbp1iXnZTpBn89VkJNJX3jY7uPuUZAv7 +// ata: 7zxEbLsj5VbGb4qvUd5Uo9JjJww97YxP58ggP5yhaaZg +// xpct: 7zxEbLsj5VbGb4qvUd5Uo9JjJww97YxP58ggP5yhaaZg +// bump: 255 +// rPda: DB9LXuNRUvoQmnRLVkZaN23bDpSK63vrpPREAixTW5Ku +// xpct: DB9LXuNRUvoQmnRLVkZaN23bDpSK63vrpPREAixTW5Ku +// bump: 255 +// ================================================================================ +// tx: 5i7xkSQjnar5vNTKddSdL6aVxuYD44Q1etYynfJuV2VFsQqcTGpfPeeo6qJqkWfDSGfP6fX9XWhaN6p8wTBiAfcF +// program: WAPGu4AoTGCYbp1iXnZTpBn89VkJNJX3jY7uPuUZAv7 +// ata: 5h1d1xqDgYkqYzqAygwPcABGPb4C98itCEKokq5w2hsa +// xpct: 5h1d1xqDgYkqYzqAygwPcABGPb4C98itCEKokq5w2hsa +// bump: 255 +// rPda: AnTKt5uMGv3xQY2N5v7XxjhvLH7WpCW4LuAQCZtEvKjn +// xpct: AnTKt5uMGv3xQY2N5v7XxjhvLH7WpCW4LuAQCZtEvKjn +// bump: 252 +// ================================================================================ +// tx: 2LCat1JPttHvrzTUUXwLz4YGx5gWszQpoHcz9cQuXpuFX1b6pFdfx3CV9yyexrwv4gZh5YnSUJiaGyoFEU5TaQnN +// program: WAPGu4AoTGCYbp1iXnZTpBn89VkJNJX3jY7uPuUZAv7 +// ata: 7yqeeFsxkA5p1jUWcfb22azXUYPajmiA8cqZAEH4Ykkt +// xpct: 7yqeeFsxkA5p1jUWcfb22azXUYPajmiA8cqZAEH4Ykkt +// bump: 255 +// rPda: A7PmVkGkN5f5NNkUCcam2v62k8aaBzqssPWB5Zq2hBNo +// xpct: A7PmVkGkN5f5NNkUCcam2v62k8aaBzqssPWB5Zq2hBNo +// bump: 252 +// ================================================================================ + +//############################################################################# + +//code: + +import { PublicKey } from "@solana/web3.js"; +import { TOKEN_PROGRAM_ID, ASSOCIATED_TOKEN_PROGRAM_ID } from "@solana/spl-token" +import { encoding } from "@wormhole-foundation/sdk-base"; +import { keccak256 } from "@wormhole-foundation/sdk-definitions"; + +const getAtaAndBump = (owner: PublicKey, mint: PublicKey) => + PublicKey.findProgramAddressSync( + [ + owner.toBytes(), + TOKEN_PROGRAM_ID.toBytes(), + mint.toBytes(), + ], + ASSOCIATED_TOKEN_PROGRAM_ID + ); + +function printTxInfo( + grantProgramId: string, + mint: string, + tx: string, + ecosystem: number, + claimant: string, + expectedAta: string, + identity: string, + expectedReceipt: string +) { + console.log("tx:", tx); + console.log("program:", grantProgramId); + const [ata, ataBump] = getAtaAndBump(new PublicKey(claimant), new PublicKey(mint)); + console.log(" ata:", ata.toBase58()); + console.log("xpct:", expectedAta); + console.log("bump:", ataBump); + const leaf = "00" + "0" + ecosystem + identity + amount; + //console.log("leaf:", leaf) + const leafHash = keccak256(encoding.hex.decode(leaf)).slice(0, 20); + //console.log("hash:", encoding.hex.encode(leafHash)); + const [rPda, bump] = PublicKey.findProgramAddressSync( + [encoding.bytes.encode("receipt"), leafHash], + new PublicKey(grantProgramId) + ); + console.log("rPda:", rPda.toBase58()); + console.log("xpct:", expectedReceipt) + console.log("bump:", bump); +} + +//all txs have the same amount +const amount = "00e1f50500000000"; +//tools used to calc identities: +// sha256: https://emn178.github.io/online-tools/sha256.html +// sha3-256: https://emn178.github.io/online-tools/sha3_256.html +// ripemd160: https://emn178.github.io/online-tools/ripemd_160.html +// bech32: https://slowli.github.io/bech32-buffer/ +// blake2b: https://hashing.tools/blake/blake2b +// ascii2hex: https://www.rapidtables.com/convert/number/ascii-to-hex.html +const txData = [ + [ + "waNTLJXETasWVTP1qj84Zs6h7XY8qvzqmKd1QWqxyLB", + "8UfkZKLgkQXLmnTQCpkxdmmAs8bGfjn9iiWrEKVvsrFx", + [ + [ + "3PYnssaWxjCXRQYBZHXsowJSCEaYHd1McH2GT3v5Jk7GaxbMCNRC54FF5qnpoPt1dkik8GgzJEhyJG4RQcd5mSCi", + 0, //Discord + "7q8qKpas5USmZwoxWQd36QYjPDgC7SK8cfHAacb5L2VH", + "9DSf7q55crkvaCMKFNh6MkFy3K9ab2TAxCPxpkoHLu2m", + "1300000031303034343734323937333336373337393233", + "MuNQAviUg6ZFvWp9Ft5PHchiMHeWE99mqw5zyMQzm7x" + ], [ + "U2zuQn7sDkNz6NZMVrEqTjPqNHG4zWDLqHh8CVuhqGutCr8WZ5eqqmLhTjZmhkMCZNLxRjJ3RhR7fTUGkJAHd1E", + 0, //Discord + "BswhzNvtNquLt5w2GbXqYvDLd95a2VnMxD4q6zhyaQFD", + "3xwGBStS3QX5hGmxweKaZgPK7QTLcEJG7YV2XYKGB3jr", + "12000000343736373430373536343035373437373133", + "BoSoN8zrkjva2BqaPnoshkhLB1AxLz6oe76x1zMo87X5" + ], [ + "573ui4vx3Avd8WpANYeUYwNdhcyj4FfY5P6QYRKPfrWNsqTaYRjzh2259J3tAQA6g1EctTfCsT5vzLtQNQhCQko4", + 0, //Discord + "BTwXQZS3EzfxBkv2A54estmn9YbmcpmRWeFP4f3avLi4", + "qYSg66vZNiAEy8k2SXBgxjnwiR8MR8N6vSP6YJWg73n", + "12000000343635343135383237383930363334373533", + "G9cpkCBzMcp7h3dZN6wLT8mRX8iDB4m8gd4T3cumHLdw" + ], [ + "4ERr2CdGa4ZmmVv4He8wmQXRzxjeGqpvEWFfSFoPbB7ohxGozJBc2vs9hZrKwWDXSQstint9LWc7poLYUuEt6GUu", + 0, //Discord + "89u5A3WLQh6xqPnvNEDDd8FBtRcvjAbZ28bbygeMoZDz", + "27VpCTrNdKAcsWE72gxxBPBFXAGcAMLgbPaLLyQXfzHk", + "12000000343237363236373331363137313234333536", + "2FSYp5oRWcUtCjBrij49YL7BZXiugknE2pEdFJAgdWdr" + ], [ + "3w4NM3fqxn2AfDa6c3P2kHsa2WzqQzbN3zH1wAVh63VYiFuHmKWDDk94Scgbjx6YGRJANVXStytXa9DjYRKVWpwZ", + 2, //evm + "Bc6acCmU9WhwDEFG4t37iJHUosMVrQ3sJS4UqnBcEgmf", + "8zfuxc7A4qw6UBYTU8nnmymfAPzxyQPiMNcTfea8oS3", + "0826d11726864b93993d333b784f42484e055c1e", + "3yqmGaXpcGfavuL4SVwrffAuH48kL9oS2bLAN86TQ58Q", + ], [ + "2ZoVWD1ToZVswUtkRDkPRAHzZGVGwgH66tfxLbswrJxnCcZjhYwsFCaZEsV2BWPBueh9TKB1UAFmkm82DKPKRoo9", + 2, //evm + "FyWzHEvV3xJKB1LADjQmQQR7A6kv4Dhb261q3rkcDHJq", + "G8P8sNvyZeSurzntNEBKUdYuhfZXDGyZLhQqNF3SY2sD", + "f2debd6e66aec4b2021e1d231651ab696ecc2afa", + "4yhfTbWg7cyucVRPzftSoyhqetv9urjpJwgFBNrpvdRG", + ], [ + "jucMMWFaafZD3F8MRutRJVkoqMfgzW53VHxRf5Jh79aBDGX7uwEDW1R4uDkSy3aVvRzoigSSRbatYDw5RijTDqp", + 2, //evm + "FyWzHEvV3xJKB1LADjQmQQR7A6kv4Dhb261q3rkcDHJq", + "G8P8sNvyZeSurzntNEBKUdYuhfZXDGyZLhQqNF3SY2sD", + "a70004dd7c887fb600b99fe6012aa11ce144f187", + "7yXVeoRk7C5HV6vMWrbtRr73kREviv79YPUAcSKQC3Bc", + ], [ + "3vyc2UPgCiPT67mHTDjpiKmHPLQukGtp44GbmBpVVKV85nZyTba2xKtN9ZKRJdxVTuLSJuHwA1u1kwKWBRJsiFXT", + 2, //evm + "Bc6acCmU9WhwDEFG4t37iJHUosMVrQ3sJS4UqnBcEgmf", + "8zfuxc7A4qw6UBYTU8nnmymfAPzxyQPiMNcTfea8oS3", + "4b5466e2a70c7292dcde9676854a3a7b3ac3df87", + "9jVoQgUwrKAeQ864jKd2onJ87c6WB34GcZ2D6PaQo28f", + ], [ + "4BfPPiHHm7Neq2utLb4zqKqAXWnz6nzAi8quRAwpRaaNXrcvQo3Ny99PzRjSULYmxNc8gzcYRS66FL1hVRjSG8bk", + 2, //evm + "FyWzHEvV3xJKB1LADjQmQQR7A6kv4Dhb261q3rkcDHJq", + "G8P8sNvyZeSurzntNEBKUdYuhfZXDGyZLhQqNF3SY2sD", + "59de65b85f69ddb0ef226d75e0a4129088a254d6", + "F59qKVTV3cQLpc6PBE9fMDDRtbEx4LHQXbrS6ERF3NLs", + ], [ + "4zKUWGufk9WZpGpNxVSU9QFTo44QKAQsM6Qf5YEBRg4fNZqJc1eckQUUjue3LXA8WAAAEECQth8KKrkHTMsHcFQX", + 2, //evm + "89u5A3WLQh6xqPnvNEDDd8FBtRcvjAbZ28bbygeMoZDz", + "27VpCTrNdKAcsWE72gxxBPBFXAGcAMLgbPaLLyQXfzHk", + "5f4ca243e844f082403c9bdfa6f7d1b3b2666d11", + "2iDPhgaeiY6XCiHqMJUwhotd1F14bWV61ub6MuHyupCq", + ], [ + "2W39xBYrMkuPYfBtuYizp9FmWzWQduwhF7xn8nfgtD534z5bmkcX8YyyGRzyehg1uiaDfgJ5o3YnL4k7yNjHKVbS", + 2, //evm + "89u5A3WLQh6xqPnvNEDDd8FBtRcvjAbZ28bbygeMoZDz", + "27VpCTrNdKAcsWE72gxxBPBFXAGcAMLgbPaLLyQXfzHk", + "c1ce054e9450d167717b5196f5d7351b1d104b11", + "6PLAcgp3vin44ov4JTcpbUcD512UpN42wFDKHV8yzAfG", + ], [ + "58e2fgsMAtwxNvv3wVRWbJuJdnwFx2thXxyEdtF5ZgeHq5g5FMD5m5fCbbhjEV4BpZD8kkt3wy1Nj1FuTAsyJehP", + 4, //aptos + "FyWzHEvV3xJKB1LADjQmQQR7A6kv4Dhb261q3rkcDHJq", + "G8P8sNvyZeSurzntNEBKUdYuhfZXDGyZLhQqNF3SY2sD", + //pubkey: 9dde8223960fea22b142eca661c3c172351149067a4f2bf263e4aac9781296c5 + 00 + //sha3-256: 0bf0a9442ef76768ece6f35a5f3e99e29f870436b5a75935f013da9577f2e02f + "0bf0a9442ef76768ece6f35a5f3e99e29f870436b5a75935f013da9577f2e02f", + "AfMmHhKn5WNyD4FhpswpHYMS1a4w9wZGP435GmdCNSjU", + ], [ + "3be6wQGM8FdDLMZm63r9YSMeXTZsAskrKvLKopDDCX8EHmCnjc9GGM28ArJRFRcs6uov7i3nSeKod4HsjtQ6swUS", + 5, //cosmwasm + "FyWzHEvV3xJKB1LADjQmQQR7A6kv4Dhb261q3rkcDHJq", + "G8P8sNvyZeSurzntNEBKUdYuhfZXDGyZLhQqNF3SY2sD", + //identity cert: + // "osmo": 040000006f736d6f + // signature: 0182223418ecc93841cdc637b8ac031c7c17ef6a6dba5f266bb84a7f3041900551c192b10ccd70e47b117f1af7546acd6ce48947b15ee32f4b65640415648b15 + // recovery id: 01 + // pubkey: 044b272d50d4c1dffaafe8d007ab3257577e1c9d632b0dc3a1d1b9e4b5a6601b796cfe9d2e7e82a1c8bd05e061af87b867cbd1d774accf55e59abc5040683159ef + //to identity: + // compressed: 034b272d50d4c1dffaafe8d007ab3257577e1c9d632b0dc3a1d1b9e4b5a6601b79 + // sha256: 45fdc8b6b25ff3123c4fa5b9798b1ecc6a5b080668b249febcbb986abc779008 + // ripemd160: 98d2155452c1c5f12a928d692e6e9b86c1b4a378 + // bech32: osmo1nrfp24zjc8zlz25j345jum5msmqmfgmcywvq2w + // hex: 6F736D6F316E72667032347A6A63387A6C7A32356A3334356A756D356D736D716D66676D63797776713277 + "2b0000006F736D6F316E72667032347A6A63387A6C7A32356A3334356A756D356D736D716D66676D63797776713277", + "3Rz3KUin6XQ7L7oa8eG7mHnb2jaKTcbzWcyQz63GLtE5", + ], [ + "258c3CH8aHktZUUCtJHR8QNqEv5L1QaJB39YPs64dpt6ByeH84mB4xWw9tMEkJD6dcnys4iUuasnJfhpMED7Ge6z", + 5, //cosmwasm + "Bc6acCmU9WhwDEFG4t37iJHUosMVrQ3sJS4UqnBcEgmf", + "8zfuxc7A4qw6UBYTU8nnmymfAPzxyQPiMNcTfea8oS3", + //identity cert: + // "terra": 050000007465727261 + // pubkey: 0455389f44092ed286630a6e36df38f6632cd869222515aedc0ff2a5820e210514d8f686a40fb1f3efe7bee02f878646ddcbcb1b3712c179fce78341bf1d434479 + //to identity: + // compressed: 0355389f44092ed286630a6e36df38f6632cd869222515aedc0ff2a5820e210514 + // sha256: 0c6dd3f02602264d5cc70aa787e3e504e53d158da8d1ad241e86ab2853b46481 + // ripemd160: dd6ba0eeddf462f72325831f37e4f089e179dcc9 + // bech32: terra1m446pmka7330wge9sv0n0e8s38shnhxfu5882u + // hex: 7465727261316D343436706D6B6137333330776765397376306E30653873333873686E687866753538383275 + "2c0000007465727261316D343436706D6B6137333330776765397376306E30653873333873686E687866753538383275", + "G2ETsQseMyKRr4AHqC9CjVgHMhQmNjKs5TazY9gm4G7q", + ], [ + "23HfzzuQBjSUDkLtM1VXeji3oT7ymDm6i8psudVuyxhkgedKEiVzqrpzsGT68ut5d9Qn2EdHNvT5aoaXQoQwRaDm", + 5, //cosmwasm + "Bc6acCmU9WhwDEFG4t37iJHUosMVrQ3sJS4UqnBcEgmf", + "8zfuxc7A4qw6UBYTU8nnmymfAPzxyQPiMNcTfea8oS3", + //identity cert: + // osmo + // pubkey: 04a052515bdc4d98d3d147ad811351e18907fb3c8e38889b9946c168c41c56ef5f985bad6c91f43f92af8cd5ee3a3a5c1fe8d65f612f7739dd78fcc89927fd52b4 + //to identity: + // compressed: 02a052515bdc4d98d3d147ad811351e18907fb3c8e38889b9946c168c41c56ef5f + // sha256: 6bec30eaba0b6c94a3e998c611722b7918b81c1c091f2e73b4ac2f21ff975a85 + // ripemd160: 40a2e5b4e94faf77b300120057a396cd287ff16e + // bech32: osmo1gz3wtd8ff7hh0vcqzgq90guke558lutwaq22wn + // hex: 6F736D6F31677A33777464386666376868307663717A6771393067756B653535386C75747761713232776E + "2b0000006F736D6F31677A33777464386666376868307663717A6771393067756B653535386C75747761713232776E", + "3vT15aYxTQrmNtkQjShQBjNrNvVe8Ya6mypz6gem1QB9", + ], [ + "5R1GrqETt7Cr5ebNhzAVX9SgvmToo8ZoL7t3n2nZUoCDnMFC7yRsp7sjqF9UVX6zug8fKS2PADZaTMFKSt2Ltawf", + 6, //injective + "Bc6acCmU9WhwDEFG4t37iJHUosMVrQ3sJS4UqnBcEgmf", + "8zfuxc7A4qw6UBYTU8nnmymfAPzxyQPiMNcTfea8oS3", + //evm pubkey: 911797dd3f93a0ed059b6abe879dcd5717e80a12 + //bech32: inj1jyte0hfljwsw6pvmd2lg08wd2ut7szsjk8pvls + //asci: 696E6A316A7974653068666C6A7773773670766D64326C673038776432757437737A736A6B3870766C73 + "2a000000696E6A316A7974653068666C6A7773773670766D64326C673038776432757437737A736A6B3870766C73", + "6NpXeEjWCPD447ii9x2qFSv2Mhmq19xmYKqTqXtFx5sJ" + ] + ] + ], + [ + "WA6TpiY1gcAxRAjz5rQeVeZzgHtJKSnRZsJoocFCEGU", + "9wonvscTW35qT622Z9LvgFtrba3YZFTqb7dZK1iktoXT", + [ + [ + "5YjAyoDd8m8bmc7zD17imJWYRc4dg2HeyVWSL48i3647moJfontGmJwU7snpDTc4MqiqQx6AdMEW7rGeUQfzgW6e", + 2, //evm + "BTwXQZS3EzfxBkv2A54estmn9YbmcpmRWeFP4f3avLi4", + "5UxD8NmcV9oLLUuKDqU15npkzuCPfbcXS4nWQGAbg7VG", + "4b5466e2a70c7292dcde9676854a3a7b3ac3df87", + "CJzucTLaguyM3m6RWiCQYgYUt8XXEAvQeCGRzQK5LPCa" + ], [ + "hPruXEKJXFiwDNuLKqQuHt1BsygbdZHST4LXh9E52Bv2MusCzmC3S3ZAFvANjfjKkXBV7fedP3iMeDUpp8N5K52", + 2, //evm + "3uuEwaVXjsszp5GoLonhRYm3NZBZfGbJ6zDRAgnue9wW", + "FXfJuWZryWAK2WTBGoqjuYSGqHAKbb4vfuRFD8UctCaZ", + "97ea8287e32ab88683d3dc334c70abb266058d0e", + "CRLwFwFpWcACmKCKQfJx98WH16iynjq51DwxadXkczAe" + ], [ + "ouVLq5CMmrU76jghoEYFGjSivzf6noiVLqegUfjYEurgb9rRdnqqjzNcVXQUyWXttuuhoW9pV6yFVFBkjcNUMpr", + 2, //evm + "HxLmHhRAfo9PGojaD39Mbs8rVsydkj6WT1qYji8PuJ5j", + "EWfpdfTnnAdSKifqQprmCrG1VmoTYi9aDZkaW6JsxBWZ", + "d17d7390af3cc6f71c800bbe9a0bcdf44271ce0d", + "A9TieXKjC7rbVHwHEf8hLwx73vPTR1Wo5oyQnD74vxb" + ], [ + "3pfztkbaUsHgpdNqwoAdAHksbs86y3odDn3tmyWjNRk5nyuHESCrYWddmqursKZStb94FQ7DrUg4wfgi1tuUMPgC", + 2, //evm + "FyWzHEvV3xJKB1LADjQmQQR7A6kv4Dhb261q3rkcDHJq", + "9aUgQeZ3ZABcyBPRodU7Z3pSUZva1xPVviavTLLBG4T5", + "a70004dd7c887fb600b99fe6012aa11ce144f187", + "BsSvBXZjhYtBdtrLoy7JQayrTJGgaN6adXqwGdTRSQV9" + ], [ + "3KoMAff3MuuoMRP2jhZCaCvBRfKHumaWG8Mmc1xbpQQYHwDkF28PphiWxS3tc5wTnwP1nT67LvNGYd6UdJeRbFXH", + 2, //evm + "89u5A3WLQh6xqPnvNEDDd8FBtRcvjAbZ28bbygeMoZDz", + "Ho62P3iPQ5W5et98dcMqGA8YwEqhqAFqfaiHGZL62Lha", + "3399052c19d6d60daf364e31feb19e6cfd156fc2", + "BaaKy8BM6zWBZr2NjinqGdPEjEuw8XyqUUVTWcmANW8u" + ], [ + "4zG76KQU3QZdpZEvfHQwfSwtN45LhM3ipPqxd58BTmvBdVxAGSMBs5QwL7dTHmBrksn9wp7z28GPMKhKBTf3skfp", + 2, //evm + "573yfYSJp3AgufxdvgMCZ7agEmpoL8KTu2c17Wrx78YH", + "CWR8XKuSXHjMsyB9TBTMov7DboNYAMVpXbEVEHd5at67", + "33a08ad58b7475f2371a89c5d7ab106ada2ae350", + "9pq3NZ88s4y4JYPg59QRPpt82KxJhefCsLvZGYzCdyk5" + ], [ + "D1G125KsundqAvP9yGvbh5mr2tkYFik3o41kAQJTkQmz9GtVFKC6HK4Qd22sA7RRA3uWVGvRkr4PRZXUHnitMEZ", + 1, //solana + "BvwvH7fP6EqoduboWt9UcWFtoNviLinviWDD4oNGLA8", + "5RLGgSF8azFHcKUaJbF4kKjqEtbviW2hbrmvhbL1nvfm", + encoding.hex.encode(encoding.b58.decode("BvwvH7fP6EqoduboWt9UcWFtoNviLinviWDD4oNGLA8")), + "5e8CC6qhMfYnRTLM7Ay4bKNcajaJhfjCFPhng5SZvPrT" + ], [ + "3C4UNJLx71GSRCiJQ5b4LyW2DJrmvXsaNH7tidWdwZYrLQ2z7yufzTY8ssfV9asDzyzgpe4XkEicLqdL9pLyGPwx", + 1, //solana + "573yfYSJp3AgufxdvgMCZ7agEmpoL8KTu2c17Wrx78YH", + "CWR8XKuSXHjMsyB9TBTMov7DboNYAMVpXbEVEHd5at67", + encoding.hex.encode(encoding.b58.decode("573yfYSJp3AgufxdvgMCZ7agEmpoL8KTu2c17Wrx78YH")), + "E8KBxNHwo33zBHozUH9nxKWxCbd5bsDrMyz4p7UzPuwk" + ], [ + "4uWbYwSZ5g3mBC2doAQVQJ9foRuBgXUf9sa1SteLdaU5zWB9WhvBmpPXgji2u8RBKfa3xLhPJmJLEdxx6YabL4Gw", + 1, //solana + "FyWzHEvV3xJKB1LADjQmQQR7A6kv4Dhb261q3rkcDHJq", + "9aUgQeZ3ZABcyBPRodU7Z3pSUZva1xPVviavTLLBG4T5", + encoding.hex.encode(encoding.b58.decode("FyWzHEvV3xJKB1LADjQmQQR7A6kv4Dhb261q3rkcDHJq")), + "9VqJfhmY16uWUF19g68kvVLCmje8KhR8qnxQhcG7ysnF" + ], [ + "34vrzPudC4kZ4rsPSjjZG9pZRxxgeeV9KmSbbufMuwTXowoFcS7QuEtMDQwMNF4cygxRnB8uCGpvKBwF8ELpgcin", + 1, //solana + "89u5A3WLQh6xqPnvNEDDd8FBtRcvjAbZ28bbygeMoZDz", + "Ho62P3iPQ5W5et98dcMqGA8YwEqhqAFqfaiHGZL62Lha", + encoding.hex.encode(encoding.b58.decode("89u5A3WLQh6xqPnvNEDDd8FBtRcvjAbZ28bbygeMoZDz")), + "BeQ4xQAYV8wVNw6Mz17YLkJS5KPC7zMn6BJAW5yhDRFi" + ], [ + "5UURwBtJW8G4dQQh6qh6B4WmNP8NsiiCDVYuz4ydy5pyfqbBp3SWCXbAzZhVWygVnZsju5n4ZyT8BucebRz5UaUs", + 1, //solana + "4pJnUs7SY7rARFi3NjJwMvzGZnYypQ6r6JvSXs4Xoxgn", + "5tFV7xjFWwSY4sJnPP2eMwV8rPRod3qSNXixCRdQoC3G", + encoding.hex.encode(encoding.b58.decode("4pJnUs7SY7rARFi3NjJwMvzGZnYypQ6r6JvSXs4Xoxgn")), + "8JUDRRrpmZejSbUn56yZjj6yBkmt2Aadb9EsjdYBx42f" + ], [ + "5KkvmT5PrGv2xUmNyw1te6rJtjMQdNHEA8dydEsY2ECD9yubGoyLgUe1tEb8f7wfzgMveNbsPfyPKpbvti44bHMa", + 1, //solana + "3UyQice7qgUGkfjYDbGxCukU9dqXbTasK4RVeLxtVzQa", + "HF216CXtEVVPUneQh8FS5ZD6nwn2fiNtoqpBQDgocpdM", + encoding.hex.encode(encoding.b58.decode("3UyQice7qgUGkfjYDbGxCukU9dqXbTasK4RVeLxtVzQa")), + "2hMFR5WrT7YAY7Ep4XqYHYbcE7CRMCusqzMFGhDjgghF" + ], [ + "5zy8wHfF3GMdPu9kLvyTBg46TszMxuRAoeBrcfYjbuxpnKw1TdEqnRFak7H9AKy523J653PEcHXjF2AmdMgh6sQf", + 3, //sui + "FyWzHEvV3xJKB1LADjQmQQR7A6kv4Dhb261q3rkcDHJq", + "9aUgQeZ3ZABcyBPRodU7Z3pSUZva1xPVviavTLLBG4T5", + //pubkey: 00 + 46d33d6dff684ffe92be7e82435ec96e9f5941f35940e77779b6c41e13c42618 + //blake2b: de109835b2ae8d6cfb2fa5ab20706d70a2330c59f8f8d827b001db6cc521d269 + "de109835b2ae8d6cfb2fa5ab20706d70a2330c59f8f8d827b001db6cc521d269", + "52cs96YUEoThSCXoZnwHJzPDcPScXbn3JKFWTLNTwPYh" + ], [ + "bGbB8ugagCavqPFBSvTCat9GCD8Kqz3J317dYW2STAmzPs9xMkXLgehUyr1PSutT3H5PoZZyyUayPTJHaS3eNUs", + 4, //aptos + "FyWzHEvV3xJKB1LADjQmQQR7A6kv4Dhb261q3rkcDHJq", + "9aUgQeZ3ZABcyBPRodU7Z3pSUZva1xPVviavTLLBG4T5", + //pubkey: 9dde8223960fea22b142eca661c3c172351149067a4f2bf263e4aac9781296c5 + 00 + //sha3-256: 0bf0a9442ef76768ece6f35a5f3e99e29f870436b5a75935f013da9577f2e02f + "0bf0a9442ef76768ece6f35a5f3e99e29f870436b5a75935f013da9577f2e02f", + "3Y7y5txWMnxBmbaBLo7ViTwL26EDxxH15L2HcX9sxk2V" + ], [ + "3w5hkXCKY2uy4tATGu457An8uBrZ1hB85Vw2hcmULqgESBZdX81WqNCuFzVH7v2Wc7EmQz8PeyuguSFBReH918nR", + 4, //aptos + "89u5A3WLQh6xqPnvNEDDd8FBtRcvjAbZ28bbygeMoZDz", + "Ho62P3iPQ5W5et98dcMqGA8YwEqhqAFqfaiHGZL62Lha", + //pubkey: + 00 + //sha3-256: 1c963ea09f2511f42bbda25f731808dc1823ff6deb04f0fe8f9a9b9773b23328 + "1c963ea09f2511f42bbda25f731808dc1823ff6deb04f0fe8f9a9b9773b23328", + "DRLkkZhrG7LnzAXpsxNnVCE64S8SX4SJSgMBJHUJUYRQ" + ], [ + "3tqaAQBYmvHS2Dri9q1Fcg5SPBTBvaqWxqcMKiGyuuE8DJJXBZfH8dpxv1FGz5SYJV6SKoU75M7VtNLBkteCQn15", + 5, //cosmwasm + "FyWzHEvV3xJKB1LADjQmQQR7A6kv4Dhb261q3rkcDHJq", + "9aUgQeZ3ZABcyBPRodU7Z3pSUZva1xPVviavTLLBG4T5", + //identity cert: + // osmo + // pubkey: 0427b74377fc92cb6051842a22bae952392e80807cb6cd02616ef6eb34c6d468b222bb110586f218d3623bc5aac61590858ef5d228bfbd496b2091928d4800fda2 + //to identity: + // compressed: 0227b74377fc92cb6051842a22bae952392e80807cb6cd02616ef6eb34c6d468b2 + // sha256: 7376d9151bbf64f9ab9920269279c7ff716c02897072aea8452b3a386de804e6 + // ripemd160: e0148fd6ce0a7e4e729f8da056da0a37e939f517 + // bech32: osmo1uq2gl4kwpflyuu5l3ks9dks2xl5nnaghcfjw06 + // hex: 6F736D6F31757132676C346B7770666C797575356C336B7339646B7332786C356E6E61676863666A773036 + "2b0000006F736D6F31757132676C346B7770666C797575356C336B7339646B7332786C356E6E61676863666A773036", + "A7YceyRVvMu8UcyQG4zmavmVbvnR9xXugr6gC3teQhos" + ], [ + "4m5Lm9PcLY9r5RdYrFfpVdn9H9bxYSRnXrZxjoK4L3PL5j5WQfbm2fLNt8JRUVSQSCruT98eUdooTmbg4JAk7vxP", + 5, //cosmwasm + "FyWzHEvV3xJKB1LADjQmQQR7A6kv4Dhb261q3rkcDHJq", + "9aUgQeZ3ZABcyBPRodU7Z3pSUZva1xPVviavTLLBG4T5", + //identity cert: + // osmo + // pubkey: 044b272d50d4c1dffaafe8d007ab3257577e1c9d632b0dc3a1d1b9e4b5a6601b796cfe9d2e7e82a1c8bd05e061af87b867cbd1d774accf55e59abc5040683159ef + //to identity: + // compressed: 034b272d50d4c1dffaafe8d007ab3257577e1c9d632b0dc3a1d1b9e4b5a6601b79 + // sha256: 45fdc8b6b25ff3123c4fa5b9798b1ecc6a5b080668b249febcbb986abc779008 + // ripemd160: 98d2155452c1c5f12a928d692e6e9b86c1b4a378 + // bech32: osmo1nrfp24zjc8zlz25j345jum5msmqmfgmcywvq2w + // hex: 6F736D6F316E72667032347A6A63387A6C7A32356A3334356A756D356D736D716D66676D63797776713277 + "2b0000006F736D6F316E72667032347A6A63387A6C7A32356A3334356A756D356D736D716D66676D63797776713277", + "32Uv9RSN56AL574gYx71hh8KFo9b5kAZjvwPpDUWd6ay" + ], [ + "4P65T1mw1YYgY53Xcyuu373MMoFCDzro8j2YWjMx6anY86XQ6F1qvrpZtLK5a1fAntyB7bBdfZ2NryAs8jBttn2J", + 5, //cosmwasm + "FyWzHEvV3xJKB1LADjQmQQR7A6kv4Dhb261q3rkcDHJq", + "9aUgQeZ3ZABcyBPRodU7Z3pSUZva1xPVviavTLLBG4T5", + //identity cert: + // "terra": 050000007465727261 + // signature: 4235e96084a54cc64bd72b07a0b43d170a1968043b901b84754bbe184ca98d062d65c2aa7f06217239039356e70ab8a473179a7f9ed4b6b636aafbed4ca4db7b + // recovery id: 01 + // pubkey: 0452817418f112203e7d5e44cf32adf2e3719cd9b1e5cb7f8cddc02fbb547461d841148cd20d3d8785aaaa27e0cb439e54950423ed104a0e09db137c36d1a5955d + //to identity: + // compressed: 0352817418f112203e7d5e44cf32adf2e3719cd9b1e5cb7f8cddc02fbb547461d8 + // sha256: aa1d3935bb874be86a816377b1200df9248527d4b832ab179eed2b6762b89fdb + // ripemd160: 3a2dcedc027142729ba31954bcbc26d53e3744fe + // bech32: terra18gkuahqzw9p89xarr92te0px65lrw387juhdch + // hex: 74657272613138676B756168717A7739703839786172723932746530707836356C72773338376A7568646368 + "2c00000074657272613138676B756168717A7739703839786172723932746530707836356C72773338376A7568646368", + "4kUMgybdWSimouGckVdSqrD1acGMBUhrufyxjmbWyjT7" + ], [ + "wLcgmj3mhtrjjdinCJJgbYioiaiuNnrTWqTiKpDpC9x6AvSMn6KzTEWXB89VoPk7D5vCEcQvTwyWwkRCaqCHWgm", + 5, //cosmwasm + "FyWzHEvV3xJKB1LADjQmQQR7A6kv4Dhb261q3rkcDHJq", + "9aUgQeZ3ZABcyBPRodU7Z3pSUZva1xPVviavTLLBG4T5", + //identity cert: + // terra + // pubkey: 041c06c8a5da274904afa1800b71bc8cee0c85296f6ef1275372a43f336a82dfb9f5303969b920dabc191c8299ac91700710afcc2c12b6a2a217dbc0f8e00694c1 + //to identity: + // compressed: 031c06c8a5da274904afa1800b71bc8cee0c85296f6ef1275372a43f336a82dfb9 + // sha256: af37810196da2190b20a84c1677301c08c9b455734786e3dedc3826a0cdb2499 + // ripemd160: 747aef95bdd2d86ae829beea634c5b90870eb5b4 + // bech32: terra1w3awl9da6tvx46pfhm4xxnzmjzrsadd5g57phj + // hex: 746572726131773361776C3964613674767834367066686D3478786E7A6D6A7A72736164643567353770686A + "2c000000746572726131773361776C3964613674767834367066686D3478786E7A6D6A7A72736164643567353770686A", + "s6z6UwVvQQNLV8fji2vGovfm7WkkKENQUKxRSTDBjDZ" + ], [ + "5xRyfymFQBL6hKgACFfsxkhEy9Jbxmja236P7VgwKHgVgNAZqmw3yLwST4CiADWKTkA75iuLc8YJN3Tsm8XfkMRm", + 6, //injective + "FyWzHEvV3xJKB1LADjQmQQR7A6kv4Dhb261q3rkcDHJq", + "9aUgQeZ3ZABcyBPRodU7Z3pSUZva1xPVviavTLLBG4T5", + //evm pubkey: db017a14f0be5f2c4e654ac9290c06d3ab41f921 + //https://slowli.github.io/bech32-buffer/ with inj prefix + //bech32: inj1mvqh598she0jcnn9ftyjjrqx6w45r7fpmgavf6 + //asci: 696E6A316D767168353938736865306A636E6E396674796A6A72717836773435723766706D6761766636 + "2a000000696E6A316D767168353938736865306A636E6E396674796A6A72717836773435723766706D6761766636", + "AbYxsUnMoA7x2boxAkjW3ZAVBUGmTDbTUuG9JgB9PUV1" + ] + ] + ], + [ + "WAPGu4AoTGCYbp1iXnZTpBn89VkJNJX3jY7uPuUZAv7", + "29xyJAzhzEeTpwrQQz8JrLethQ4a8UoK29dZRopEAXpW", + [ + [ + "3JQapHPhJAvfEq2UV9ywnmaSLPDrzQtNrJPudqSmXBpUmf6N5svAQWWKTbKVHYNp4ZoEAnY1hr3ibfvB2WpBkABD", + 3, //sui + "73D1CUu581E4FMLBMns6fj2BBDb8Y9MYHhdVBJyictvm", + "7zxEbLsj5VbGb4qvUd5Uo9JjJww97YxP58ggP5yhaaZg", + "8429bc7aa2f902786304faba82f226da97c586a06e850c10574238316e78404a", //https://hashing.tools/blake/blake2b + "DB9LXuNRUvoQmnRLVkZaN23bDpSK63vrpPREAixTW5Ku" + ], [ + "5i7xkSQjnar5vNTKddSdL6aVxuYD44Q1etYynfJuV2VFsQqcTGpfPeeo6qJqkWfDSGfP6fX9XWhaN6p8wTBiAfcF", + 5, //cosmwasm + "Bc6acCmU9WhwDEFG4t37iJHUosMVrQ3sJS4UqnBcEgmf", + "5h1d1xqDgYkqYzqAygwPcABGPb4C98itCEKokq5w2hsa", + //identity cert: + // osmo + // pubkey: 04008b8faad61593a0cae096dbcf474bd45d62f692eaf06c30e90e635e13c7e87d3f2b7580fe5e3383a32651b9e6bd41f8ec21f1d2d64be8269afd4b87ab9fad4c + //to identity: + // compressed: 02008b8faad61593a0cae096dbcf474bd45d62f692eaf06c30e90e635e13c7e87d + // sha256: a3b14dd309cf127d00009f2eeae15020879c782025278aa90b450e4c555be3bf + // ripemd160: 485715c52c7e600d994ffb8672cbccb482a8e924 + // bech32: osmo1fpt3t3fv0esqmx20lwr89j7vkjp236fyk374kj + // hex: 6F736D6F316670743374336676306573716D7832306C777238396A37766B6A7032333666796B3337346B6A + "2b0000006F736D6F316670743374336676306573716D7832306C777238396A37766B6A7032333666796B3337346B6A", + "AnTKt5uMGv3xQY2N5v7XxjhvLH7WpCW4LuAQCZtEvKjn" + ], [ + "2LCat1JPttHvrzTUUXwLz4YGx5gWszQpoHcz9cQuXpuFX1b6pFdfx3CV9yyexrwv4gZh5YnSUJiaGyoFEU5TaQnN", + 7, //algorand + "FyWzHEvV3xJKB1LADjQmQQR7A6kv4Dhb261q3rkcDHJq", + "7yqeeFsxkA5p1jUWcfb22azXUYPajmiA8cqZAEH4Ykkt", + "e76ebbb390cfb012c18396d3ae0e19e98912e00f3ad3b33bdbb70ece3acd547c", + "A7PmVkGkN5f5NNkUCcam2v62k8aaBzqssPWB5Zq2hBNo" + ] + ] + ] +] as const; + +for (const [pId, mint, txs] of txData) + for (const [txHash, ecosystem, claimant, claimantAta, identity, receiptPda] of txs) { + printTxInfo(pId, mint, txHash, ecosystem, claimant, claimantAta, identity, receiptPda); + console.log("=".repeat(80)) + } diff --git a/frontend/claim_sdk/solana.ts b/frontend/claim_sdk/solana.ts index a079ef8f..43da9385 100644 --- a/frontend/claim_sdk/solana.ts +++ b/frontend/claim_sdk/solana.ts @@ -322,71 +322,134 @@ export class TokenDispenserProvider { proofOfInclusion: Uint8Array[], signedMessage: SignedMessage | undefined ): Promise { - // 1. generate claim certificate - // a. create proofOfIdentity - const proofOfIdentity = this.createProofOfIdentity(claimInfo, signedMessage) + const [receiptPda, receiptBump] = this.getReceiptPda(claimInfo) + const { mint } = await this.getConfig() + //same as getClaimantFundAddress / getAssociatedTokenAddress but with bump + const [claimantFund, claimaintFundBump] = PublicKey.findProgramAddressSync( + [ + this.claimant.toBytes(), + splToken.TOKEN_PROGRAM_ID.toBytes(), + mint.toBytes(), + ], + splToken.ASSOCIATED_TOKEN_PROGRAM_ID + ) + const [claimantFundAccount, lookupTableAccount] = await Promise.all([ + this.connection.getAccountInfo(claimantFund), + this.getLookupTableAccount(), + ]) - const claimCert: IdlTypes['ClaimCertificate'] = { - amount: claimInfo.amount, - proofOfIdentity, - proofOfInclusion, - } + const ixs: anchor.web3.TransactionInstruction[] = [] - // 2. generate signature verification instruction if needed + // 1. add signatureVerification instruction if needed const signatureVerificationIx = this.generateSignatureVerificationInstruction( claimInfo.ecosystem, signedMessage ) - // 3. derive receipt pda - const receiptPda = this.getReceiptPda(claimInfo)[0] + if (signatureVerificationIx) ixs.push(signatureVerificationIx) - const lookupTableAccount = await this.getLookupTableAccount() + // 2. add create ATA instruction if needed + const claimantFundExists = claimantFundAccount !== null - const ixs = signatureVerificationIx ? [signatureVerificationIx] : [] - const claim_ix = await this.tokenDispenserProgram.methods - .claim(claimCert) - .accounts({ - funder, - claimant: this.claimant, - claimantFund: await this.getClaimantFundAddress(), - config: this.getConfigPda()[0], - mint: (await this.getConfig()).mint, - treasury, - tokenProgram: TOKEN_PROGRAM_ID, - systemProgram: anchor.web3.SystemProgram.programId, - sysvarInstruction: anchor.web3.SYSVAR_INSTRUCTIONS_PUBKEY, - associatedTokenProgram: splToken.ASSOCIATED_TOKEN_PROGRAM_ID, - }) - .remainingAccounts([ - { - pubkey: receiptPda, - isWritable: true, - isSigner: false, - }, - ]) - .instruction() - ixs.push(claim_ix) - ixs.push(ComputeBudgetProgram.setComputeUnitLimit({ units: 200_000 })) - - const microLamports = 1 //TODO determine true value + if (!claimantFundExists) + ixs.push( + splToken.Token.createAssociatedTokenAccountInstruction( + splToken.ASSOCIATED_TOKEN_PROGRAM_ID, + splToken.TOKEN_PROGRAM_ID, + mint, + claimantFund, + this.claimant, + funder + ) + ) + + // 3. add claim instruction + const proofOfIdentity = this.createProofOfIdentity( + claimInfo, + signedMessage, + 0 + ) + + const claimCert: IdlTypes['ClaimCertificate'] = { + amount: claimInfo.amount, + proofOfIdentity, + proofOfInclusion, + } + + ixs.push( + await this.tokenDispenserProgram.methods + .claim(claimCert) + .accounts({ + funder, + claimant: this.claimant, + claimantFund, + config: this.getConfigPda()[0], + mint, + treasury, + tokenProgram: TOKEN_PROGRAM_ID, + systemProgram: anchor.web3.SystemProgram.programId, + sysvarInstruction: anchor.web3.SYSVAR_INSTRUCTIONS_PUBKEY, + associatedTokenProgram: splToken.ASSOCIATED_TOKEN_PROGRAM_ID, + }) + .remainingAccounts([ + { + pubkey: receiptPda, + isWritable: true, + isSigner: false, + }, + ]) + .instruction() + ) + + // 4. add Compute Unit instructions + const pdaDerivationCosts = (bump: number) => { + const maxBump = 255 + const cusPerPdaDerivation = 1500 + return (maxBump - bump) * cusPerPdaDerivation + } + const safetyMargin = 1000 + const ataCreationCost = 20460 + //determined experimentally: + const ecosystemCUs = { + discord: 44200, + solana: 40450, + evm: 66600, + sui: 79200, + aptos: 78800, + terra: 113500, + osmosis: 113200, + injective: 71700, + algorand: 70700, + } + + const units = + safetyMargin + + ecosystemCUs[claimInfo.ecosystem] + + pdaDerivationCosts(claimaintFundBump) + + pdaDerivationCosts(receiptBump) + + (claimantFundExists + ? 0 + : ataCreationCost + pdaDerivationCosts(claimaintFundBump)) + ixs.push(ComputeBudgetProgram.setComputeUnitLimit({ units })) + + const microLamports = 1_000_000 //somewhat arbitrary choice ixs.push(ComputeBudgetProgram.setComputeUnitPrice({ microLamports })) - const claimTx = new VersionedTransaction( + // 5. build and return the transaction + return new VersionedTransaction( new TransactionMessage({ instructions: ixs, payerKey: funder, recentBlockhash: (await this.connection.getLatestBlockhash()).blockhash, }).compileToV0Message([lookupTableAccount!]) ) - - return claimTx } private createProofOfIdentity( claimInfo: ClaimInfo, - signedMessage: SignedMessage | undefined + signedMessage: SignedMessage | undefined, + verificationInstructionIndex: number ): IdlTypes['IdentityCertificate'] { if (claimInfo.ecosystem === 'solana') { return { @@ -404,7 +467,7 @@ export class TokenDispenserProvider { return { [claimInfo.ecosystem]: { pubkey: Array.from(signedMessage.publicKey), - verificationInstructionIndex: 0, + verificationInstructionIndex, }, } } @@ -424,7 +487,7 @@ export class TokenDispenserProvider { return { discord: { username: claimInfo.identity, - verificationInstructionIndex: 0, + verificationInstructionIndex, }, } } @@ -442,7 +505,8 @@ export class TokenDispenserProvider { private generateSignatureVerificationInstruction( ecosystem: Ecosystem, - signedMessage: SignedMessage | undefined + signedMessage: SignedMessage | undefined, + instructionIndex: number = 0 ): anchor.web3.TransactionInstruction | undefined { if (ecosystem === 'solana') { return undefined @@ -457,6 +521,7 @@ export class TokenDispenserProvider { message: signedMessage.fullMessage, signature: signedMessage.signature, recoveryId: signedMessage.recoveryId!, + instructionIndex, }) } case 'osmosis': @@ -471,7 +536,7 @@ export class TokenDispenserProvider { publicKey: signedMessage.publicKey, message: signedMessage.fullMessage, signature: signedMessage.signature, - instructionIndex: 0, + instructionIndex, }) } default: { diff --git a/frontend/integration/api.test.ts b/frontend/integration/api.test.ts index d8204c7e..eeb8d7b8 100644 --- a/frontend/integration/api.test.ts +++ b/frontend/integration/api.test.ts @@ -1,4 +1,5 @@ import { AnchorProvider, Program } from '@coral-xyz/anchor' +import * as splToken from '@solana/spl-token' import IDL from '../claim_sdk/idl/token_dispenser.json' import { ComputeBudgetProgram, @@ -32,6 +33,7 @@ import { tokenDispenserProgramId } from '../utils/constants' dotenv.config() const tokenDispenserPublicKey = new PublicKey(tokenDispenserProgramId) const WHITELISTED_PROGRAMS: PublicKey[] = [ + splToken.ASSOCIATED_TOKEN_PROGRAM_ID, tokenDispenserPublicKey, Secp256k1Program.programId, Ed25519Program.programId, diff --git a/frontend/integration/api.ts b/frontend/integration/api.ts index f812335a..4a18bfdc 100644 --- a/frontend/integration/api.ts +++ b/frontend/integration/api.ts @@ -5,6 +5,7 @@ import { Secp256k1Program, VersionedTransaction, } from '@solana/web3.js' +import * as splToken from '@solana/spl-token' import { NextApiRequest, NextApiResponse } from 'next' import { TransactionWithPayers, @@ -28,6 +29,7 @@ const wallets = loadFunderWallets() const tokenDispenserPublicKey = new PublicKey(tokenDispenserProgramId) const WHITELISTED_PROGRAMS: PublicKey[] = [ + splToken.ASSOCIATED_TOKEN_PROGRAM_ID, tokenDispenserPublicKey, Secp256k1Program.programId, Ed25519Program.programId, diff --git a/frontend/utils/verifyTransaction.ts b/frontend/utils/verifyTransaction.ts index 98e3b1f1..dbefa5a9 100644 --- a/frontend/utils/verifyTransaction.ts +++ b/frontend/utils/verifyTransaction.ts @@ -88,7 +88,7 @@ export function checkSetComputeBudgetInstructionsAreSetComputeUnitPrice( const priorityFee = ComputeBudgetInstruction.decodeSetComputeUnitPrice( legacTransactionInstruction ) - if (priorityFee.microLamports >= MAX_COMPUTE_UNIT_PRICE) { + if (priorityFee.microLamports > MAX_COMPUTE_UNIT_PRICE) { return false } } From d467d5241dab6bce498f0961553dcc7bda609de6 Mon Sep 17 00:00:00 2001 From: Valentino Conti <41705567+valentinoConti@users.noreply.github.com> Date: Mon, 1 Apr 2024 20:53:48 -0300 Subject: [PATCH 09/12] Add Phantom Wallet support for EVM (#66) --- frontend/components/wallets/EVM.tsx | 16 +- frontend/components/wallets/Solana.tsx | 15 +- .../components/wallets/phantomConnector.ts | 140 ++++++++++++++++++ frontend/images/phantom.svg | 89 +++++++++++ 4 files changed, 258 insertions(+), 2 deletions(-) create mode 100644 frontend/components/wallets/phantomConnector.ts create mode 100644 frontend/images/phantom.svg diff --git a/frontend/components/wallets/EVM.tsx b/frontend/components/wallets/EVM.tsx index 8f9270cf..cb87c30b 100644 --- a/frontend/components/wallets/EVM.tsx +++ b/frontend/components/wallets/EVM.tsx @@ -18,11 +18,13 @@ import { CoinbaseWalletConnector } from 'wagmi/connectors/coinbaseWallet' import { MetaMaskConnector } from 'wagmi/connectors/metaMask' import { WalletConnectConnector } from 'wagmi/connectors/walletConnect' import { InjectedConnector } from 'wagmi/connectors/injected' +import { PhantomConnector } from './phantomConnector' import coinbase from '@images/coinbase.svg' import walletConnect from '@images/wallet-connect.svg' import metamask from '@images/metamask.svg' import okx from '@images/okx.svg' +import phantom from '@images/phantom.svg' import { getInjectiveAddress } from '../../utils/getInjectiveAddress' @@ -54,12 +56,23 @@ const config = createConfig({ showQrModal: true, }, }), + new PhantomConnector({ + chains, + options: { + name: 'Phantom', + }, + }), ], publicClient, webSocketPublicClient, }) -type WalletIds = 'metaMask' | 'coinbaseWallet' | 'walletConnect' | 'injected' +type WalletIds = + | 'metaMask' + | 'coinbaseWallet' + | 'walletConnect' + | 'injected' + | 'phantom' type EVMWalletProviderProps = { children: ReactNode @@ -153,6 +166,7 @@ function getIcon(id: WalletIds | undefined) { if (id === undefined) return undefined if (id === 'metaMask') return metamask if (id === 'coinbaseWallet') return coinbase + if (id === 'phantom') return phantom if (id === 'injected') return okx return walletConnect } diff --git a/frontend/components/wallets/Solana.tsx b/frontend/components/wallets/Solana.tsx index 2ffc45d3..156005d9 100644 --- a/frontend/components/wallets/Solana.tsx +++ b/frontend/components/wallets/Solana.tsx @@ -58,7 +58,20 @@ export function SolanaWalletProvider({ return ( - + { + if ( + e?.error?.code === -32603 && + e?.error?.message === 'Unexpected error' + ) { + alert( + `An unexpected error happened.\n\nMake sure that the wallet that you selected it's connected to your Solana account and reload the page.` + ) + } + }} + wallets={wallets} + autoConnect + > {children} diff --git a/frontend/components/wallets/phantomConnector.ts b/frontend/components/wallets/phantomConnector.ts new file mode 100644 index 00000000..ef6fa37d --- /dev/null +++ b/frontend/components/wallets/phantomConnector.ts @@ -0,0 +1,140 @@ +import { InjectedConnector } from 'wagmi/connectors/injected' +import { WindowProvider, ConnectorNotFoundError } from 'wagmi' +import { + ProviderRpcError, + ResourceNotFoundRpcError, + UserRejectedRequestError, + getAddress, +} from 'viem' +import type { Address } from 'abitype' +import type { Chain } from '@wagmi/core/chains' + +type InjectedConnectorOptions = { + /** Name of connector */ + name?: string | ((detectedName: string | string[]) => string) + /** + * [EIP-1193](https://eips.ethereum.org/EIPS/eip-1193) Ethereum Provider to target + * + * @default + * () => typeof window !== 'undefined' ? window.ethereum : undefined + */ + getProvider?: () => WindowProvider | undefined + /** + * MetaMask and other injected providers do not support programmatic disconnect. + * This flag simulates the disconnect behavior by keeping track of connection status in storage. See [GitHub issue](https://github.com/MetaMask/metamask-extension/issues/10353) for more info. + * @default true + */ + shimDisconnect?: boolean +} + +declare global { + interface Window { + phantom: { + ethereum: WindowProvider + } + } +} + +export class PhantomConnector extends InjectedConnector { + readonly id = 'phantom' + + protected shimDisconnectKey = `${this.id}.shimDisconnect` + + constructor({ + chains, + options: options_, + }: { + chains?: Chain[] + options?: InjectedConnectorOptions + } = {}) { + const options = { + name: 'Phantom', + shimDisconnect: true, + getProvider() { + function getReady(ethereum?: WindowProvider) { + const isPhantom = !!ethereum?.isPhantom + if (!isPhantom) return + return ethereum + } + + if (typeof window === 'undefined') return + const ethereum = window?.phantom?.ethereum as WindowProvider | undefined + if (ethereum?.providers) return ethereum.providers.find(getReady) + return getReady(ethereum) + }, + ...options_, + } + super({ chains, options }) + } + + async connect({ chainId }: { chainId?: number } = {}) { + try { + const provider = await this.getProvider() + if (!provider) throw new ConnectorNotFoundError() + + if (provider.on) { + provider.on('accountsChanged', this.onAccountsChanged) + provider.on('chainChanged', this.onChainChanged) + provider.on('disconnect', this.onDisconnect) + } + + this.emit('message', { type: 'connecting' }) + + // Attempt to show wallet select prompt with `wallet_requestPermissions` when + // `shimDisconnect` is active and account is in disconnected state (flag in storage) + let account: Address | null = null + if ( + this.options?.shimDisconnect && + !this.storage?.getItem(this.shimDisconnectKey) + ) { + account = await this.getAccount().catch(() => null) + const isConnected = !!account + if (isConnected) + // Attempt to show another prompt for selecting wallet if already connected + try { + await provider.request({ + method: 'wallet_requestPermissions', + params: [{ eth_accounts: {} }], + }) + // User may have selected a different account so we will need to revalidate here. + account = await this.getAccount() + } catch (error) { + if (this.isUserRejectedRequestError(error)) + throw new UserRejectedRequestError(error as Error) + if ( + (error as ProviderRpcError).code === + new ResourceNotFoundRpcError(error as ProviderRpcError).code + ) + throw error + } + } + + if (!account) { + const accounts = await provider.request({ + method: 'eth_requestAccounts', + }) + account = getAddress(accounts[0] as string) + } + + // Switch to chain if provided + let id = await this.getChainId() + let unsupported = this.isChainUnsupported(id) + if (chainId && id !== chainId) { + const chain = await this.switchChain(chainId) + id = chain.id + unsupported = this.isChainUnsupported(id) + } + + if (this.options?.shimDisconnect) + this.storage?.setItem(this.shimDisconnectKey, true) + + return { account, chain: { id, unsupported }, provider } + } catch (error) { + if (this.isUserRejectedRequestError(error)) + throw new UserRejectedRequestError(error as Error) + if ((error as ProviderRpcError).code === -32002) + throw new ResourceNotFoundRpcError(error as ProviderRpcError) + throw error + } + } +} diff --git a/frontend/images/phantom.svg b/frontend/images/phantom.svg new file mode 100644 index 00000000..e4bbf2ba --- /dev/null +++ b/frontend/images/phantom.svg @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + From dfb34a7876f3086c84b191d94390d73331693290 Mon Sep 17 00:00:00 2001 From: Solano Date: Mon, 1 Apr 2024 22:45:09 -0300 Subject: [PATCH 10/12] Deployments (#67) * mt-04 * mt-05 * prettier * prettier again * even prettier * prettier --------- Co-authored-by: matias martinez --- backend/src/config.ts | 2 +- frontend/components/Subscribe.tsx | 2 +- frontend/integration/integrationTest.test.ts | 2 +- frontend/sections/TokensReceived.tsx | 2 +- frontend/utils/constants.ts | 2 +- token-dispenser/Anchor.toml | 6 +++--- .../programs/token-dispenser/src/lib.rs | 2 +- token-dispenser/scripts/treasuries | 13 +++++++------ token-dispenser/ts/scripts/config.ts | 14 +++++++------- token-dispenser/ts/sdk/token-dispenser.ts | 4 ---- 10 files changed, 23 insertions(+), 26 deletions(-) diff --git a/backend/src/config.ts b/backend/src/config.ts index c84775c4..fed1fdb2 100644 --- a/backend/src/config.ts +++ b/backend/src/config.ts @@ -5,7 +5,7 @@ export default { aws: { region: process.env.AWS_REGION ?? 'us-east-2' }, - tokenDispenserProgramId: () => 'WapFw9mSyHh8trDDRy7AamUn1V7QiGaVvtouj5AucQA', + tokenDispenserProgramId: () => 'Wapq3Hpv2aSKjWrh4pM8eweh8jVJB7D1nLBw9ikjVYx', secrets: { dispenserGuard: { /** optional. mostly for local testing */ diff --git a/frontend/components/Subscribe.tsx b/frontend/components/Subscribe.tsx index 5f76ecf5..da9247f0 100644 --- a/frontend/components/Subscribe.tsx +++ b/frontend/components/Subscribe.tsx @@ -106,7 +106,7 @@ const Subscribe = () => { onChange={() => setStatus((s) => ({ ...status, terms: !status.terms })) } - className="bg-opacity-15 checkbox h-4 w-4 appearance-none border border-white bg-white" + className="checkbox bg-opacity-15 h-4 w-4 appearance-none border border-white bg-white" /> I agree to receive marketing emails and other communications diff --git a/frontend/integration/integrationTest.test.ts b/frontend/integration/integrationTest.test.ts index 68bd9c1a..5f620b74 100644 --- a/frontend/integration/integrationTest.test.ts +++ b/frontend/integration/integrationTest.test.ts @@ -75,7 +75,7 @@ describe('integration test', () => { const funderWallet = Object.entries(loadFunderWallets())[0][1] const endpoint = 'http://127.0.0.1:8899' const tokenDispenserPid = new PublicKey( - 'WapFw9mSyHh8trDDRy7AamUn1V7QiGaVvtouj5AucQA' + 'Wapq3Hpv2aSKjWrh4pM8eweh8jVJB7D1nLBw9ikjVYx' ) const confirmOpts: anchor.web3.ConfirmOptions = { diff --git a/frontend/sections/TokensReceived.tsx b/frontend/sections/TokensReceived.tsx index 9fdd3556..b841dcbf 100644 --- a/frontend/sections/TokensReceived.tsx +++ b/frontend/sections/TokensReceived.tsx @@ -53,7 +53,7 @@ export const TokensReceived = ({ totalCoinsClaimed }: TokensReceivedProps) => { newsletter.

-
+
diff --git a/frontend/utils/constants.ts b/frontend/utils/constants.ts index 936e9207..9faefbb6 100644 --- a/frontend/utils/constants.ts +++ b/frontend/utils/constants.ts @@ -41,4 +41,4 @@ export const EVM_CHAINS = [ export type EvmChains = typeof EVM_CHAINS[number] export const tokenDispenserProgramId = - 'WapFw9mSyHh8trDDRy7AamUn1V7QiGaVvtouj5AucQA' + 'Wapq3Hpv2aSKjWrh4pM8eweh8jVJB7D1nLBw9ikjVYx' diff --git a/token-dispenser/Anchor.toml b/token-dispenser/Anchor.toml index 922e13cf..34d90634 100644 --- a/token-dispenser/Anchor.toml +++ b/token-dispenser/Anchor.toml @@ -14,13 +14,13 @@ cluster = "devnet" wallet = "../frontend/integration/keys/funder_private_key.json" [programs.localnet] -token_dispenser = "WapFw9mSyHh8trDDRy7AamUn1V7QiGaVvtouj5AucQA" +token_dispenser = "Wapq3Hpv2aSKjWrh4pM8eweh8jVJB7D1nLBw9ikjVYx" [programs.mainnet] -token_dispenser = "WapFw9mSyHh8trDDRy7AamUn1V7QiGaVvtouj5AucQA" +token_dispenser = "Wapq3Hpv2aSKjWrh4pM8eweh8jVJB7D1nLBw9ikjVYx" [programs.devnet] -token_dispenser = "WapFw9mSyHh8trDDRy7AamUn1V7QiGaVvtouj5AucQA" +token_dispenser = "Wapq3Hpv2aSKjWrh4pM8eweh8jVJB7D1nLBw9ikjVYx" [scripts] test = "cargo test-bpf" diff --git a/token-dispenser/programs/token-dispenser/src/lib.rs b/token-dispenser/programs/token-dispenser/src/lib.rs index 3a218370..3cdbc97d 100644 --- a/token-dispenser/programs/token-dispenser/src/lib.rs +++ b/token-dispenser/programs/token-dispenser/src/lib.rs @@ -73,7 +73,7 @@ mod tests; mod ecosystems; -declare_id!("WapFw9mSyHh8trDDRy7AamUn1V7QiGaVvtouj5AucQA"); +declare_id!("Wapq3Hpv2aSKjWrh4pM8eweh8jVJB7D1nLBw9ikjVYx"); const CONFIG_SEED: &[u8] = b"config"; const RECEIPT_SEED: &[u8] = b"receipt"; diff --git a/token-dispenser/scripts/treasuries b/token-dispenser/scripts/treasuries index c31d9682..28283fc3 100644 --- a/token-dispenser/scripts/treasuries +++ b/token-dispenser/scripts/treasuries @@ -1,6 +1,7 @@ -waTh9vNmRz8hHxQv1zW81ExKQ7fwaa1TR6tQT5fTkjg -waTirsbdRyyxm8DFxH9Z9P5Pyrj74jJ7E74zqhmGX1k -wAtMcoqwHb7obEL2USNXPqxg1CmJDSjjjsNcEm9bzCZ -Wats1sM7W4UvxUuQPevGxexgcaFiaXMXxActKUmcvHx -waTtgLt1WVRgoWYNZh97AYAUqoU4nN98jVThPdYQVwj -WaTxa5w4TjYHRdHwG2zaN9ynA1c9z4J9TswsBCmzy4N +waTiAKS8FBdnNnGLJv5aF2b1ouwn22ZP1WGd2NsFS1F +wAtQwJteMdGidPcvoeKSVPcvBj6brA38ZQDFSwTQqm3 +WatsKcF7vbvxAMp26pz3yMc4X4R66gNvExCtHwc371H +WATY4JeitW6xZeZa9U4Wy8cxYdk1LtW6s6mmDFhUKuD +waTyocL9rFxerXZNsGP7v7G8VVoR7hDk74Tp4nC7uEV +waTZHsCNgr8SzkbXiwEPBd6PE1pb5owuR1NQotM4zJj +waTyocL9rFxerXZNsGP7v7G8VVoR7hDk74Tp4nC7uEV diff --git a/token-dispenser/ts/scripts/config.ts b/token-dispenser/ts/scripts/config.ts index ec22b8a9..94973f3f 100644 --- a/token-dispenser/ts/scripts/config.ts +++ b/token-dispenser/ts/scripts/config.ts @@ -1,12 +1,12 @@ import { PublicKey } from "@solana/web3.js"; export const treasuries = [ - new PublicKey("waTh9vNmRz8hHxQv1zW81ExKQ7fwaa1TR6tQT5fTkjg"), - new PublicKey("waTirsbdRyyxm8DFxH9Z9P5Pyrj74jJ7E74zqhmGX1k"), - new PublicKey("wAtMcoqwHb7obEL2USNXPqxg1CmJDSjjjsNcEm9bzCZ"), - new PublicKey("Wats1sM7W4UvxUuQPevGxexgcaFiaXMXxActKUmcvHx"), - new PublicKey("waTtgLt1WVRgoWYNZh97AYAUqoU4nN98jVThPdYQVwj"), - new PublicKey("WaTxa5w4TjYHRdHwG2zaN9ynA1c9z4J9TswsBCmzy4N"), + new PublicKey("waTiAKS8FBdnNnGLJv5aF2b1ouwn22ZP1WGd2NsFS1F"), + new PublicKey("wAtQwJteMdGidPcvoeKSVPcvBj6brA38ZQDFSwTQqm3"), + new PublicKey("WatsKcF7vbvxAMp26pz3yMc4X4R66gNvExCtHwc371H"), + new PublicKey("WATY4JeitW6xZeZa9U4Wy8cxYdk1LtW6s6mmDFhUKuD"), + new PublicKey("waTyocL9rFxerXZNsGP7v7G8VVoR7hDk74Tp4nC7uEV"), + new PublicKey("waTZHsCNgr8SzkbXiwEPBd6PE1pb5owuR1NQotM4zJj"), ]; export const funders = [ @@ -19,4 +19,4 @@ export const funders = [ ]; export const tokenDispenserProgramId = - "WapFw9mSyHh8trDDRy7AamUn1V7QiGaVvtouj5AucQA"; + "Wapq3Hpv2aSKjWrh4pM8eweh8jVJB7D1nLBw9ikjVYx"; diff --git a/token-dispenser/ts/sdk/token-dispenser.ts b/token-dispenser/ts/sdk/token-dispenser.ts index d43ae437..6832f827 100644 --- a/token-dispenser/ts/sdk/token-dispenser.ts +++ b/token-dispenser/ts/sdk/token-dispenser.ts @@ -9,8 +9,6 @@ const CONFIG_SEED_PREFIX = "config"; export class TokenDispenserSdk { readonly program: Program; - // readonly mint: PublicKey; - constructor( connection: Connection, args: { @@ -26,7 +24,6 @@ export class TokenDispenserSdk { signAllTransactions: async function (...args: any[]): Promise { throw new Error("ilegal call"); }, - // payer: args.payer, }; const provider = new AnchorProvider( connection, @@ -34,7 +31,6 @@ export class TokenDispenserSdk { AnchorProvider.defaultOptions() ); - // this.program = new Program(IDL as any, new PublicKey(args.programId), provider); this.program = new Program( IDL as any, new PublicKey(args.programId), From f99c8198df818859c9274d9858de1da85ee5a304 Mon Sep 17 00:00:00 2001 From: Solano Date: Mon, 1 Apr 2024 23:54:38 -0300 Subject: [PATCH 11/12] Deployments (#69) * mt-04 * mt-05 * prettier * prettier again * even prettier * prettier * new treasuries --------- Co-authored-by: matias martinez --- frontend/claim_sdk/treasury.ts | 12 ++++++------ token-dispenser/scripts/treasuries | 13 ++++++------- token-dispenser/ts/scripts/config.ts | 12 ++++++------ 3 files changed, 18 insertions(+), 19 deletions(-) diff --git a/frontend/claim_sdk/treasury.ts b/frontend/claim_sdk/treasury.ts index cec841d4..46c0509e 100644 --- a/frontend/claim_sdk/treasury.ts +++ b/frontend/claim_sdk/treasury.ts @@ -3,12 +3,12 @@ import { ClaimInfo } from './claim' import { PublicKey } from '@solana/web3.js' export const treasuries = [ - new PublicKey('waTh9vNmRz8hHxQv1zW81ExKQ7fwaa1TR6tQT5fTkjg'), - new PublicKey('waTirsbdRyyxm8DFxH9Z9P5Pyrj74jJ7E74zqhmGX1k'), - new PublicKey('wAtMcoqwHb7obEL2USNXPqxg1CmJDSjjjsNcEm9bzCZ'), - new PublicKey('Wats1sM7W4UvxUuQPevGxexgcaFiaXMXxActKUmcvHx'), - new PublicKey('waTtgLt1WVRgoWYNZh97AYAUqoU4nN98jVThPdYQVwj'), - new PublicKey('WaTxa5w4TjYHRdHwG2zaN9ynA1c9z4J9TswsBCmzy4N'), + new PublicKey('WaTtAHa1YZB2DFHTZveUSqBnAWsDQtxfN6RC77gmifa'), + new PublicKey('wAT8vs52AcD7B77KpkwVVUgDm5vcb83uDUr1eSuvhTm'), + new PublicKey('wAt9yuPxmredtJxFxM19aeToc5wWZVEfN5L346XPR2o'), + new PublicKey('waTgcmvbUNBCW9h5sd6Fd2ziRJyRTvtTBPiYBNuQUNx'), + new PublicKey('WatWL18fpiB28zMg3mbxxnPfoemx6Pr4YA4rL56PQyg'), + new PublicKey('WaT7ACb6Zvibjh1NN6zNkpdMGBTqPjVigQKxU2MbBWs'), ] export const funders = [ diff --git a/token-dispenser/scripts/treasuries b/token-dispenser/scripts/treasuries index 28283fc3..def7d049 100644 --- a/token-dispenser/scripts/treasuries +++ b/token-dispenser/scripts/treasuries @@ -1,7 +1,6 @@ -waTiAKS8FBdnNnGLJv5aF2b1ouwn22ZP1WGd2NsFS1F -wAtQwJteMdGidPcvoeKSVPcvBj6brA38ZQDFSwTQqm3 -WatsKcF7vbvxAMp26pz3yMc4X4R66gNvExCtHwc371H -WATY4JeitW6xZeZa9U4Wy8cxYdk1LtW6s6mmDFhUKuD -waTyocL9rFxerXZNsGP7v7G8VVoR7hDk74Tp4nC7uEV -waTZHsCNgr8SzkbXiwEPBd6PE1pb5owuR1NQotM4zJj -waTyocL9rFxerXZNsGP7v7G8VVoR7hDk74Tp4nC7uEV +WaTtAHa1YZB2DFHTZveUSqBnAWsDQtxfN6RC77gmifa +wAT8vs52AcD7B77KpkwVVUgDm5vcb83uDUr1eSuvhTm +wAt9yuPxmredtJxFxM19aeToc5wWZVEfN5L346XPR2o +waTgcmvbUNBCW9h5sd6Fd2ziRJyRTvtTBPiYBNuQUNx +WatWL18fpiB28zMg3mbxxnPfoemx6Pr4YA4rL56PQyg +WaT7ACb6Zvibjh1NN6zNkpdMGBTqPjVigQKxU2MbBWs diff --git a/token-dispenser/ts/scripts/config.ts b/token-dispenser/ts/scripts/config.ts index 94973f3f..356a81c8 100644 --- a/token-dispenser/ts/scripts/config.ts +++ b/token-dispenser/ts/scripts/config.ts @@ -1,12 +1,12 @@ import { PublicKey } from "@solana/web3.js"; export const treasuries = [ - new PublicKey("waTiAKS8FBdnNnGLJv5aF2b1ouwn22ZP1WGd2NsFS1F"), - new PublicKey("wAtQwJteMdGidPcvoeKSVPcvBj6brA38ZQDFSwTQqm3"), - new PublicKey("WatsKcF7vbvxAMp26pz3yMc4X4R66gNvExCtHwc371H"), - new PublicKey("WATY4JeitW6xZeZa9U4Wy8cxYdk1LtW6s6mmDFhUKuD"), - new PublicKey("waTyocL9rFxerXZNsGP7v7G8VVoR7hDk74Tp4nC7uEV"), - new PublicKey("waTZHsCNgr8SzkbXiwEPBd6PE1pb5owuR1NQotM4zJj"), + new PublicKey("WaTtAHa1YZB2DFHTZveUSqBnAWsDQtxfN6RC77gmifa"), + new PublicKey("wAT8vs52AcD7B77KpkwVVUgDm5vcb83uDUr1eSuvhTm"), + new PublicKey("wAt9yuPxmredtJxFxM19aeToc5wWZVEfN5L346XPR2o"), + new PublicKey("waTgcmvbUNBCW9h5sd6Fd2ziRJyRTvtTBPiYBNuQUNx"), + new PublicKey("WatWL18fpiB28zMg3mbxxnPfoemx6Pr4YA4rL56PQyg"), + new PublicKey("WaT7ACb6Zvibjh1NN6zNkpdMGBTqPjVigQKxU2MbBWs"), ]; export const funders = [ From d041392b2463bb066d0c442f4d99507a2946cfc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=ADas=20Mart=C3=ADnez?= <131624652+mat1asm@users.noreply.github.com> Date: Tue, 2 Apr 2024 01:07:04 -0300 Subject: [PATCH 12/12] be: change influx secret key name (#68) * be: change influx secret key name * logging stuff --- backend/src/utils/persistence.ts | 6 +++++- backend/src/utils/secrets.ts | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/backend/src/utils/persistence.ts b/backend/src/utils/persistence.ts index 92aaeb83..57b42a1c 100644 --- a/backend/src/utils/persistence.ts +++ b/backend/src/utils/persistence.ts @@ -117,10 +117,14 @@ function mapIdentity(claimSignature: ClaimSignature) { async function initInfluxWriter() { const token = await getInfluxToken() + console.log('Influx URL: ' + config.influx.url()) + console.log('Influx ORG: ' + config.influx.org()) + console.log('Influx BUCKET: ' + config.influx.bucket()) + return new InfluxDB({ url: config.influx.url(), token - }).getWriteApi(config.influx.org(), config.influx.bucket(), 'ms') + }).getWriteApi(config.influx.org(), config.influx.bucket()) } process.on('SIGTERM', async () => { diff --git a/backend/src/utils/secrets.ts b/backend/src/utils/secrets.ts index f148c0d1..b39c0cef 100644 --- a/backend/src/utils/secrets.ts +++ b/backend/src/utils/secrets.ts @@ -38,7 +38,7 @@ export async function getInfluxToken(): Promise { console.log('Using influx token from config') key = config.secrets.influx.key()! } else { - key = await getSecretKey(config.secrets.influx.secretName, 'key') + key = await getSecretKey(config.secrets.influx.secretName, 'idb-token') } return key