diff --git a/packages/chain-adapters/src/solana/SolanaChainAdapter.ts b/packages/chain-adapters/src/solana/SolanaChainAdapter.ts index a2cc85d81af..ab22e5aa920 100644 --- a/packages/chain-adapters/src/solana/SolanaChainAdapter.ts +++ b/packages/chain-adapters/src/solana/SolanaChainAdapter.ts @@ -140,6 +140,10 @@ export class ChainAdapter implements IChainAdapter return this.chainId } + getConnection(): Connection { + return this.connection + } + getBIP44Params({ accountNumber }: GetBIP44ParamsInput): BIP44Params { if (accountNumber < 0) throw new Error('accountNumber must be >= 0') return { ...ChainAdapter.defaultBIP44Params, accountNumber } diff --git a/packages/swapper/package.json b/packages/swapper/package.json index f279ac32dee..f047a2a63e6 100644 --- a/packages/swapper/package.json +++ b/packages/swapper/package.json @@ -17,6 +17,7 @@ "dev": "yarn run -T tsc --build --watch" }, "dependencies": { + "@coral-xyz/anchor": "0.29.0", "@shapeshiftoss/caip": "workspace:^", "@shapeshiftoss/chain-adapters": "workspace:^", "@shapeshiftoss/types": "workspace:^", diff --git a/packages/swapper/src/swappers/JupiterSwapper/idls/referral.ts b/packages/swapper/src/swappers/JupiterSwapper/idls/referral.ts new file mode 100644 index 00000000000..a6a0be5a4f4 --- /dev/null +++ b/packages/swapper/src/swappers/JupiterSwapper/idls/referral.ts @@ -0,0 +1,1477 @@ +export type Referral = { + version: '0.1.0' + name: 'referral' + instructions: [ + { + name: 'initializeProject' + accounts: [ + { + name: 'payer' + isMut: true + isSigner: true + }, + { + name: 'base' + isMut: false + isSigner: true + }, + { + name: 'admin' + isMut: false + isSigner: false + }, + { + name: 'project' + isMut: true + isSigner: false + }, + { + name: 'systemProgram' + isMut: false + isSigner: false + }, + ] + args: [ + { + name: 'params' + type: { + defined: 'InitializeProjectParams' + } + }, + ] + }, + { + name: 'initializeReferralAccount' + accounts: [ + { + name: 'payer' + isMut: true + isSigner: true + }, + { + name: 'partner' + isMut: false + isSigner: false + }, + { + name: 'project' + isMut: false + isSigner: false + }, + { + name: 'referralAccount' + isMut: true + isSigner: true + }, + { + name: 'systemProgram' + isMut: false + isSigner: false + }, + ] + args: [ + { + name: 'params' + type: { + defined: 'InitializeReferralAccountParams' + } + }, + ] + }, + { + name: 'initializeReferralAccountWithName' + accounts: [ + { + name: 'payer' + isMut: true + isSigner: true + }, + { + name: 'partner' + isMut: false + isSigner: false + }, + { + name: 'project' + isMut: false + isSigner: false + }, + { + name: 'referralAccount' + isMut: true + isSigner: false + }, + { + name: 'systemProgram' + isMut: false + isSigner: false + }, + ] + args: [ + { + name: 'params' + type: { + defined: 'InitializeReferralAccountWithNameParams' + } + }, + ] + }, + { + name: 'updateProject' + accounts: [ + { + name: 'admin' + isMut: false + isSigner: true + }, + { + name: 'project' + isMut: true + isSigner: false + }, + ] + args: [ + { + name: 'params' + type: { + defined: 'UpdateProjectParams' + } + }, + ] + }, + { + name: 'transferProject' + accounts: [ + { + name: 'admin' + isMut: false + isSigner: true + }, + { + name: 'newAdmin' + isMut: false + isSigner: false + }, + { + name: 'project' + isMut: true + isSigner: false + }, + ] + args: [ + { + name: 'params' + type: { + defined: 'TransferProjectParams' + } + }, + ] + }, + { + name: 'updateReferralAccount' + accounts: [ + { + name: 'admin' + isMut: false + isSigner: true + }, + { + name: 'project' + isMut: false + isSigner: false + }, + { + name: 'referralAccount' + isMut: true + isSigner: false + }, + ] + args: [ + { + name: 'params' + type: { + defined: 'UpdateReferralAccountParams' + } + }, + ] + }, + { + name: 'transferReferralAccount' + accounts: [ + { + name: 'partner' + isMut: false + isSigner: true + }, + { + name: 'newPartner' + isMut: false + isSigner: false + }, + { + name: 'referralAccount' + isMut: true + isSigner: false + }, + ] + args: [ + { + name: 'params' + type: { + defined: 'TransferReferralAccountParams' + } + }, + ] + }, + { + name: 'initializeReferralTokenAccount' + accounts: [ + { + name: 'payer' + isMut: true + isSigner: true + }, + { + name: 'project' + isMut: false + isSigner: false + }, + { + name: 'referralAccount' + isMut: false + isSigner: false + }, + { + name: 'referralTokenAccount' + isMut: true + isSigner: false + }, + { + name: 'mint' + isMut: false + isSigner: false + }, + { + name: 'systemProgram' + isMut: false + isSigner: false + }, + { + name: 'tokenProgram' + isMut: false + isSigner: false + }, + ] + args: [] + }, + { + name: 'claim' + accounts: [ + { + name: 'payer' + isMut: true + isSigner: true + }, + { + name: 'project' + isMut: false + isSigner: false + }, + { + name: 'admin' + isMut: false + isSigner: false + }, + { + name: 'projectAdminTokenAccount' + isMut: true + isSigner: false + }, + { + name: 'referralAccount' + isMut: false + isSigner: false + }, + { + name: 'referralTokenAccount' + isMut: true + isSigner: false + }, + { + name: 'partner' + isMut: false + isSigner: false + }, + { + name: 'partnerTokenAccount' + isMut: true + isSigner: false + }, + { + name: 'mint' + isMut: false + isSigner: false + }, + { + name: 'associatedTokenProgram' + isMut: false + isSigner: false + }, + { + name: 'systemProgram' + isMut: false + isSigner: false + }, + { + name: 'tokenProgram' + isMut: false + isSigner: false + }, + ] + args: [] + }, + { + name: 'createAdminTokenAccount' + accounts: [ + { + name: 'project' + isMut: false + isSigner: false + }, + { + name: 'projectAuthority' + isMut: true + isSigner: false + }, + { + name: 'admin' + isMut: false + isSigner: false + }, + { + name: 'projectAdminTokenAccount' + isMut: true + isSigner: false + }, + { + name: 'mint' + isMut: false + isSigner: false + }, + { + name: 'systemProgram' + isMut: false + isSigner: false + }, + { + name: 'tokenProgram' + isMut: false + isSigner: false + }, + { + name: 'associatedTokenProgram' + isMut: false + isSigner: false + }, + ] + args: [] + }, + { + name: 'withdrawFromProject' + accounts: [ + { + name: 'admin' + isMut: true + isSigner: true + }, + { + name: 'project' + isMut: false + isSigner: false + }, + { + name: 'projectAuthority' + isMut: true + isSigner: false + }, + { + name: 'systemProgram' + isMut: false + isSigner: false + }, + ] + args: [ + { + name: 'params' + type: { + defined: 'WithdrawFromProjectParams' + } + }, + ] + }, + ] + accounts: [ + { + name: 'project' + type: { + kind: 'struct' + fields: [ + { + name: 'base' + type: 'publicKey' + }, + { + name: 'admin' + type: 'publicKey' + }, + { + name: 'name' + type: 'string' + }, + { + name: 'defaultShareBps' + type: 'u16' + }, + ] + } + }, + { + name: 'referralAccount' + type: { + kind: 'struct' + fields: [ + { + name: 'partner' + type: 'publicKey' + }, + { + name: 'project' + type: 'publicKey' + }, + { + name: 'shareBps' + type: 'u16' + }, + { + name: 'name' + type: { + option: 'string' + } + }, + ] + } + }, + ] + types: [ + { + name: 'InitializeProjectParams' + type: { + kind: 'struct' + fields: [ + { + name: 'name' + type: 'string' + }, + { + name: 'defaultShareBps' + type: 'u16' + }, + ] + } + }, + { + name: 'InitializeReferralAccountWithNameParams' + type: { + kind: 'struct' + fields: [ + { + name: 'name' + type: 'string' + }, + ] + } + }, + { + name: 'InitializeReferralAccountParams' + type: { + kind: 'struct' + fields: [] + } + }, + { + name: 'TransferProjectParams' + type: { + kind: 'struct' + fields: [] + } + }, + { + name: 'TransferReferralAccountParams' + type: { + kind: 'struct' + fields: [] + } + }, + { + name: 'UpdateProjectParams' + type: { + kind: 'struct' + fields: [ + { + name: 'name' + type: { + option: 'string' + } + }, + { + name: 'defaultShareBps' + type: { + option: 'u16' + } + }, + ] + } + }, + { + name: 'UpdateReferralAccountParams' + type: { + kind: 'struct' + fields: [ + { + name: 'shareBps' + type: 'u16' + }, + ] + } + }, + { + name: 'WithdrawFromProjectParams' + type: { + kind: 'struct' + fields: [ + { + name: 'amount' + type: 'u64' + }, + ] + } + }, + ] + events: [ + { + name: 'InitializeProjectEvent' + fields: [ + { + name: 'project' + type: 'publicKey' + index: false + }, + { + name: 'admin' + type: 'publicKey' + index: false + }, + { + name: 'name' + type: 'string' + index: false + }, + { + name: 'defaultShareBps' + type: 'u16' + index: false + }, + ] + }, + { + name: 'UpdateProjectEvent' + fields: [ + { + name: 'project' + type: 'publicKey' + index: false + }, + { + name: 'name' + type: 'string' + index: false + }, + { + name: 'defaultShareBps' + type: 'u16' + index: false + }, + ] + }, + { + name: 'InitializeReferralAccountEvent' + fields: [ + { + name: 'project' + type: 'publicKey' + index: false + }, + { + name: 'partner' + type: 'publicKey' + index: false + }, + { + name: 'referralAccount' + type: 'publicKey' + index: false + }, + { + name: 'shareBps' + type: 'u16' + index: false + }, + { + name: 'name' + type: { + option: 'string' + } + index: false + }, + ] + }, + { + name: 'UpdateReferralAccountEvent' + fields: [ + { + name: 'referralAccount' + type: 'publicKey' + index: false + }, + { + name: 'shareBps' + type: 'u16' + index: false + }, + ] + }, + { + name: 'InitializeReferralTokenAccountEvent' + fields: [ + { + name: 'project' + type: 'publicKey' + index: false + }, + { + name: 'referralAccount' + type: 'publicKey' + index: false + }, + { + name: 'referralTokenAccount' + type: 'publicKey' + index: false + }, + { + name: 'mint' + type: 'publicKey' + index: false + }, + ] + }, + { + name: 'ClaimEvent' + fields: [ + { + name: 'project' + type: 'publicKey' + index: false + }, + { + name: 'projectAdminTokenAccount' + type: 'publicKey' + index: false + }, + { + name: 'referralAccount' + type: 'publicKey' + index: false + }, + { + name: 'referralTokenAccount' + type: 'publicKey' + index: false + }, + { + name: 'partnerTokenAccount' + type: 'publicKey' + index: false + }, + { + name: 'mint' + type: 'publicKey' + index: false + }, + { + name: 'referralAmount' + type: 'u64' + index: false + }, + { + name: 'projectAmount' + type: 'u64' + index: false + }, + ] + }, + ] + errors: [ + { + code: 6000 + name: 'InvalidCalculation' + }, + { + code: 6001 + name: 'InvalidSharePercentage' + }, + { + code: 6002 + name: 'NameTooLong' + }, + ] +} + +export const referralIdl: Referral = { + version: '0.1.0', + name: 'referral', + instructions: [ + { + name: 'initializeProject', + accounts: [ + { + name: 'payer', + isMut: true, + isSigner: true, + }, + { + name: 'base', + isMut: false, + isSigner: true, + }, + { + name: 'admin', + isMut: false, + isSigner: false, + }, + { + name: 'project', + isMut: true, + isSigner: false, + }, + { + name: 'systemProgram', + isMut: false, + isSigner: false, + }, + ], + args: [ + { + name: 'params', + type: { + defined: 'InitializeProjectParams', + }, + }, + ], + }, + { + name: 'initializeReferralAccount', + accounts: [ + { + name: 'payer', + isMut: true, + isSigner: true, + }, + { + name: 'partner', + isMut: false, + isSigner: false, + }, + { + name: 'project', + isMut: false, + isSigner: false, + }, + { + name: 'referralAccount', + isMut: true, + isSigner: true, + }, + { + name: 'systemProgram', + isMut: false, + isSigner: false, + }, + ], + args: [ + { + name: 'params', + type: { + defined: 'InitializeReferralAccountParams', + }, + }, + ], + }, + { + name: 'initializeReferralAccountWithName', + accounts: [ + { + name: 'payer', + isMut: true, + isSigner: true, + }, + { + name: 'partner', + isMut: false, + isSigner: false, + }, + { + name: 'project', + isMut: false, + isSigner: false, + }, + { + name: 'referralAccount', + isMut: true, + isSigner: false, + }, + { + name: 'systemProgram', + isMut: false, + isSigner: false, + }, + ], + args: [ + { + name: 'params', + type: { + defined: 'InitializeReferralAccountWithNameParams', + }, + }, + ], + }, + { + name: 'updateProject', + accounts: [ + { + name: 'admin', + isMut: false, + isSigner: true, + }, + { + name: 'project', + isMut: true, + isSigner: false, + }, + ], + args: [ + { + name: 'params', + type: { + defined: 'UpdateProjectParams', + }, + }, + ], + }, + { + name: 'transferProject', + accounts: [ + { + name: 'admin', + isMut: false, + isSigner: true, + }, + { + name: 'newAdmin', + isMut: false, + isSigner: false, + }, + { + name: 'project', + isMut: true, + isSigner: false, + }, + ], + args: [ + { + name: 'params', + type: { + defined: 'TransferProjectParams', + }, + }, + ], + }, + { + name: 'updateReferralAccount', + accounts: [ + { + name: 'admin', + isMut: false, + isSigner: true, + }, + { + name: 'project', + isMut: false, + isSigner: false, + }, + { + name: 'referralAccount', + isMut: true, + isSigner: false, + }, + ], + args: [ + { + name: 'params', + type: { + defined: 'UpdateReferralAccountParams', + }, + }, + ], + }, + { + name: 'transferReferralAccount', + accounts: [ + { + name: 'partner', + isMut: false, + isSigner: true, + }, + { + name: 'newPartner', + isMut: false, + isSigner: false, + }, + { + name: 'referralAccount', + isMut: true, + isSigner: false, + }, + ], + args: [ + { + name: 'params', + type: { + defined: 'TransferReferralAccountParams', + }, + }, + ], + }, + { + name: 'initializeReferralTokenAccount', + accounts: [ + { + name: 'payer', + isMut: true, + isSigner: true, + }, + { + name: 'project', + isMut: false, + isSigner: false, + }, + { + name: 'referralAccount', + isMut: false, + isSigner: false, + }, + { + name: 'referralTokenAccount', + isMut: true, + isSigner: false, + }, + { + name: 'mint', + isMut: false, + isSigner: false, + }, + { + name: 'systemProgram', + isMut: false, + isSigner: false, + }, + { + name: 'tokenProgram', + isMut: false, + isSigner: false, + }, + ], + args: [], + }, + { + name: 'claim', + accounts: [ + { + name: 'payer', + isMut: true, + isSigner: true, + }, + { + name: 'project', + isMut: false, + isSigner: false, + }, + { + name: 'admin', + isMut: false, + isSigner: false, + }, + { + name: 'projectAdminTokenAccount', + isMut: true, + isSigner: false, + }, + { + name: 'referralAccount', + isMut: false, + isSigner: false, + }, + { + name: 'referralTokenAccount', + isMut: true, + isSigner: false, + }, + { + name: 'partner', + isMut: false, + isSigner: false, + }, + { + name: 'partnerTokenAccount', + isMut: true, + isSigner: false, + }, + { + name: 'mint', + isMut: false, + isSigner: false, + }, + { + name: 'associatedTokenProgram', + isMut: false, + isSigner: false, + }, + { + name: 'systemProgram', + isMut: false, + isSigner: false, + }, + { + name: 'tokenProgram', + isMut: false, + isSigner: false, + }, + ], + args: [], + }, + { + name: 'createAdminTokenAccount', + accounts: [ + { + name: 'project', + isMut: false, + isSigner: false, + }, + { + name: 'projectAuthority', + isMut: true, + isSigner: false, + }, + { + name: 'admin', + isMut: false, + isSigner: false, + }, + { + name: 'projectAdminTokenAccount', + isMut: true, + isSigner: false, + }, + { + name: 'mint', + isMut: false, + isSigner: false, + }, + { + name: 'systemProgram', + isMut: false, + isSigner: false, + }, + { + name: 'tokenProgram', + isMut: false, + isSigner: false, + }, + { + name: 'associatedTokenProgram', + isMut: false, + isSigner: false, + }, + ], + args: [], + }, + { + name: 'withdrawFromProject', + accounts: [ + { + name: 'admin', + isMut: true, + isSigner: true, + }, + { + name: 'project', + isMut: false, + isSigner: false, + }, + { + name: 'projectAuthority', + isMut: true, + isSigner: false, + }, + { + name: 'systemProgram', + isMut: false, + isSigner: false, + }, + ], + args: [ + { + name: 'params', + type: { + defined: 'WithdrawFromProjectParams', + }, + }, + ], + }, + ], + accounts: [ + { + name: 'project', + type: { + kind: 'struct', + fields: [ + { + name: 'base', + type: 'publicKey', + }, + { + name: 'admin', + type: 'publicKey', + }, + { + name: 'name', + type: 'string', + }, + { + name: 'defaultShareBps', + type: 'u16', + }, + ], + }, + }, + { + name: 'referralAccount', + type: { + kind: 'struct', + fields: [ + { + name: 'partner', + type: 'publicKey', + }, + { + name: 'project', + type: 'publicKey', + }, + { + name: 'shareBps', + type: 'u16', + }, + { + name: 'name', + type: { + option: 'string', + }, + }, + ], + }, + }, + ], + types: [ + { + name: 'InitializeProjectParams', + type: { + kind: 'struct', + fields: [ + { + name: 'name', + type: 'string', + }, + { + name: 'defaultShareBps', + type: 'u16', + }, + ], + }, + }, + { + name: 'InitializeReferralAccountWithNameParams', + type: { + kind: 'struct', + fields: [ + { + name: 'name', + type: 'string', + }, + ], + }, + }, + { + name: 'InitializeReferralAccountParams', + type: { + kind: 'struct', + fields: [], + }, + }, + { + name: 'TransferProjectParams', + type: { + kind: 'struct', + fields: [], + }, + }, + { + name: 'TransferReferralAccountParams', + type: { + kind: 'struct', + fields: [], + }, + }, + { + name: 'UpdateProjectParams', + type: { + kind: 'struct', + fields: [ + { + name: 'name', + type: { + option: 'string', + }, + }, + { + name: 'defaultShareBps', + type: { + option: 'u16', + }, + }, + ], + }, + }, + { + name: 'UpdateReferralAccountParams', + type: { + kind: 'struct', + fields: [ + { + name: 'shareBps', + type: 'u16', + }, + ], + }, + }, + { + name: 'WithdrawFromProjectParams', + type: { + kind: 'struct', + fields: [ + { + name: 'amount', + type: 'u64', + }, + ], + }, + }, + ], + events: [ + { + name: 'InitializeProjectEvent', + fields: [ + { + name: 'project', + type: 'publicKey', + index: false, + }, + { + name: 'admin', + type: 'publicKey', + index: false, + }, + { + name: 'name', + type: 'string', + index: false, + }, + { + name: 'defaultShareBps', + type: 'u16', + index: false, + }, + ], + }, + { + name: 'UpdateProjectEvent', + fields: [ + { + name: 'project', + type: 'publicKey', + index: false, + }, + { + name: 'name', + type: 'string', + index: false, + }, + { + name: 'defaultShareBps', + type: 'u16', + index: false, + }, + ], + }, + { + name: 'InitializeReferralAccountEvent', + fields: [ + { + name: 'project', + type: 'publicKey', + index: false, + }, + { + name: 'partner', + type: 'publicKey', + index: false, + }, + { + name: 'referralAccount', + type: 'publicKey', + index: false, + }, + { + name: 'shareBps', + type: 'u16', + index: false, + }, + { + name: 'name', + type: { + option: 'string', + }, + index: false, + }, + ], + }, + { + name: 'UpdateReferralAccountEvent', + fields: [ + { + name: 'referralAccount', + type: 'publicKey', + index: false, + }, + { + name: 'shareBps', + type: 'u16', + index: false, + }, + ], + }, + { + name: 'InitializeReferralTokenAccountEvent', + fields: [ + { + name: 'project', + type: 'publicKey', + index: false, + }, + { + name: 'referralAccount', + type: 'publicKey', + index: false, + }, + { + name: 'referralTokenAccount', + type: 'publicKey', + index: false, + }, + { + name: 'mint', + type: 'publicKey', + index: false, + }, + ], + }, + { + name: 'ClaimEvent', + fields: [ + { + name: 'project', + type: 'publicKey', + index: false, + }, + { + name: 'projectAdminTokenAccount', + type: 'publicKey', + index: false, + }, + { + name: 'referralAccount', + type: 'publicKey', + index: false, + }, + { + name: 'referralTokenAccount', + type: 'publicKey', + index: false, + }, + { + name: 'partnerTokenAccount', + type: 'publicKey', + index: false, + }, + { + name: 'mint', + type: 'publicKey', + index: false, + }, + { + name: 'referralAmount', + type: 'u64', + index: false, + }, + { + name: 'projectAmount', + type: 'u64', + index: false, + }, + ], + }, + ], + errors: [ + { + code: 6000, + name: 'InvalidCalculation', + }, + { + code: 6001, + name: 'InvalidSharePercentage', + }, + { + code: 6002, + name: 'NameTooLong', + }, + ], +} diff --git a/packages/swapper/src/swappers/JupiterSwapper/swapperApi/getTradeQuote.ts b/packages/swapper/src/swappers/JupiterSwapper/swapperApi/getTradeQuote.ts index c305cda2e1b..0865311c85c 100644 --- a/packages/swapper/src/swappers/JupiterSwapper/swapperApi/getTradeQuote.ts +++ b/packages/swapper/src/swappers/JupiterSwapper/swapperApi/getTradeQuote.ts @@ -1,10 +1,8 @@ -import type { Instruction } from '@jup-ag/api' import type { AssetId } from '@shapeshiftoss/caip' import { ASSET_NAMESPACE, CHAIN_NAMESPACE, CHAIN_REFERENCE, - fromAssetId, solAssetId, toAssetId, wrappedSolAssetId, @@ -14,9 +12,6 @@ import type { KnownChainIds } from '@shapeshiftoss/types' import { bn, bnOrZero, convertDecimalPercentageToBasisPoints } from '@shapeshiftoss/utils' import type { Result } from '@sniptt/monads' import { Err, Ok } from '@sniptt/monads' -import type { TransactionInstruction } from '@solana/web3.js' -import { PublicKey } from '@solana/web3.js' -import type { AxiosError } from 'axios' import { v4 as uuid } from 'uuid' import type { @@ -29,7 +24,12 @@ import type { import { SwapperName, TradeQuoteError } from '../../../types' import { getInputOutputRate, makeSwapErrorRight } from '../../../utils' import { JUPITER_COMPUTE_UNIT_MARGIN_MULTIPLIER } from '../utils/constants' -import { getJupiterPrice, getJupiterSwapInstructions, isSupportedChainId } from '../utils/helpers' +import { + calculateAccountCreationCosts, + createSwapInstructions, + getJupiterPrice, + isSupportedChainId, +} from '../utils/helpers' export const getTradeQuote = async ( input: CommonTradeQuoteInput, @@ -50,6 +50,8 @@ export const getTradeQuote = async ( const jupiterUrl = deps.config.REACT_APP_JUPITER_API_URL + const solAsset = assetsById[solAssetId] + if (accountNumber === undefined) { return Err( makeSwapErrorRight({ @@ -88,6 +90,15 @@ export const getTradeQuote = async ( ) } + if (!solAsset) { + return Err( + makeSwapErrorRight({ + message: `solAsset is required`, + code: TradeQuoteError.UnknownError, + }), + ) + } + const maybePriceResponse = await getJupiterPrice({ apiUrl: jupiterUrl, sourceAsset: sellAsset.assetId === solAssetId ? wrappedSolAssetId : sellAsset.assetId, @@ -115,62 +126,19 @@ export const getTradeQuote = async ( // e.g for 0.5% bps, Jupiter represents this as 50. 50/100 = 0.5, then we div by 100 again to honour our decimal format e.g 0.5/100 = 0.005 bn(priceResponse.slippageBps).div(100).div(100).toString() - const contractAddress = - buyAsset.assetId === solAssetId ? undefined : fromAssetId(buyAsset.assetId).assetReference - const adapter = deps.assertGetSolanaChainAdapter(sellAsset.chainId) - const isCrossAccountTrade = receiveAddress ? receiveAddress !== sendAddress : false - - const { instruction: createTokenAccountInstruction, destinationTokenAccount } = - contractAddress && isCrossAccountTrade - ? await adapter.createAssociatedTokenAccountInstruction({ - from: sendAddress, - to: receiveAddress!, - tokenId: contractAddress, - }) - : { instruction: undefined, destinationTokenAccount: undefined } - - const maybeSwapResponse = await getJupiterSwapInstructions({ - apiUrl: jupiterUrl, - fromAddress: sendAddress, - toAddress: isCrossAccountTrade ? destinationTokenAccount?.toString() : undefined, - rawQuote: priceResponse, - // Shared account is not supported for simple AMMs - useSharedAccounts: priceResponse.routePlan.length > 1 && isCrossAccountTrade ? true : false, - }) - - if (maybeSwapResponse.isErr()) { - const error = maybeSwapResponse.unwrapErr() - const cause = error.cause as AxiosError - throw Error(cause.response!.data.detail) - } - - const { data: swapResponse } = maybeSwapResponse.unwrap() - - const convertJupiterInstruction = (instruction: Instruction): TransactionInstruction => ({ - ...instruction, - keys: instruction.accounts.map(account => ({ - ...account, - pubkey: new PublicKey(account.pubkey), - })), - data: Buffer.from(instruction.data, 'base64'), - programId: new PublicKey(instruction.programId), + const { instructions, addressLookupTableAddresses } = await createSwapInstructions({ + priceResponse, + sendAddress, + receiveAddress, + affiliateBps, + buyAsset, + sellAsset, + adapter, + jupiterUrl, }) - const instructions: TransactionInstruction[] = [ - ...swapResponse.setupInstructions.map(convertJupiterInstruction), - convertJupiterInstruction(swapResponse.swapInstruction), - ] - - if (createTokenAccountInstruction) { - instructions.unshift(createTokenAccountInstruction) - } - - if (swapResponse.cleanupInstruction) { - instructions.push(convertJupiterInstruction(swapResponse.cleanupInstruction)) - } - const getFeeData = async () => { const sellAdapter = deps.assertGetSolanaChainAdapter(sellAsset.chainId) const getFeeDataInput: GetFeeDataInput = { @@ -178,7 +146,7 @@ export const getTradeQuote = async ( value: '0', chainSpecific: { from: sendAddress, - addressLookupTableAccounts: swapResponse.addressLookupTableAddresses, + addressLookupTableAccounts: addressLookupTableAddresses, instructions, }, } @@ -230,6 +198,18 @@ export const getTradeQuote = async ( buyAsset, }) + const accountCreationFees = calculateAccountCreationCosts(instructions) + + if (accountCreationFees !== '0') { + const solProtocolFeeAmount = bnOrZero(protocolFees[solAssetId]?.amountCryptoBaseUnit) + + protocolFees[solAssetId] = { + requiresBalance: true, + amountCryptoBaseUnit: bnOrZero(solProtocolFeeAmount).plus(accountCreationFees).toFixed(), + asset: solAsset, + } + } + const tradeQuote: TradeQuote = { id: uuid(), rate, @@ -245,7 +225,7 @@ export const getTradeQuote = async ( sellAmountIncludingProtocolFeesCryptoBaseUnit: priceResponse.inAmount, jupiterQuoteResponse: priceResponse, jupiterTransactionMetadata: { - addressLookupTableAddresses: swapResponse.addressLookupTableAddresses, + addressLookupTableAddresses, instructions, }, feeData: { diff --git a/packages/swapper/src/swappers/JupiterSwapper/swapperApi/getTradeRate.ts b/packages/swapper/src/swappers/JupiterSwapper/swapperApi/getTradeRate.ts index 6c2d32b69aa..677dc3dfacc 100644 --- a/packages/swapper/src/swappers/JupiterSwapper/swapperApi/getTradeRate.ts +++ b/packages/swapper/src/swappers/JupiterSwapper/swapperApi/getTradeRate.ts @@ -25,7 +25,12 @@ import type { import { SwapperName, TradeQuoteError } from '../../../types' import { getInputOutputRate, makeSwapErrorRight } from '../../../utils' import { SOLANA_RANDOM_ADDRESS } from '../utils/constants' -import { getJupiterPrice, isSupportedChainId } from '../utils/helpers' +import { + calculateAccountCreationCosts, + createSwapInstructions, + getJupiterPrice, + isSupportedChainId, +} from '../utils/helpers' export const getTradeRate = async ( input: GetTradeRateInput, @@ -45,6 +50,8 @@ export const getTradeRate = async ( const jupiterUrl = deps.config.REACT_APP_JUPITER_API_URL + const solAsset = assetsById[solAssetId] + if (!isSupportedChainId(sellAsset.chainId)) { return Err( makeSwapErrorRight({ @@ -74,6 +81,15 @@ export const getTradeRate = async ( ) } + if (!solAsset) { + return Err( + makeSwapErrorRight({ + message: `solAsset should be defined`, + code: TradeQuoteError.UnknownError, + }), + ) + } + const maybePriceResponse = await getJupiterPrice({ apiUrl: jupiterUrl, sourceAsset: sellAsset.assetId === solAssetId ? wrappedSolAssetId : sellAsset.assetId, @@ -114,6 +130,8 @@ export const getTradeRate = async ( return { networkFeeCryptoBaseUnit: fast.txFee } } + const adapter = deps.assertGetSolanaChainAdapter(sellAsset.chainId) + const protocolFees: Record = priceResponse.routePlan.reduce( (acc, route) => { const feeAssetId = toAssetId({ @@ -155,6 +173,29 @@ export const getTradeRate = async ( // e.g for 0.5% bps, Jupiter represents this as 50. 50/100 = 0.5, then we div by 100 again to honour our decimal format e.g 0.5/100 = 0.005 bn(priceResponse.slippageBps).div(100).div(100).toString() + const { instructions } = await createSwapInstructions({ + priceResponse, + sendAddress: input.sendAddress ?? SOLANA_RANDOM_ADDRESS, + receiveAddress, + affiliateBps, + buyAsset, + sellAsset, + adapter, + jupiterUrl, + }) + + const accountCreationFees = calculateAccountCreationCosts(instructions) + + if (accountCreationFees !== '0') { + const solProtocolFeeAmount = bnOrZero(protocolFees[solAssetId]?.amountCryptoBaseUnit) + + protocolFees[solAssetId] = { + requiresBalance: true, + amountCryptoBaseUnit: bnOrZero(solProtocolFeeAmount).plus(accountCreationFees).toFixed(), + asset: solAsset, + } + } + const tradeRate: TradeRate = { id: uuid(), rate: inputOutputRate, diff --git a/packages/swapper/src/swappers/JupiterSwapper/utils/constants.ts b/packages/swapper/src/swappers/JupiterSwapper/utils/constants.ts index a196d3a652c..032a7a2c2fb 100644 --- a/packages/swapper/src/swappers/JupiterSwapper/utils/constants.ts +++ b/packages/swapper/src/swappers/JupiterSwapper/utils/constants.ts @@ -10,7 +10,17 @@ export const JUPITER_SUPPORTED_CHAIN_IDS: SupportedChainIds = { buy: jupiterSupportedChainIds, } +export const PDA_ACCOUNT_CREATION_COST = 2040000 + export const SOLANA_RANDOM_ADDRESS = '2zHKF6tqam3tnNFPK2E9nBDkV7GMXnvdJautmzqQdn8A' +export const TOKEN_2022_PROGRAM_ID = 'TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb' + // Jupiter use 40% as a compute unit margin while calculating them, some TX reverts without this export const JUPITER_COMPUTE_UNIT_MARGIN_MULTIPLIER = 1.4 + +export const SHAPESHIFT_JUPITER_REFERRAL_KEY = 'Ajgmo453yGmcHDPoJBrMUj3GFwLVL7HaaZGNLkB8vREG' + +export const JUPITER_AFFILIATE_CONTRACT_ADDRESS = 'REFER4ZgmyYx9c6He5XfaTMiGfdLwRnkV4RPp9t9iF3' + +export const JUPITER_REFERALL_FEE_PROJECT_ACCOUNT = '45ruCyfdRkWpRNGEqWzjCiXRHkZs8WXCLQ67Pnpye7Hp' diff --git a/packages/swapper/src/swappers/JupiterSwapper/utils/helpers.ts b/packages/swapper/src/swappers/JupiterSwapper/utils/helpers.ts index a6ee7ccf62a..0c4993293d3 100644 --- a/packages/swapper/src/swappers/JupiterSwapper/utils/helpers.ts +++ b/packages/swapper/src/swappers/JupiterSwapper/utils/helpers.ts @@ -1,12 +1,25 @@ -import type { QuoteResponse, SwapInstructionsResponse } from '@jup-ag/api' +import { BorshInstructionCoder } from '@coral-xyz/anchor' +import { ASSOCIATED_PROGRAM_ID, TOKEN_PROGRAM_ID } from '@coral-xyz/anchor/dist/cjs/utils/token' +import type { Instruction, QuoteResponse, SwapInstructionsResponse } from '@jup-ag/api' import type { ChainId } from '@shapeshiftoss/caip' -import { fromAssetId } from '@shapeshiftoss/caip' -import type { KnownChainIds } from '@shapeshiftoss/types' +import { fromAssetId, solAssetId, wrappedSolAssetId } from '@shapeshiftoss/caip' +import type { ChainAdapter } from '@shapeshiftoss/chain-adapters/src/solana' +import type { Asset, KnownChainIds } from '@shapeshiftoss/types' +import { bnOrZero } from '@shapeshiftoss/utils' import type { Result } from '@sniptt/monads' -import type { AxiosResponse } from 'axios' +import type { Connection } from '@solana/web3.js' +import { PublicKey, SystemProgram, TransactionInstruction } from '@solana/web3.js' +import type { AxiosError, AxiosResponse } from 'axios' import type { SwapErrorRight } from '../../../types' -import { jupiterSupportedChainIds } from './constants' +import { referralIdl } from '../idls/referral' +import { + JUPITER_AFFILIATE_CONTRACT_ADDRESS, + JUPITER_REFERALL_FEE_PROJECT_ACCOUNT, + jupiterSupportedChainIds, + PDA_ACCOUNT_CREATION_COST, + SHAPESHIFT_JUPITER_REFERRAL_KEY, +} from './constants' import { jupiterService } from './jupiterService' export const isSupportedChainId = (chainId: ChainId): chainId is KnownChainIds.SolanaMainnet => { @@ -30,6 +43,18 @@ type GetJupiterSwapArgs = { rawQuote: unknown toAddress?: string useSharedAccounts: boolean + feeAccount: string | undefined +} + +type CreateInstructionsParams = { + priceResponse: QuoteResponse + sendAddress: string + receiveAddress?: string + affiliateBps: string + buyAsset: Asset + sellAsset: any + adapter: ChainAdapter + jupiterUrl: string } export const getJupiterPrice = ({ @@ -50,13 +75,13 @@ export const getJupiterPrice = ({ `&platformFeeBps=${commissionBps}`, ) -// @TODO: Add DAO's fee account export const getJupiterSwapInstructions = ({ apiUrl, fromAddress, toAddress, rawQuote, useSharedAccounts, + feeAccount, }: GetJupiterSwapArgs): Promise< Result, SwapErrorRight> > => @@ -67,4 +92,222 @@ export const getJupiterSwapInstructions = ({ quoteResponse: rawQuote, dynamicComputeUnitLimit: true, prioritizationFeeLamports: 'auto', + feeAccount, }) + +export const getFeeTokenAccountAndInstruction = async ({ + feePayerPubKey, + programId, + buyAssetReferralPubKey, + sellAssetReferralPubKey, + buyTokenId, + sellTokenId, + instructionData, + connection, +}: { + feePayerPubKey: PublicKey + programId: PublicKey + buyAssetReferralPubKey: PublicKey + sellAssetReferralPubKey: PublicKey + buyTokenId: string + sellTokenId: string + instructionData: Buffer + connection: Connection +}): Promise<{ + tokenAccount?: PublicKey + instruction?: TransactionInstruction | undefined +}> => { + const sellAssetTokenAccount = await connection.getAccountInfo(sellAssetReferralPubKey) + + if (sellAssetTokenAccount) return { tokenAccount: sellAssetReferralPubKey } + + const buyAssetTokenAccount = await connection.getAccountInfo(buyAssetReferralPubKey) + + if (buyAssetTokenAccount) return { tokenAccount: buyAssetReferralPubKey } + + const buyTokenInfo = await connection.getAccountInfo(new PublicKey(buyTokenId)) + const sellTokenInfo = await connection.getAccountInfo(new PublicKey(sellTokenId)) + + if ( + buyTokenInfo?.owner.toString() !== TOKEN_PROGRAM_ID.toString() && + sellTokenInfo?.owner.toString() !== TOKEN_PROGRAM_ID.toString() + ) { + return { tokenAccount: undefined, instruction: undefined } + } + + const project = new PublicKey(JUPITER_REFERALL_FEE_PROJECT_ACCOUNT) + + return { + tokenAccount: sellAssetReferralPubKey, + instruction: new TransactionInstruction({ + keys: [ + { + pubkey: feePayerPubKey, + isSigner: true, + isWritable: true, + }, + { + pubkey: project, + isWritable: false, + isSigner: false, + }, + { + pubkey: new PublicKey(SHAPESHIFT_JUPITER_REFERRAL_KEY), + isSigner: false, + isWritable: false, + }, + { + pubkey: sellAssetReferralPubKey, + isSigner: false, + isWritable: true, + }, + { + pubkey: new PublicKey(buyTokenId), + isSigner: false, + isWritable: false, + }, + { + pubkey: SystemProgram.programId, + isSigner: false, + isWritable: false, + }, + { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }, + ], + data: instructionData, + programId, + }), + } +} + +export const calculateAccountCreationCosts = (instructions: TransactionInstruction[]): string => { + let totalCost = bnOrZero(0) + + for (const ix of instructions) { + if (ix.programId.toString() === ASSOCIATED_PROGRAM_ID.toString()) { + if (ix.data?.[0] === 1) { + totalCost = totalCost.plus(PDA_ACCOUNT_CREATION_COST) + } + } + } + + return totalCost.toString() +} + +export const createSwapInstructions = async ({ + priceResponse, + sendAddress, + receiveAddress, + affiliateBps, + buyAsset, + sellAsset, + adapter, + jupiterUrl, +}: CreateInstructionsParams): Promise<{ + instructions: TransactionInstruction[] + addressLookupTableAddresses: string[] +}> => { + const isCrossAccountTrade = receiveAddress ? receiveAddress !== sendAddress : false + + const buyAssetAddress = + buyAsset.assetId === solAssetId + ? fromAssetId(wrappedSolAssetId).assetReference + : fromAssetId(buyAsset.assetId).assetReference + + const sellAssetAddress = + sellAsset.assetId === solAssetId + ? fromAssetId(wrappedSolAssetId).assetReference + : fromAssetId(sellAsset.assetId).assetReference + + const contractAddress = + buyAsset.assetId === solAssetId ? undefined : fromAssetId(buyAsset.assetId).assetReference + + const { instruction: createTokenAccountInstruction, destinationTokenAccount } = + contractAddress && isCrossAccountTrade + ? await adapter.createAssociatedTokenAccountInstruction({ + from: sendAddress, + to: receiveAddress!, + tokenId: contractAddress, + }) + : { instruction: undefined, destinationTokenAccount: undefined } + + const [buyAssetReferralPubKey] = PublicKey.findProgramAddressSync( + [ + Buffer.from('referral_ata'), + new PublicKey(SHAPESHIFT_JUPITER_REFERRAL_KEY).toBuffer(), + new PublicKey(buyAssetAddress).toBuffer(), + ], + new PublicKey(JUPITER_AFFILIATE_CONTRACT_ADDRESS), + ) + + const [sellAssetReferralPubKey] = PublicKey.findProgramAddressSync( + [ + Buffer.from('referral_ata'), + new PublicKey(SHAPESHIFT_JUPITER_REFERRAL_KEY).toBuffer(), + new PublicKey(sellAssetAddress).toBuffer(), + ], + new PublicKey(JUPITER_AFFILIATE_CONTRACT_ADDRESS), + ) + + const instructionData = new BorshInstructionCoder(referralIdl).encode( + 'initializeReferralTokenAccount', + {}, + ) + + const { instruction: feeAccountInstruction, tokenAccount } = + await getFeeTokenAccountAndInstruction({ + feePayerPubKey: new PublicKey(sendAddress), + buyAssetReferralPubKey, + sellAssetReferralPubKey, + programId: new PublicKey(JUPITER_AFFILIATE_CONTRACT_ADDRESS), + instructionData, + buyTokenId: buyAssetAddress, + sellTokenId: sellAssetAddress, + connection: adapter.getConnection(), + }) + + const maybeSwapResponse = await getJupiterSwapInstructions({ + apiUrl: jupiterUrl, + fromAddress: sendAddress, + toAddress: isCrossAccountTrade ? destinationTokenAccount?.toString() : undefined, + rawQuote: priceResponse, + useSharedAccounts: priceResponse.routePlan.length > 1 && isCrossAccountTrade ? true : false, + feeAccount: affiliateBps !== '0' ? tokenAccount?.toString() : undefined, + }) + + if (maybeSwapResponse.isErr()) { + const error = maybeSwapResponse.unwrapErr() + const cause = error.cause as AxiosError + throw Error(cause.response!.data.detail) + } + + const { data: swapResponse } = maybeSwapResponse.unwrap() + + const convertJupiterInstruction = (instruction: Instruction): TransactionInstruction => ({ + ...instruction, + keys: instruction.accounts.map(account => ({ + ...account, + pubkey: new PublicKey(account.pubkey), + })), + data: Buffer.from(instruction.data, 'base64'), + programId: new PublicKey(instruction.programId), + }) + + const instructions: TransactionInstruction[] = [ + ...swapResponse.setupInstructions.map(convertJupiterInstruction), + convertJupiterInstruction(swapResponse.swapInstruction), + ] + + if (feeAccountInstruction && affiliateBps !== '0') { + instructions.unshift(feeAccountInstruction) + } + + if (createTokenAccountInstruction) { + instructions.unshift(createTokenAccountInstruction) + } + + if (swapResponse.cleanupInstruction) { + instructions.push(convertJupiterInstruction(swapResponse.cleanupInstruction)) + } + + return { instructions, addressLookupTableAddresses: swapResponse.addressLookupTableAddresses } +} diff --git a/src/state/apis/swapper/helpers/validateTradeQuote.ts b/src/state/apis/swapper/helpers/validateTradeQuote.ts index f1260baad7d..482a8d145ca 100644 --- a/src/state/apis/swapper/helpers/validateTradeQuote.ts +++ b/src/state/apis/swapper/helpers/validateTradeQuote.ts @@ -216,6 +216,20 @@ export const validateTradeQuote = ( const accountId = portfolioAccountIdByNumberByChainId[sellAssetAccountNumber][protocolFee.asset.chainId] const balanceCryptoBaseUnit = portfolioAccountBalancesBaseUnit[accountId][assetId] + + // @TODO: seems like this condition should be applied for all the swappers, verify by smoke testing all of them + // them kick the swapperName bit out of the condition + if ( + firstHopSellFeeAsset?.assetId === assetId && + firstHop.sellAsset.assetId === assetId && + swapperName === SwapperName.Jupiter + ) { + return bnOrZero(balanceCryptoBaseUnit) + .minus(sellAmountCryptoBaseUnit) + .minus(protocolFee.amountCryptoBaseUnit) + .lt(0) + } + return bnOrZero(balanceCryptoBaseUnit).lt(protocolFee.amountCryptoBaseUnit) }) .map(([_assetId, protocolFee]: [AssetId, ProtocolFee]) => { diff --git a/yarn.lock b/yarn.lock index 368a7914784..8d5e7954552 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5424,6 +5424,40 @@ __metadata: languageName: node linkType: hard +"@coral-xyz/anchor@npm:0.29.0": + version: 0.29.0 + resolution: "@coral-xyz/anchor@npm:0.29.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 + checksum: 10c4e6c5557653419683f5ae22ec47ac266b64e5b422d466885cf2dc7efa8f836239bdf321495d3e2b3ce03e766667c0e2192cc573fbd66bc12cc652f5146e10 + languageName: node + linkType: hard + +"@coral-xyz/borsh@npm:^0.29.0": + version: 0.29.0 + resolution: "@coral-xyz/borsh@npm:0.29.0" + dependencies: + bn.js: ^5.1.2 + buffer-layout: ^1.2.0 + peerDependencies: + "@solana/web3.js": ^1.68.0 + checksum: 37006c75cd012672adf48e10234062624634da2a9335e34b7ff30969f58aff78cc3073b66a3edc806b52f038469f0c477a5a3ed35aaa075f3cbd44d7133ac218 + languageName: node + linkType: hard + "@cosmjs/amino@npm:0.25.0-alpha.2": version: 0.25.0-alpha.2 resolution: "@cosmjs/amino@npm:0.25.0-alpha.2" @@ -11665,6 +11699,7 @@ __metadata: version: 0.0.0-use.local resolution: "@shapeshiftoss/swapper@workspace:packages/swapper" dependencies: + "@coral-xyz/anchor": 0.29.0 "@shapeshiftoss/caip": "workspace:^" "@shapeshiftoss/chain-adapters": "workspace:^" "@shapeshiftoss/types": "workspace:^" @@ -12227,6 +12262,29 @@ __metadata: languageName: node linkType: hard +"@solana/web3.js@npm:^1.68.0": + version: 1.95.8 + resolution: "@solana/web3.js@npm:1.95.8" + dependencies: + "@babel/runtime": ^7.25.0 + "@noble/curves": ^1.4.2 + "@noble/hashes": ^1.4.0 + "@solana/buffer-layout": ^4.0.1 + agentkeepalive: ^4.5.0 + bigint-buffer: ^1.1.5 + bn.js: ^5.2.1 + borsh: ^0.7.0 + bs58: ^4.0.1 + buffer: 6.0.3 + fast-stable-stringify: ^1.0.0 + jayson: ^4.1.1 + node-fetch: ^2.7.0 + rpc-websockets: ^9.0.2 + superstruct: ^2.0.2 + checksum: 875a65c2e16ea797b2a1e842fe9a53ae74f627b8678d946a12f4a6acd1922dfcb107429b2b6d93131d406d30deffaa366132fe9b87dbf0b62c7b83e83184b3fa + languageName: node + linkType: hard + "@solana/web3.js@npm:^1.70.1": version: 1.73.0 resolution: "@solana/web3.js@npm:1.73.0" @@ -18734,7 +18792,7 @@ __metadata: languageName: node linkType: hard -"buffer-layout@npm:^1.2.0": +"buffer-layout@npm:^1.2.0, buffer-layout@npm:^1.2.2": version: 1.2.2 resolution: "buffer-layout@npm:1.2.2" checksum: e5809ba275530bf4e52fd09558b7c2111fbda5b405124f581acf364261d9c154e271800271898cd40473f9bcbb42c31584efb04219bde549d3460ca4bafeaa07 @@ -18998,7 +19056,7 @@ __metadata: languageName: node linkType: hard -"camelcase@npm:^6.2.0, camelcase@npm:^6.2.1": +"camelcase@npm:^6.2.0, camelcase@npm:^6.2.1, camelcase@npm:^6.3.0": version: 6.3.0 resolution: "camelcase@npm:6.3.0" checksum: 8c96818a9076434998511251dcb2761a94817ea17dbdc37f47ac080bd088fc62c7369429a19e2178b993497132c8cbcf5cc1f44ba963e76782ba469c0474938d @@ -20402,6 +20460,13 @@ __metadata: languageName: node linkType: hard +"crypto-hash@npm:^1.3.0": + version: 1.3.0 + resolution: "crypto-hash@npm:1.3.0" + checksum: a3a507e0d2b18fbd2da8088a1c62d0c53c009a99bbfa6d851cac069734ffa546922fa51bdd776d006459701cdda873463e5059ece3431aca048fd99e7573d138 + languageName: node + linkType: hard + "crypto-js@npm:4.2.0": version: 4.2.0 resolution: "crypto-js@npm:4.2.0" @@ -31188,6 +31253,13 @@ __metadata: languageName: node linkType: hard +"pako@npm:^2.0.3": + version: 2.1.0 + resolution: "pako@npm:2.1.0" + checksum: 71666548644c9a4d056bcaba849ca6fd7242c6cf1af0646d3346f3079a1c7f4a66ffec6f7369ee0dc88f61926c10d6ab05da3e1fca44b83551839e89edd75a3e + languageName: node + linkType: hard + "pako@npm:~1.0.5": version: 1.0.11 resolution: "pako@npm:1.0.11" @@ -35932,6 +36004,16 @@ pvutils@latest: languageName: node linkType: hard +"snake-case@npm:^3.0.4": + version: 3.0.4 + resolution: "snake-case@npm:3.0.4" + dependencies: + dot-case: ^3.0.4 + tslib: ^2.0.3 + checksum: 0a7a79900bbb36f8aaa922cf111702a3647ac6165736d5dc96d3ef367efc50465cac70c53cd172c382b022dac72ec91710608e5393de71f76d7142e6fd80e8a3 + languageName: node + linkType: hard + "snakecase-keys@npm:3.2.1": version: 3.2.1 resolution: "snakecase-keys@npm:3.2.1" @@ -36863,7 +36945,7 @@ pvutils@latest: languageName: node linkType: hard -"superstruct@npm:^0.15.3": +"superstruct@npm:^0.15.3, superstruct@npm:^0.15.4": version: 0.15.5 resolution: "superstruct@npm:0.15.5" checksum: 6d1f5249fee789424b7178fa0a1ffb2ace629c5480c39505885bd8c0046a4ff8b267569a3442fa53b8c560a7ba6599cf3f8af94225aebeb2cf6023f7dd911050 @@ -37533,6 +37615,13 @@ pvutils@latest: languageName: node linkType: hard +"toml@npm:^3.0.0": + version: 3.0.0 + resolution: "toml@npm:3.0.0" + checksum: 5d7f1d8413ad7780e9bdecce8ea4c3f5130dd53b0a4f2e90b93340979a137739879d7b9ce2ce05c938b8cc828897fe9e95085197342a1377dd8850bf5125f15f + languageName: node + linkType: hard + "totalist@npm:^3.0.0": version: 3.0.1 resolution: "totalist@npm:3.0.1"