UNPKG

@raydium-io/raydium-sdk-v2

Version:

An SDK for building applications on top of Raydium.

1 lines 885 kB
{"version":3,"sources":["../../../src/raydium/tradeV2/trade.ts","../../../src/common/logger.ts","../../../src/common/utility.ts","../../../src/module/amount.ts","../../../src/common/bignumber.ts","../../../node_modules/decimal.js/decimal.mjs","../../../src/module/token.ts","../../../src/common/pubKey.ts","../../../src/raydium/token/constant.ts","../../../src/module/fraction.ts","../../../src/module/formatter.ts","../../../src/module/price.ts","../../../src/module/currency.ts","../../../src/module/percent.ts","../../../src/common/txTool/txTool.ts","../../../src/common/txTool/txType.ts","../../../src/common/txTool/txUtils.ts","../../../src/common/txTool/lookupTable.ts","../../../src/common/accountInfo.ts","../../../src/common/lodash.ts","../../../src/common/programId.ts","../../../src/common/pda.ts","../../../src/common/transfer.ts","../../../src/raydium/moduleBase.ts","../../../src/raydium/account/instruction.ts","../../../src/raydium/account/util.ts","../../../src/marshmallow/index.ts","../../../src/marshmallow/buffer-layout.ts","../../../src/raydium/account/layout.ts","../../../node_modules/@noble/hashes/src/_assert.ts","../../../node_modules/@noble/hashes/src/utils.ts","../../../node_modules/@noble/hashes/src/_md.ts","../../../node_modules/@noble/hashes/src/sha256.ts","../../../src/raydium/liquidity/constant.ts","../../../src/raydium/liquidity/layout.ts","../../../src/raydium/liquidity/utils.ts","../../../src/raydium/token/utils.ts","../../../src/raydium/liquidity/serum.ts","../../../src/raydium/liquidity/stable.ts","../../../src/raydium/liquidity/instruction.ts","../../../src/raydium/clmm/utils/tick.ts","../../../src/raydium/clmm/utils/util.ts","../../../src/raydium/clmm/utils/pda.ts","../../../src/raydium/clmm/utils/constants.ts","../../../src/raydium/clmm/utils/tickQuery.ts","../../../src/raydium/clmm/utils/math.ts","../../../src/raydium/clmm/utils/pool.ts","../../../src/raydium/clmm/utils/tickarrayBitmap.ts","../../../src/raydium/clmm/utils/position.ts","../../../src/raydium/clmm/layout.ts","../../../src/raydium/cpmm/layout.ts","../../../src/raydium/cpmm/instruction.ts","../../../src/raydium/cpmm/pda.ts","../../../src/raydium/cpmm/curve/calculator.ts","../../../src/raydium/cpmm/curve/fee.ts","../../../src/raydium/cpmm/curve/constantProduct.ts","../../../src/raydium/clmm/clmm.ts","../../../src/raydium/clmm/instrument.ts","../../../src/raydium/token/layout.ts","../../../src/raydium/tradeV2/instrument.ts","../../../src/raydium/serum/id.ts","../../../src/raydium/serum/layout.ts","../../../src/raydium/serum/serum.ts"],"sourcesContent":["import { PublicKey, EpochInfo } from \"@solana/web3.js\";\nimport { TOKEN_PROGRAM_ID, TOKEN_2022_PROGRAM_ID, createTransferInstruction } from \"@solana/spl-token\";\nimport {\n WSOLMint,\n AMM_V4,\n CLMM_PROGRAM_ID,\n CREATE_CPMM_POOL_PROGRAM,\n minExpirationTime,\n getMultipleAccountsInfoWithCustomFlags,\n solToWSol,\n fetchMultipleMintInfos,\n} from \"@/common\";\nimport { InstructionType, TxVersion } from \"@/common/txTool/txType\";\nimport { MakeTxData, MakeMultiTxData } from \"@/common/txTool/txTool\";\nimport ModuleBase, { ModuleBaseProps } from \"../moduleBase\";\nimport { BigNumberish, parseBigNumberish } from \"@/common/bignumber\";\nimport {\n createWSolAccountInstructions,\n closeAccountInstruction,\n makeTransferInstruction,\n} from \"../account/instruction\";\nimport { TokenAccount } from \"../account/types\";\nimport { ComputeBudgetConfig, ReturnTypeFetchMultipleMintInfos } from \"@/raydium/type\";\nimport {\n getLiquidityAssociatedAuthority,\n ComputeAmountOutParam,\n liquidityStateV4Layout,\n toAmmComputePoolInfo,\n} from \"@/raydium/liquidity\";\nimport { PoolInfoLayout } from \"@/raydium/clmm/layout\";\nimport { CpmmPoolInfoLayout, getPdaPoolAuthority } from \"@/raydium/cpmm\";\nimport { ReturnTypeFetchMultiplePoolTickArrays, PoolUtils, ClmmRpcData, ComputeClmmPoolInfo } from \"@/raydium/clmm\";\nimport { struct, publicKey } from \"@/marshmallow\";\nimport {\n ReturnTypeGetAllRoute,\n BasicPoolInfo,\n RoutePathType,\n ReturnTypeFetchMultipleInfo,\n ComputeAmountOutLayout,\n ComputeAmountOutAmmLayout,\n ComputePoolType,\n ComputeRoutePathType,\n} from \"./type\";\nimport { TokenAmount, Price } from \"@/module\";\nimport BN from \"bn.js\";\nimport { AmmV4Keys, ApiV3Token, ClmmKeys, PoolKeys } from \"@/api\";\nimport { toApiV3Token, toToken, toTokenAmount } from \"../token\";\nimport Decimal from \"decimal.js\";\nimport { makeSwapInstruction } from \"./instrument\";\nimport { AmmRpcData } from \"../liquidity\";\nimport { MARKET_STATE_LAYOUT_V3, Market } from \"../serum\";\nimport { CpmmComputeData } from \"../cpmm\";\n\nconst ZERO = new BN(0);\nexport default class TradeV2 extends ModuleBase {\n constructor(params: ModuleBaseProps) {\n super(params);\n }\n\n private async getWSolAccounts(): Promise<TokenAccount[]> {\n this.scope.checkOwner();\n await this.scope.account.fetchWalletTokenAccounts();\n const tokenAccounts = this.scope.account.tokenAccounts.filter((acc) => acc.mint.equals(WSOLMint));\n tokenAccounts.sort((a, b) => {\n if (a.isAssociated) return 1;\n if (b.isAssociated) return -1;\n return a.amount.lt(b.amount) ? -1 : 1;\n });\n return tokenAccounts;\n }\n\n public async unWrapWSol<T extends TxVersion>(props: {\n amount: BigNumberish;\n computeBudgetConfig?: ComputeBudgetConfig;\n tokenProgram?: PublicKey;\n txVersion?: T;\n }): Promise<MakeTxData<T>> {\n const { amount, tokenProgram, txVersion = TxVersion.LEGACY } = props;\n const tokenAccounts = await this.getWSolAccounts();\n const txBuilder = this.createTxBuilder();\n txBuilder.addCustomComputeBudget(props.computeBudgetConfig);\n const ins = await createWSolAccountInstructions({\n connection: this.scope.connection,\n owner: this.scope.ownerPubKey,\n payer: this.scope.ownerPubKey,\n amount: 0,\n });\n txBuilder.addInstruction(ins);\n\n const amountBN = parseBigNumberish(amount);\n for (let i = 0; i < tokenAccounts.length; i++) {\n if (amountBN.gte(tokenAccounts[i].amount)) {\n txBuilder.addInstruction({\n instructions: [\n closeAccountInstruction({\n tokenAccount: tokenAccounts[i].publicKey!,\n payer: this.scope.ownerPubKey,\n owner: this.scope.ownerPubKey,\n programId: tokenProgram,\n }),\n ],\n });\n amountBN.sub(tokenAccounts[i].amount);\n } else {\n txBuilder.addInstruction({\n instructions: [\n closeAccountInstruction({\n tokenAccount: tokenAccounts[i].publicKey!,\n payer: this.scope.ownerPubKey,\n owner: this.scope.ownerPubKey,\n programId: tokenProgram,\n }),\n ],\n });\n makeTransferInstruction({\n destination: ins.addresses.newAccount,\n source: tokenAccounts[i].publicKey!,\n amount: amountBN,\n owner: this.scope.ownerPubKey,\n tokenProgram,\n });\n }\n }\n\n return txBuilder.versionBuild({ txVersion }) as Promise<MakeTxData<T>>;\n }\n\n public async wrapWSol<T extends TxVersion>(\n amount: BigNumberish,\n tokenProgram?: PublicKey,\n txVersion?: T,\n ): Promise<MakeTxData<T>> {\n const tokenAccounts = await this.getWSolAccounts();\n\n const txBuilder = this.createTxBuilder();\n const ins = await createWSolAccountInstructions({\n connection: this.scope.connection,\n owner: this.scope.ownerPubKey,\n payer: this.scope.ownerPubKey,\n amount,\n skipCloseAccount: true,\n });\n txBuilder.addInstruction(ins);\n\n if (tokenAccounts.length) {\n // already have wsol account\n txBuilder.addInstruction({\n instructions: [\n makeTransferInstruction({\n // destination: ins.signers![0].publicKey,\n destination: tokenAccounts[0].publicKey!,\n source: ins.addresses.newAccount,\n amount,\n owner: this.scope.ownerPubKey,\n tokenProgram,\n }),\n ],\n endInstructions: [\n closeAccountInstruction({\n tokenAccount: ins.addresses.newAccount,\n payer: this.scope.ownerPubKey,\n owner: this.scope.ownerPubKey,\n programId: tokenProgram,\n }),\n ],\n });\n }\n return txBuilder.versionBuild({ txVersion: txVersion ?? TxVersion.LEGACY }) as Promise<MakeTxData<T>>;\n }\n\n public async swap<T extends TxVersion>({\n swapInfo,\n swapPoolKeys,\n ownerInfo,\n computeBudgetConfig,\n routeProgram,\n txVersion,\n }: {\n txVersion: T;\n swapInfo: ComputeAmountOutLayout;\n swapPoolKeys?: PoolKeys[];\n ownerInfo: {\n associatedOnly: boolean;\n checkCreateATAOwner: boolean;\n };\n routeProgram: PublicKey;\n computeBudgetConfig?: ComputeBudgetConfig;\n }): Promise<MakeMultiTxData<T>> {\n const txBuilder = this.createTxBuilder();\n\n const amountIn = swapInfo.amountIn;\n const amountOut = swapInfo.amountOut;\n const useSolBalance = amountIn.amount.token.mint.equals(WSOLMint);\n const isOutputSol = amountOut.amount.token.mint.equals(WSOLMint);\n const inputMint = amountIn.amount.token.mint;\n const outputMint = amountOut.amount.token.mint;\n\n const { account: sourceAcc, instructionParams: sourceAccInsParams } =\n await this.scope.account.getOrCreateTokenAccount({\n tokenProgram: amountIn.amount.token.isToken2022 ? TOKEN_2022_PROGRAM_ID : TOKEN_PROGRAM_ID,\n mint: inputMint,\n notUseTokenAccount: useSolBalance,\n owner: this.scope.ownerPubKey,\n skipCloseAccount: !useSolBalance,\n createInfo: useSolBalance\n ? {\n payer: this.scope.ownerPubKey,\n amount: amountIn.amount.raw,\n }\n : undefined,\n associatedOnly: useSolBalance ? false : ownerInfo.associatedOnly,\n checkCreateATAOwner: ownerInfo.checkCreateATAOwner,\n });\n\n sourceAccInsParams && txBuilder.addInstruction(sourceAccInsParams);\n\n if (sourceAcc === undefined) {\n throw Error(\"input account check error\");\n }\n\n let destinationAcc: PublicKey;\n if (swapInfo.routeType === \"route\") {\n destinationAcc = this.scope.account.getAssociatedTokenAccount(\n outputMint,\n amountOut.amount.token.isToken2022 ? TOKEN_2022_PROGRAM_ID : TOKEN_PROGRAM_ID,\n );\n } else {\n const { account, instructionParams } = await this.scope.account.getOrCreateTokenAccount({\n tokenProgram: amountOut.amount.token.isToken2022 ? TOKEN_2022_PROGRAM_ID : TOKEN_PROGRAM_ID,\n mint: outputMint,\n notUseTokenAccount: isOutputSol,\n owner: this.scope.ownerPubKey,\n skipCloseAccount: true,\n createInfo: {\n payer: this.scope.ownerPubKey,\n amount: 0,\n },\n associatedOnly: isOutputSol ? false : ownerInfo.associatedOnly,\n checkCreateATAOwner: ownerInfo.checkCreateATAOwner,\n });\n destinationAcc = account!;\n instructionParams && txBuilder.addInstruction(instructionParams);\n }\n\n if (isOutputSol) {\n txBuilder.addInstruction({\n endInstructions: [\n closeAccountInstruction({\n owner: this.scope.ownerPubKey,\n payer: this.scope.ownerPubKey,\n tokenAccount: destinationAcc,\n programId: TOKEN_PROGRAM_ID,\n }),\n ],\n endInstructionTypes: [InstructionType.CloseAccount],\n });\n }\n\n let routeTokenAcc: PublicKey | undefined = undefined;\n if (swapInfo.routeType === \"route\") {\n const middleMint = swapInfo.middleToken;\n routeTokenAcc = this.scope.account.getAssociatedTokenAccount(\n middleMint.mint,\n middleMint.isToken2022 ? TOKEN_2022_PROGRAM_ID : TOKEN_PROGRAM_ID,\n );\n }\n\n const poolKeys = swapPoolKeys ? swapPoolKeys : await this.computePoolToPoolKeys({ pools: swapInfo.poolInfoList });\n const swapIns = makeSwapInstruction({\n routeProgram,\n inputMint,\n swapInfo: {\n ...swapInfo,\n poolInfo: [...swapInfo.poolInfoList],\n poolKey: poolKeys,\n outputMint,\n },\n ownerInfo: {\n wallet: this.scope.ownerPubKey,\n sourceToken: sourceAcc,\n routeToken: routeTokenAcc,\n destinationToken: destinationAcc!,\n },\n });\n\n if (swapInfo.feeConfig !== undefined) {\n const checkTxBuilder = this.createTxBuilder();\n checkTxBuilder.addInstruction({\n instructions: [\n createTransferInstruction(\n sourceAcc,\n swapInfo.feeConfig.feeAccount,\n this.scope.ownerPubKey,\n swapInfo.feeConfig.feeAmount.toNumber(),\n ),\n ],\n instructionTypes: [InstructionType.TransferAmount],\n });\n checkTxBuilder.addInstruction(swapIns);\n\n const { transactions } =\n txVersion === TxVersion.V0 ? await checkTxBuilder.sizeCheckBuildV0() : await checkTxBuilder.sizeCheckBuild();\n if (transactions.length < 2) {\n txBuilder.addInstruction({\n instructions: [\n createTransferInstruction(\n sourceAcc,\n swapInfo.feeConfig.feeAccount,\n this.scope.ownerPubKey,\n swapInfo.feeConfig.feeAmount.toNumber(),\n ),\n ],\n instructionTypes: [InstructionType.TransferAmount],\n });\n }\n }\n txBuilder.addInstruction(swapIns);\n\n if (txVersion === TxVersion.V0)\n return txBuilder.sizeCheckBuildV0({ computeBudgetConfig, address: swapIns.address }) as Promise<\n MakeMultiTxData<T>\n >;\n return txBuilder.sizeCheckBuild({ computeBudgetConfig, address: swapIns.address }) as Promise<MakeMultiTxData<T>>;\n }\n\n // get all amm/clmm/cpmm pools data only with id and mint\n public async fetchRoutePoolBasicInfo(programIds?: { amm: PublicKey; clmm: PublicKey; cpmm: PublicKey }): Promise<{\n ammPools: BasicPoolInfo[];\n clmmPools: BasicPoolInfo[];\n cpmmPools: BasicPoolInfo[];\n }> {\n const { amm = AMM_V4, clmm = CLMM_PROGRAM_ID, cpmm = CREATE_CPMM_POOL_PROGRAM } = programIds || {};\n const ammPoolsData = await this.scope.connection.getProgramAccounts(amm, {\n dataSlice: { offset: liquidityStateV4Layout.offsetOf(\"baseMint\"), length: 64 },\n });\n\n const layoutAmm = struct([publicKey(\"baseMint\"), publicKey(\"quoteMint\")]);\n const ammData = ammPoolsData.map((data) => ({\n id: data.pubkey,\n version: 4,\n mintA: layoutAmm.decode(data.account.data).baseMint,\n mintB: layoutAmm.decode(data.account.data).quoteMint,\n }));\n\n const layout = struct([publicKey(\"mintA\"), publicKey(\"mintB\")]);\n const clmmPoolsData = await this.scope.connection.getProgramAccounts(clmm, {\n filters: [{ dataSize: PoolInfoLayout.span }],\n dataSlice: { offset: PoolInfoLayout.offsetOf(\"mintA\"), length: 64 },\n });\n\n const clmmData = clmmPoolsData.map((data) => {\n const clmm = layout.decode(data.account.data);\n return {\n id: data.pubkey,\n version: 6,\n mintA: clmm.mintA,\n mintB: clmm.mintB,\n };\n });\n\n const cpmmPools = await this.scope.connection.getProgramAccounts(cpmm, {\n dataSlice: { offset: CpmmPoolInfoLayout.offsetOf(\"mintA\"), length: 64 },\n });\n\n const cpmmData = cpmmPools.map((data) => {\n const clmm = layout.decode(data.account.data);\n return {\n id: data.pubkey,\n version: 7,\n mintA: clmm.mintA,\n mintB: clmm.mintB,\n };\n });\n\n return {\n clmmPools: clmmData,\n ammPools: ammData,\n cpmmPools: cpmmData,\n };\n }\n\n // get pools with in routes\n public getAllRoute({\n inputMint,\n outputMint,\n clmmPools,\n ammPools,\n cpmmPools,\n }: {\n inputMint: PublicKey;\n outputMint: PublicKey;\n clmmPools: BasicPoolInfo[];\n ammPools: BasicPoolInfo[];\n cpmmPools: BasicPoolInfo[];\n }): ReturnTypeGetAllRoute {\n inputMint = inputMint.toString() === PublicKey.default.toString() ? WSOLMint : inputMint;\n outputMint = outputMint.toString() === PublicKey.default.toString() ? WSOLMint : outputMint;\n\n const needSimulate: { [poolKey: string]: BasicPoolInfo } = {};\n const needTickArray: { [poolKey: string]: BasicPoolInfo } = {};\n const cpmmPoolList: { [poolKey: string]: BasicPoolInfo } = {};\n\n const directPath: BasicPoolInfo[] = [];\n\n const routePathDict: RoutePathType = {}; // {[route mint: string]: {in: [] , out: []}}\n\n for (const itemClmmPool of clmmPools ?? []) {\n if (\n (itemClmmPool.mintA.equals(inputMint) && itemClmmPool.mintB.equals(outputMint)) ||\n (itemClmmPool.mintA.equals(outputMint) && itemClmmPool.mintB.equals(inputMint))\n ) {\n directPath.push(itemClmmPool);\n needTickArray[itemClmmPool.id.toString()] = itemClmmPool;\n }\n\n if (itemClmmPool.mintA.equals(inputMint)) {\n const t = itemClmmPool.mintB.toString();\n if (routePathDict[t] === undefined)\n routePathDict[t] = {\n mintProgram: TOKEN_PROGRAM_ID, // to fetch later\n in: [],\n out: [],\n mDecimals: 0, // to fetch later\n };\n routePathDict[t].in.push(itemClmmPool);\n }\n if (itemClmmPool.mintB.equals(inputMint)) {\n const t = itemClmmPool.mintA.toString();\n if (routePathDict[t] === undefined)\n routePathDict[t] = {\n mintProgram: TOKEN_PROGRAM_ID, // to fetch later\n in: [],\n out: [],\n mDecimals: 0, // to fetch later\n };\n routePathDict[t].in.push(itemClmmPool);\n }\n if (itemClmmPool.mintA.equals(outputMint)) {\n const t = itemClmmPool.mintB.toString();\n if (routePathDict[t] === undefined)\n routePathDict[t] = {\n mintProgram: TOKEN_PROGRAM_ID, // to fetch later\n in: [],\n out: [],\n mDecimals: 0, // to fetch later\n };\n routePathDict[t].out.push(itemClmmPool);\n }\n if (itemClmmPool.mintB.equals(outputMint)) {\n const t = itemClmmPool.mintA.toString();\n if (routePathDict[t] === undefined)\n routePathDict[t] = {\n mintProgram: TOKEN_PROGRAM_ID, // to fetch later\n in: [],\n out: [],\n mDecimals: 0, // to fetch later\n };\n routePathDict[t].out.push(itemClmmPool);\n }\n }\n\n const addLiquidityPools: BasicPoolInfo[] = [];\n\n for (const itemAmmPool of ammPools) {\n if (\n (itemAmmPool.mintA.equals(inputMint) && itemAmmPool.mintB.equals(outputMint)) ||\n (itemAmmPool.mintA.equals(outputMint) && itemAmmPool.mintB.equals(inputMint))\n ) {\n directPath.push(itemAmmPool);\n needSimulate[itemAmmPool.id.toBase58()] = itemAmmPool;\n addLiquidityPools.push(itemAmmPool);\n }\n if (itemAmmPool.mintA.equals(inputMint)) {\n if (routePathDict[itemAmmPool.mintB.toBase58()] === undefined)\n routePathDict[itemAmmPool.mintB.toBase58()] = {\n mintProgram: TOKEN_PROGRAM_ID,\n in: [],\n out: [],\n mDecimals: 0, // to fetch later\n };\n routePathDict[itemAmmPool.mintB.toBase58()].in.push(itemAmmPool);\n }\n if (itemAmmPool.mintB.equals(inputMint)) {\n if (routePathDict[itemAmmPool.mintA.toBase58()] === undefined)\n routePathDict[itemAmmPool.mintA.toBase58()] = {\n mintProgram: TOKEN_PROGRAM_ID,\n in: [],\n out: [],\n mDecimals: 0, // to fetch later\n };\n routePathDict[itemAmmPool.mintA.toBase58()].in.push(itemAmmPool);\n }\n if (itemAmmPool.mintA.equals(outputMint)) {\n if (routePathDict[itemAmmPool.mintB.toBase58()] === undefined)\n routePathDict[itemAmmPool.mintB.toBase58()] = {\n mintProgram: TOKEN_PROGRAM_ID,\n in: [],\n out: [],\n mDecimals: 0, // to fetch later\n };\n routePathDict[itemAmmPool.mintB.toBase58()].out.push(itemAmmPool);\n }\n if (itemAmmPool.mintB.equals(outputMint)) {\n if (routePathDict[itemAmmPool.mintA.toBase58()] === undefined)\n routePathDict[itemAmmPool.mintA.toBase58()] = {\n mintProgram: TOKEN_PROGRAM_ID,\n in: [],\n out: [],\n mDecimals: 0, // to fetch later\n };\n routePathDict[itemAmmPool.mintA.toBase58()].out.push(itemAmmPool);\n }\n }\n\n for (const itemCpmmPool of cpmmPools) {\n if (\n (itemCpmmPool.mintA.equals(inputMint) && itemCpmmPool.mintB.equals(outputMint)) ||\n (itemCpmmPool.mintA.equals(outputMint) && itemCpmmPool.mintB.equals(inputMint))\n ) {\n directPath.push(itemCpmmPool);\n cpmmPoolList[itemCpmmPool.id.toBase58()] = itemCpmmPool;\n }\n if (itemCpmmPool.mintA.equals(inputMint)) {\n if (routePathDict[itemCpmmPool.mintB.toBase58()] === undefined)\n routePathDict[itemCpmmPool.mintB.toBase58()] = {\n mintProgram: TOKEN_PROGRAM_ID,\n in: [],\n out: [],\n mDecimals: 0, // to fetch later\n };\n routePathDict[itemCpmmPool.mintB.toBase58()].in.push(itemCpmmPool);\n }\n if (itemCpmmPool.mintB.equals(inputMint)) {\n if (routePathDict[itemCpmmPool.mintA.toBase58()] === undefined)\n routePathDict[itemCpmmPool.mintA.toBase58()] = {\n mintProgram: TOKEN_PROGRAM_ID,\n in: [],\n out: [],\n mDecimals: 0, // to fetch later\n };\n routePathDict[itemCpmmPool.mintA.toBase58()].in.push(itemCpmmPool);\n }\n if (itemCpmmPool.mintA.equals(outputMint)) {\n if (routePathDict[itemCpmmPool.mintB.toBase58()] === undefined)\n routePathDict[itemCpmmPool.mintB.toBase58()] = {\n mintProgram: TOKEN_PROGRAM_ID,\n in: [],\n out: [],\n mDecimals: 0, // to fetch later\n };\n routePathDict[itemCpmmPool.mintB.toBase58()].out.push(itemCpmmPool);\n }\n if (itemCpmmPool.mintB.equals(outputMint)) {\n if (routePathDict[itemCpmmPool.mintA.toBase58()] === undefined)\n routePathDict[itemCpmmPool.mintA.toBase58()] = {\n mintProgram: TOKEN_PROGRAM_ID,\n in: [],\n out: [],\n mDecimals: 0, // to fetch later\n };\n routePathDict[itemCpmmPool.mintA.toBase58()].out.push(itemCpmmPool);\n }\n }\n\n for (const t of Object.keys(routePathDict)) {\n if (\n routePathDict[t].in.length === 1 &&\n routePathDict[t].out.length === 1 &&\n routePathDict[t].in[0].id.equals(routePathDict[t].out[0].id)\n ) {\n delete routePathDict[t];\n continue;\n }\n if (routePathDict[t].in.length === 0 || routePathDict[t].out.length === 0) {\n delete routePathDict[t];\n continue;\n }\n\n const info = routePathDict[t];\n\n for (const infoIn of info.in) {\n for (const infoOut of info.out) {\n if (infoIn.version === 6 && needTickArray[infoIn.id.toString()] === undefined) {\n needTickArray[infoIn.id.toString()] = infoIn;\n } else if (infoIn.version === 7 && cpmmPoolList[infoIn.id.toString()] === undefined) {\n cpmmPoolList[infoIn.id.toString()] = infoIn;\n } else if (\n (infoIn.version === 4 || infoIn.version === 5) &&\n needSimulate[infoIn.id.toString()] === undefined\n ) {\n needSimulate[infoIn.id.toString()] = infoIn;\n }\n if (infoOut.version === 6 && needTickArray[infoOut.id.toString()] === undefined) {\n needTickArray[infoOut.id.toString()] = infoOut;\n } else if (infoOut.version === 7 && cpmmPoolList[infoOut.id.toString()] === undefined) {\n cpmmPoolList[infoOut.id.toString()] = infoOut;\n } else if (\n (infoOut.version === 4 || infoOut.version === 5) &&\n needSimulate[infoOut.id.toString()] === undefined\n ) {\n needSimulate[infoOut.id.toString()] = infoOut;\n }\n }\n }\n }\n\n return {\n directPath,\n addLiquidityPools,\n routePathDict,\n needSimulate: Object.values(needSimulate),\n needTickArray: Object.values(needTickArray),\n cpmmPoolList: Object.values(cpmmPoolList),\n };\n }\n\n // fetch pools detail info in route\n public async fetchSwapRoutesData({\n routes,\n inputMint,\n outputMint,\n }: {\n inputMint: string | PublicKey;\n outputMint: string | PublicKey;\n routes: ReturnTypeGetAllRoute;\n }): Promise<{\n mintInfos: ReturnTypeFetchMultipleMintInfos;\n ammPoolsRpcInfo: Record<string, AmmRpcData>;\n ammSimulateCache: Record<string, ComputeAmountOutParam[\"poolInfo\"]>;\n clmmPoolsRpcInfo: Record<string, ClmmRpcData>;\n computeClmmPoolInfo: Record<string, ComputeClmmPoolInfo>;\n computePoolTickData: ReturnTypeFetchMultiplePoolTickArrays;\n computeCpmmData: Record<string, CpmmComputeData>;\n routePathDict: ComputeRoutePathType;\n }> {\n const mintSet = new Set([\n ...routes.needTickArray.map((p) => [p.mintA.toBase58(), p.mintB.toBase58()]).flat(),\n inputMint.toString(),\n outputMint.toString(),\n ]);\n\n console.log(\"fetching amm pools info, total: \", routes.needSimulate.length);\n const ammPoolsRpcInfo = await this.scope.liquidity.getRpcPoolInfos(routes.needSimulate.map((p) => p.id));\n const ammSimulateCache = toAmmComputePoolInfo(ammPoolsRpcInfo);\n\n let mintInfos: ReturnTypeFetchMultipleMintInfos = {};\n // amm doesn't support token2022 yet, so don't need to fetch mint info\n Object.values(ammSimulateCache).forEach((p) => {\n mintSet.delete(p.mintA.address);\n mintInfos[p.mintA.address] = {\n address: new PublicKey(p.mintA.address),\n programId: TOKEN_PROGRAM_ID,\n mintAuthority: null,\n supply: BigInt(0),\n decimals: p.mintA.decimals,\n isInitialized: true,\n freezeAuthority: null,\n tlvData: Buffer.from(\"0\", \"hex\"),\n feeConfig: undefined,\n };\n\n mintSet.delete(p.mintB.address);\n mintInfos[p.mintB.address] = {\n address: new PublicKey(p.mintB.address),\n programId: TOKEN_PROGRAM_ID,\n mintAuthority: null,\n supply: BigInt(0),\n decimals: p.mintB.decimals,\n isInitialized: true,\n freezeAuthority: null,\n tlvData: Buffer.from(\"0\", \"hex\"),\n feeConfig: undefined,\n };\n });\n\n console.log(\"fetching cpmm pools info, total: \", routes.cpmmPoolList.length);\n const cpmmPoolsRpcInfo = await this.scope.cpmm.getRpcPoolInfos(\n routes.cpmmPoolList.map((p) => p.id.toBase58()),\n true,\n );\n\n Object.values(cpmmPoolsRpcInfo).forEach((p) => {\n const [mintA, mintB] = [p.mintA.toBase58(), p.mintB.toBase58()];\n if (p.mintProgramA.equals(TOKEN_PROGRAM_ID)) {\n mintSet.delete(mintA);\n mintInfos[mintA] = {\n address: p.mintA,\n programId: p.mintProgramA,\n mintAuthority: null,\n supply: BigInt(0),\n decimals: p.mintDecimalA,\n isInitialized: true,\n freezeAuthority: null,\n tlvData: Buffer.from(\"0\", \"hex\"),\n feeConfig: undefined,\n };\n } else mintSet.add(mintA); // 2022, need to fetch fee config\n if (p.mintProgramB.equals(TOKEN_PROGRAM_ID)) {\n mintSet.delete(mintB);\n mintInfos[mintB] = {\n address: p.mintB,\n programId: p.mintProgramB,\n mintAuthority: null,\n supply: BigInt(0),\n decimals: p.mintDecimalB,\n isInitialized: true,\n freezeAuthority: null,\n tlvData: Buffer.from(\"0\", \"hex\"),\n feeConfig: undefined,\n };\n } else mintSet.add(mintB); // 2022, need to fetch fee config\n });\n\n console.log(\"fetching mints info, total: \", mintSet.size);\n const fetchMintInfoRes = await fetchMultipleMintInfos({\n connection: this.scope.connection,\n mints: Array.from(mintSet).map((m) => new PublicKey(m)),\n });\n\n mintInfos = {\n ...mintInfos,\n ...fetchMintInfoRes,\n };\n\n const computeCpmmData = this.scope.cpmm.toComputePoolInfos({\n pools: cpmmPoolsRpcInfo,\n mintInfos,\n });\n\n console.log(\"fetching clmm pools info, total:\", routes.needTickArray.length);\n const clmmPoolsRpcInfo = await this.scope.clmm.getRpcClmmPoolInfos({\n poolIds: routes.needTickArray.map((p) => p.id),\n });\n const { computeClmmPoolInfo, computePoolTickData } = await this.scope.clmm.getComputeClmmPoolInfos({\n clmmPoolsRpcInfo,\n mintInfos,\n });\n\n // update route pool mint info\n const routePathDict = Object.keys(routes.routePathDict).reduce((acc, cur) => {\n return {\n ...acc,\n [cur]: {\n ...routes.routePathDict[cur],\n mintProgram: mintInfos[cur].programId,\n mDecimals: mintInfos[cur].decimals,\n in: routes.routePathDict[cur].in.map(\n (p) =>\n ammSimulateCache[p.id.toBase58()] ||\n computeClmmPoolInfo[p.id.toBase58()] ||\n computeCpmmData[p.id.toBase58()],\n ),\n out: routes.routePathDict[cur].out.map(\n (p) =>\n ammSimulateCache[p.id.toBase58()] ||\n computeClmmPoolInfo[p.id.toBase58()] ||\n computeCpmmData[p.id.toBase58()],\n ),\n },\n };\n }, {} as ComputeRoutePathType);\n\n return {\n mintInfos,\n\n ammPoolsRpcInfo,\n ammSimulateCache,\n\n clmmPoolsRpcInfo,\n computeClmmPoolInfo,\n computePoolTickData,\n\n computeCpmmData,\n\n routePathDict,\n };\n }\n\n // compute amount from routes\n public getAllRouteComputeAmountOut({\n inputTokenAmount,\n outputToken: propOutputToken,\n directPath,\n routePathDict,\n simulateCache,\n tickCache,\n slippage,\n chainTime,\n epochInfo,\n feeConfig,\n }: {\n directPath: ComputePoolType[];\n routePathDict: ComputeRoutePathType;\n simulateCache: ReturnTypeFetchMultipleInfo;\n tickCache: ReturnTypeFetchMultiplePoolTickArrays;\n\n mintInfos: ReturnTypeFetchMultipleMintInfos;\n\n inputTokenAmount: TokenAmount;\n outputToken: ApiV3Token;\n slippage: number;\n chainTime: number;\n epochInfo: EpochInfo;\n\n feeConfig?: {\n feeBps: BN;\n feeAccount: PublicKey;\n };\n }): ComputeAmountOutLayout[] {\n const _amountInFee =\n feeConfig === undefined\n ? new BN(0)\n : inputTokenAmount.raw.mul(new BN(feeConfig.feeBps.toNumber())).div(new BN(10000));\n const _amoutIn = inputTokenAmount.raw.sub(_amountInFee);\n const amountIn = new TokenAmount(inputTokenAmount.token, _amoutIn);\n const _inFeeConfig =\n feeConfig === undefined\n ? undefined\n : {\n feeAmount: _amountInFee,\n feeAccount: feeConfig.feeAccount,\n };\n const outputToken = {\n ...propOutputToken,\n address: solToWSol(propOutputToken.address).toString(),\n };\n const outRoute: ComputeAmountOutLayout[] = [];\n for (const itemPool of directPath) {\n try {\n outRoute.push({\n ...this.computeAmountOut({\n itemPool,\n tickCache,\n simulateCache,\n chainTime,\n epochInfo,\n slippage,\n outputToken,\n amountIn,\n }),\n feeConfig: _inFeeConfig,\n });\n } catch (e: any) {\n this.logDebug(\"direct error\", itemPool.version, itemPool.id.toString(), e.message);\n /* empty */\n }\n }\n this.logDebug(\"direct done\");\n for (const [routeMint, info] of Object.entries(routePathDict)) {\n // const routeToken = new Token(info.mintProgram, routeMint, info.mDecimals);\n const routeToken = {\n chainId: 101,\n address: routeMint,\n programId: info.mintProgram.toBase58(),\n logoURI: \"\",\n symbol: \"\",\n name: \"\",\n decimals: info.mDecimals,\n tags: [],\n extensions: {},\n };\n const maxFirstIn = info.in\n .map((i) => {\n try {\n return {\n pool: i,\n data: this.computeAmountOut({\n itemPool: i,\n tickCache,\n simulateCache,\n chainTime,\n epochInfo,\n slippage,\n outputToken: routeToken,\n amountIn,\n }),\n };\n } catch (e: any) {\n this.logDebug(\"route in error\", i.version, i.id.toString(), e.message);\n return undefined;\n }\n })\n .sort((_a, _b) => {\n const a = _a === undefined ? ZERO : _a.data.amountOut.amount.raw.sub(_a.data.amountOut.fee?.raw ?? ZERO);\n const b = _b === undefined ? ZERO : _b.data.amountOut.amount.raw.sub(_b.data.amountOut.fee?.raw ?? ZERO);\n return a.lt(b) ? 1 : -1;\n })[0];\n if (maxFirstIn === undefined) continue;\n const routeAmountIn = new TokenAmount(\n toToken(routeToken),\n maxFirstIn.data.amountOut.amount.raw.sub(maxFirstIn.data.amountOut.fee?.raw ?? ZERO),\n );\n for (const iOutPool of info.out) {\n try {\n const outC = this.computeAmountOut({\n itemPool: iOutPool,\n tickCache,\n simulateCache,\n chainTime,\n epochInfo,\n slippage,\n outputToken,\n amountIn: routeAmountIn,\n });\n outRoute.push({\n ...outC,\n allTrade: maxFirstIn.data.allTrade && outC.allTrade ? true : false,\n amountIn: maxFirstIn.data.amountIn,\n amountOut: outC.amountOut,\n minAmountOut: outC.minAmountOut,\n currentPrice: undefined,\n executionPrice: new Decimal(\n new Price({\n baseToken: maxFirstIn.data.amountIn.amount.token,\n denominator: maxFirstIn.data.amountIn.amount.raw,\n quoteToken: outC.amountOut.amount.token,\n numerator: outC.amountOut.amount.raw.sub(outC.amountOut.fee?.raw ?? ZERO),\n }).toFixed(),\n ),\n priceImpact: new Decimal(maxFirstIn.data.priceImpact.add(outC.priceImpact).toFixed()),\n fee: [maxFirstIn.data.fee[0], outC.fee[0]],\n routeType: \"route\",\n poolInfoList: [maxFirstIn.pool, iOutPool],\n remainingAccounts: [maxFirstIn.data.remainingAccounts[0], outC.remainingAccounts[0]],\n minMiddleAmountFee: outC.amountOut.fee?.raw\n ? new TokenAmount(\n (maxFirstIn.data.amountOut.amount as TokenAmount).token,\n (maxFirstIn.data.amountOut.fee?.raw ?? ZERO).add(outC.amountOut.fee?.raw ?? ZERO),\n )\n : undefined,\n middleToken: (maxFirstIn.data.amountOut.amount as TokenAmount).token,\n poolReady: maxFirstIn.data.poolReady && outC.poolReady,\n poolType: [maxFirstIn.data.poolType, outC.poolType],\n feeConfig: _inFeeConfig,\n expirationTime: minExpirationTime(maxFirstIn.data.expirationTime, outC.expirationTime),\n });\n } catch (e: any) {\n this.logDebug(\"route out error\", iOutPool.version, iOutPool.id.toString(), e.message);\n /* empty */\n }\n }\n }\n\n return outRoute\n .filter((i) => {\n if (!i.allTrade)\n this.logDebug(`pool ${i.poolInfoList.map((p) => p.id.toString()).join(\",\")} filter out since not all trade`);\n return i.allTrade;\n })\n .sort((a, b) => (a.amountOut.amount.raw.sub(b.amountOut.amount.raw).gt(ZERO) ? -1 : 1));\n }\n\n /** trade related utils */\n\n private computeAmountOut({\n itemPool,\n tickCache,\n simulateCache,\n chainTime,\n epochInfo,\n slippage,\n outputToken,\n amountIn,\n }: {\n itemPool: ComputePoolType;\n tickCache: ReturnTypeFetchMultiplePoolTickArrays;\n simulateCache: ReturnTypeFetchMultipleInfo;\n chainTime: number;\n epochInfo: EpochInfo;\n amountIn: TokenAmount;\n outputToken: ApiV3Token;\n slippage: number;\n }): ComputeAmountOutAmmLayout {\n if (itemPool.version === 6) {\n const {\n allTrade,\n realAmountIn,\n amountOut,\n minAmountOut,\n expirationTime,\n currentPrice,\n executionPrice,\n priceImpact,\n fee,\n remainingAccounts,\n executionPriceX64,\n } = PoolUtils.computeAmountOutFormat({\n poolInfo: itemPool,\n tickArrayCache: tickCache[itemPool.id.toString()],\n amountIn: amountIn.raw,\n tokenOut: outputToken,\n slippage,\n epochInfo,\n catchLiquidityInsufficient: true,\n });\n return {\n allTrade,\n amountIn: realAmountIn,\n amountOut,\n minAmountOut,\n currentPrice: new Decimal(currentPrice.toFixed()),\n executionPrice: new Decimal(executionPrice.toFixed()),\n priceImpact: new Decimal(priceImpact.toFixed()),\n fee: [fee],\n remainingAccounts: [remainingAccounts],\n routeType: \"amm\",\n poolInfoList: [itemPool],\n poolReady: itemPool.startTime < chainTime,\n poolType: \"CLMM\",\n slippage,\n clmmExPriceX64: [executionPriceX64],\n expirationTime: minExpirationTime(realAmountIn.expirationTime, expirationTime),\n };\n } else if (itemPool.version === 7) {\n const { allTrade, executionPrice, amountOut, minAmountOut, priceImpact, fee } = this.scope.cpmm.computeSwapAmount(\n {\n pool: itemPool,\n outputMint: outputToken.address,\n amountIn: amountIn.raw,\n slippage,\n },\n );\n\n return {\n allTrade,\n amountIn: { amount: amountIn, fee: undefined, expirationTime: undefined },\n amountOut: {\n amount: toTokenAmount({\n ...outputToken,\n amount: amountOut,\n }),\n fee: undefined,\n expirationTime: undefined,\n },\n minAmountOut: {\n amount: toTokenAmount({\n ...outputToken,\n amount: minAmountOut,\n }),\n fee: undefined,\n expirationTime: undefined,\n },\n currentPrice: itemPool.poolPrice,\n executionPrice,\n priceImpact,\n fee: [new TokenAmount(amountIn.token, fee)],\n remainingAccounts: [],\n routeType: \"amm\",\n poolInfoList: [itemPool],\n poolReady: itemPool.openTime.toNumber() < chainTime,\n poolType: \"CPMM\",\n slippage,\n clmmExPriceX64: [undefined],\n expirationTime: undefined,\n };\n } else {\n if (![1, 6, 7].includes(simulateCache[itemPool.id.toString()].status)) throw Error(\"swap error\");\n const { amountOut, minAmountOut, currentPrice, executionPrice, priceImpact, fee } =\n this.scope.liquidity.computeAmountOut({\n poolInfo: simulateCache[itemPool.id.toString()],\n amountIn: amountIn.raw,\n mintIn: amountIn.token.mint,\n mintOut: outputToken.address,\n slippage,\n });\n return {\n amountIn: { amount: amountIn, fee: undefined, expirationTime: undefined },\n amountOut: {\n amount: toTokenAmount({\n ...outputToken,\n amount: amountOut,\n }),\n fee: undefined,\n expirationTime: undefined,\n },\n minAmountOut: {\n amount: toTokenAmount({\n ...outputToken,\n amount: minAmountOut,\n }),\n fee: undefined,\n expirationTime: undefined,\n },\n currentPrice,\n executionPrice,\n priceImpact,\n fee: [new TokenAmount(amountIn.token, fee)],\n routeType: \"amm\",\n poolInfoList: [itemPool],\n remainingAccounts: [],\n poolReady: Number(simulateCache[itemPool.id as string].openTime) < chainTime,\n poolType: itemPool.version === 5 ? \"STABLE\" : undefined,\n expirationTime: undefined,\n allTrade: true,\n slippage,\n clmmExPriceX64: [undefined],\n };\n }\n }\n\n public async computePoolToPoolKeys({\n pools,\n clmmRpcData = {},\n ammRpcData = {},\n }: {\n pools: ComputePoolType[];\n clmmRpcData?: Record<string, ClmmRpcData>;\n ammRpcData?: Record<string, AmmRpcData>;\n }): Promise<PoolKeys[]> {\n const clmmFetchKeys = new Set(\n pools.filter((p) => p.version === 6 && !clmmRpcData[p.id.toString()]).map((p) => p.id.toString()),\n );\n if (clmmFetchKeys.size > 0) {\n const clmmData = await this.scope.clmm.getRpcClmmPoolInfos({ poolIds: Array.from(clmmFetchKeys) });\n Object.keys(clmmData).forEach((poolId) => {\n clmmRpcData[poolId] = clmmData[poolId];\n });\n }\n\n const ammFetchKeys = new Set(\n pools.filter((p) => p.version === 4 && !ammRpcData[p.id.toString()]).map((p) => p.id.toString()),\n );\n if (ammFetchKeys.size > 0) {\n const ammData = await this.scope.liquidity.getRpcPoolInfos(Array.from(clmmFetchKeys));\n Object.keys(ammData).forEach((poolId) => {\n ammRpcData[poolId] = ammData[poolId];\n });\n }\n\n const ammMarketFetchKeys = new Set(\n pools.filter((p) => p.version === 4).map((p) => (p as ComputeAmountOutParam[\"poolInfo\"]).marketId),\n );\n const marketData: Record<\n string,\n {\n marketProgramId: string;\n marketId: string;\n marketAuthority: string;\n marketBaseVault: string;\n marketQuoteVault: string;\n marketBids: string;\n marketAsks: string;\n marketEventQueue: string;\n }\n > = {};\n if (ammMarketFetchKeys.size > 0) {\n const marketAccount = await getMultipleAccountsInfoWithCustomFlags(\n this.scope.connection,\n Array.from(ammMarketFetchKeys).map((p) => ({ pubkey: new PublicKey(p) })),\n );\n marketAccount.forEach((m) => {\n if (!m.accountInfo) return;\n const itemMarketInfo = MARKET_STATE_LAYOUT_V3.decode(m.accountInfo.data);\n marketData[m.pubkey.toBase58()] = {\n marketId: m.pubkey.toString(),\n marketProgramId: m.accountInfo.owner.toString(),\n marketAuthority: Market.getAssociatedAuthority({\n programId: m.accountInfo.owner,\n marketId: m.pubkey,\n }).publicKey.toString(),\n marketBaseVault: itemMarketInfo.baseVault.toString(),\n marketQuoteVault: itemMarketInfo.quoteVault.toString(),\n marketBids: itemMarketInfo.bids.toString(),\n marketAsks: itemMarketInfo.asks.toString(),\n marketEventQueue: itemMarketInfo.eventQueue.toString(),\n };\n });\n }\n\n const poolKeys: PoolKeys[] = [];\n pools.forEach((pool) => {\n if (pool.version === 6) {\n const rpcInfo = clmmRpcData[pool.id.toString()];\n const clmmKeys: ClmmKeys = {\n programId: pool.programId.toBase58(),\n id: pool.id.toBase58(),\n mintA: pool.mintA,\n mintB: pool.mintB,\n openTime: String(pool.startTime),\n vault: {\n A: rpcInfo.vaultA.toBase58(),\n B: rpcInfo.vaultB.toBase58(),\n },\n config: {\n ...pool.ammConfig,\n id: pool.ammConfig.id.toString(),\n defaultRange: 0,\n defaultRangePoint: [],\n },\n rewardInfos: [],\n };\n poolKeys.push(clmmKeys);\n } else if (pool.version === 4) {\n const rpcInfo = ammRpcData[pool.id.toString()];\n const ammKeys: AmmV4Keys = {\n programId: pool.programId,\n id: pool.id,\n mintA: pool.mintA,\n mintB: pool.mintB,\n openTime: String(pool.openTime),\n vault: {\n A: rpcInfo.baseVault.toBase58(),\n B: rpcInfo.quoteVault.toBase58(),\n },\n authority: getLiquidityAssociatedAuthority({ programId: new PublicKey(pool.programId) }).publicKey.toString(),\n openOrders: rpcInfo.openOrders.toBase58(),\n targetOrders: rpcInfo.targetOrders.toBase58(),\n mintLp: pool.lpMint,\n ...marketData[pool.marketId],\n };\n poolKeys.push(ammKeys);\n } else if (pool.version === 7) {\n poolKeys.push({\n programId: pool.programId.toBase58(),\n id: pool.id.toBase58(),\n mintA: pool.mintA,\n mintB: pool.mintB,\n openTime: String(pool.openTime),\n authority: getPdaPoolAuthority(pool.programId).publicKey.toBase58(),\n vault: {\n A: pool.vaultA.toBase58(),\n B: pool.vaultB.toBase58(),\n },\n mintLp: toApiV3Token({\n address: pool.mintLp.toBase58(),\n programId: TOKEN_PROGRAM_ID.toBase58(),\n decimals: pool.lpDecimals,\n }),\n config: {\n id: pool.configId.toBase58(),\n ...pool.configInfo,\n protocolFeeRate: pool.configInfo.protocolFeeRate.toNumber(),\n tradeFeeRate: pool.configInfo.tradeFeeRate.toNumber(),\n fundFeeRate: pool.configInfo.fundFeeRate.toNumber(),\n createPoolFee: pool.configInfo.createPoolFee.toString(),\n },\n });\n }\n });\n return poolKeys;\n }\n}\n","import { get, set } from \"lodash\";\n\nexport type ModuleName = \"Common.Api\";\n\nexport enum LogLevel {\n Error,\n Warning,\n Info,\n Debug,\n}\nexport class Logger {\n private logLevel: LogLevel;\n private name: string;\n constructor(params: { name: string; logLevel?: LogLevel }) {\n this.logLevel = params.logLevel !== undefined ? params.logLevel : LogLevel.Error;\n this.name = params.name;\n }\n\n set level(logLevel: LogLevel) {\n this.logLevel = logLevel;\n }\n get time(): string {\n return Date.now().toString();\n }\n get moduleName(): string {\n return this.name;\n }\n\n private isLogLevel(level: LogLevel): boolean {\n return level <= this.logLevel;\n }\n\n public error(...props): Logger {\n if (!this.isLogLevel(LogLevel.Error)) return this;\n console.error(this.time, this.name, \"sdk logger error\", ...props);\n return this;\n }\n\n public logWithError(...props): Logger {\n // this.error(...props)\n const msg = props.map((arg) => (typeof arg === \"object\" ? JSON.stringify(arg) : arg)).join(\", \");\n throw new Error(msg);\n }\n\n public warning(...props): Logger {\n if (!this.isLogLevel(LogLevel.Warning)) return this;\n console.warn(this.time, this.name, \"sdk logger warning\", ...props);\n return this;\n }\n\n public info(...props): Logger {\n if (!this.isLogLevel(LogLevel.Info)) return this;\n console.info(this.time, this.name, \"sdk logger info\", ...props);\n return this;\n }\n\n public debug(...props): Logger {\n if (!this.isLogLevel(LogLevel.Debug)) return this;\n console.debug(this.time, this.name, \"sdk logger debug\", ...props);\n return this;\n }\n}\n\nconst moduleLoggers: { [key in ModuleName]?: Logger } = {};\nconst moduleLevels: { [key in ModuleName]?: LogLevel } = {};\n\nexport function createLogger(moduleName: string): Logger {\n let logger = get(moduleLoggers, moduleName);\n if (!logger) {\n // default level is error\n const logLevel = get(moduleLevels, moduleName);\n\n logger = new Logger({ name: moduleName, logLevel });\n set(moduleLoggers, moduleName, logger);\n }\n\n return logger;\n}\n\nexport function setLoggerLevel(moduleName: string, level: LogLevel): void {\n set(moduleLevels, moduleName, level);\n\n const logger = get(moduleLoggers, moduleName);\n if (logger) logger.level = level;\n}\n","import { PublicKey } from \"@solana/web3.js\";\nimport BN from \"bn.js\";\n\nimport { Fraction, Percent, Price, Token, TokenAmount } from \"../module\";\nimport { ReplaceType } from \"../raydium/type\";\n\nimport { tryParsePublicKey } from \"./pubKey\";\n\nexport async function sleep(ms: number): Promise<void> {\n new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport function getTimestamp(): number {\n return new Date().getTime();\n}\n\nexport function notInnerObject(v: unknown): v is Record<string, any> {\n return (\n typeof v === \"object\" &&\n v !== null &&\n ![Token, TokenAmount, PublicKey, Fraction, BN, Price, Percent].some((o) => typeof o === \"object\" && v instanceof o)\n );\n}\n\nexport function jsonInfo2PoolKeys<T>(jsonInfo: T): ReplaceType<T, string, PublicKey> {\n // @ts-expect-error no need type for inner code\n return typeof jsonInfo === \"string\"\n ? tryParsePublicKey(jsonInfo)\n : Array.isArray(jsonInfo)\n ? jsonInfo.map((k) => jsonInfo2PoolKeys(k))\n : notInnerObject(jsonInfo)\n ? Object.fromEntries(Object.entries(jsonInfo).map(([k, v]) => [k, jsonInfo2PoolKeys(v)]))\n : jsonInfo;\n}\n","im