UNPKG

test-rrr-sdk

Version:

An SDK for building applications on top of Raydium.

1 lines 946 kB
{"version":3,"sources":["../../../src/raydium/tradeV2/trade.ts","../../../node_modules/decimal.js/decimal.mjs","../../../src/common/accountInfo.ts","../../../src/common/logger.ts","../../../src/common/bignumber.ts","../../../src/module/amount.ts","../../../src/module/formatter.ts","../../../src/module/fraction.ts","../../../src/common/constant.ts","../../../src/raydium/token/constant.ts","../../../src/module/token.ts","../../../src/common/pubKey.ts","../../../src/module/currency.ts","../../../src/module/percent.ts","../../../src/module/price.ts","../../../src/common/utility.ts","../../../src/common/lodash.ts","../../../src/common/pda.ts","../../../src/common/txTool/txUtils.ts","../../../src/common/txTool/txType.ts","../../../src/common/programId.ts","../../../src/common/transfer.ts","../../../src/common/txTool/lookupTable.ts","../../../src/common/txTool/txTool.ts","../../../src/common/fee.ts","../../../src/marshmallow/index.ts","../../../src/marshmallow/buffer-layout.ts","../../../src/raydium/clmm/clmm.ts","../../../src/raydium/token/utils.ts","../../../src/raydium/clmm/instrument.ts","../../../src/raydium/clmm/utils/tick.ts","../../../src/raydium/clmm/utils/constants.ts","../../../src/raydium/clmm/utils/math.ts","../../../src/raydium/clmm/utils/util.ts","../../../src/raydium/clmm/utils/pda.ts","../../../src/raydium/clmm/utils/pool.ts","../../../src/raydium/clmm/utils/position.ts","../../../src/raydium/clmm/utils/tickQuery.ts","../../../src/raydium/clmm/utils/tickarrayBitmap.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/constantProduct.ts","../../../src/raydium/liquidity/constant.ts","../../../src/raydium/liquidity/layout.ts","../../../src/raydium/liquidity/utils.ts","../../../src/raydium/liquidity/instruction.ts","../../../src/raydium/liquidity/stable.ts","../../../src/raydium/liquidity/serum.ts","../../../src/raydium/account/layout.ts","../../../src/raydium/account/util.ts","../../../src/raydium/account/instruction.ts","../../../src/raydium/token/layout.ts","../../../src/raydium/serum/id.ts","../../../src/raydium/serum/layout.ts","../../../src/raydium/serum/serum.ts","../../../src/raydium/tradeV2/instrument.ts"],"sourcesContent":["import { EpochInfo, PublicKey } from \"@solana/web3.js\";\nimport { createTransferInstruction, TOKEN_PROGRAM_ID, TOKEN_2022_PROGRAM_ID } from \"@solana/spl-token\";\nimport BN from \"bn.js\";\nimport Decimal from \"decimal.js\";\nimport { AmmV4Keys, ApiV3Token, ClmmKeys, PoolKeys } from \"@/api\";\nimport {\n AMM_V4,\n BigNumberish,\n CLMM_PROGRAM_ID,\n CREATE_CPMM_POOL_PROGRAM,\n fetchMultipleMintInfos,\n getMultipleAccountsInfoWithCustomFlags,\n minExpirationTime,\n parseBigNumberish,\n solToWSol,\n WSOLMint,\n} from \"@/common\";\nimport { MakeMultiTxData, MakeTxData } from \"@/common/txTool/txTool\";\nimport { InstructionType, TxVersion } from \"@/common/txTool/txType\";\nimport { publicKey, struct } from \"../../marshmallow\";\nimport { Price, TokenAmount } from \"../../module\";\nimport { ClmmRpcData, ComputeClmmPoolInfo, PoolUtils, ReturnTypeFetchMultiplePoolTickArrays } from \"../../raydium/clmm\";\nimport { PoolInfoLayout } from \"../../raydium/clmm/layout\";\nimport { CpmmPoolInfoLayout, getPdaPoolAuthority } from \"../../raydium/cpmm\";\nimport {\n ComputeAmountOutParam,\n getLiquidityAssociatedAuthority,\n liquidityStateV4Layout,\n toAmmComputePoolInfo,\n} from \"../../raydium/liquidity\";\nimport { ComputeBudgetConfig, ReturnTypeFetchMultipleMintInfos } from \"../../raydium/type\";\nimport { closeAccountInstruction, createWSolAccountInstructions } from \"../account/instruction\";\nimport { TokenAccount } from \"../account/types\";\nimport { CpmmComputeData } from \"../cpmm\";\nimport { AmmRpcData } from \"../liquidity\";\nimport ModuleBase, { ModuleBaseProps } from \"../moduleBase\";\nimport { Market, MARKET_STATE_LAYOUT_V3 } from \"../serum\";\nimport { toApiV3Token, toToken, toTokenAmount } from \"../token\";\nimport { makeSwapInstruction } from \"./instrument\";\nimport {\n BasicPoolInfo,\n ComputeAmountOutAmmLayout,\n ComputeAmountOutLayout,\n ComputePoolType,\n ComputeRoutePathType,\n ReturnTypeFetchMultipleInfo,\n ReturnTypeGetAllRoute,\n RoutePathType,\n} from \"./type\";\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 feePayer?: PublicKey;\n }): Promise<MakeTxData<T>> {\n const { amount, tokenProgram, txVersion = TxVersion.LEGACY, feePayer } = props;\n const tokenAccounts = await this.getWSolAccounts();\n const txBuilder = this.createTxBuilder(feePayer);\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 }\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 feePayer?: PublicKey,\n ): Promise<MakeTxData<T>> {\n // const tokenAccounts = await this.getWSolAccounts();\n\n const txBuilder = this.createTxBuilder(feePayer);\n\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: 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 feePayer,\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 feePayer?: PublicKey;\n }): Promise<MakeMultiTxData<T>> {\n const txBuilder = this.createTxBuilder(feePayer);\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\" && !isOutputSol) {\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(ammFetchKeys));\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 observationId: pool.observationId.toBase58(),\n exBitmapAccount: pool.exBitmapAccount.toBase58(),\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 observationId: pool.observationId.toBase58(),\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","/*\r\n * decimal.js v10.3.1\r\n * An arbitrary-precision Decimal type for JavaScript.\r\n * https://github.com/MikeMcl/decimal.js\r\n * Copyright (c) 2021 Michael Mclaughlin <M8ch88l@gmail.com>\r\n * MIT Licence\r\n */\r\n\r\n\r\n// ----------------------------------- EDITABLE DEFAULTS ------------------------------------ //\r\n\r\n\r\n // The maximum exponent magnitude.\r\n // The limit on the value of `toExpNeg`, `toExpPos`, `minE` and `maxE`.\r\nvar EXP_LIMIT = 9e15, // 0 to 9e15\r\n\r\n // The limit on the value of `precision`, and on the value of the first argument to\r\n // `toDecimalPlaces`, `toExponential`, `toFixed`, `toPrecision` and `toSignificantDigits`.\r\n MAX_DIGITS = 1e9, // 0 to 1e9\r\n\r\n // Base conversion alphabet.\r\n NUMERALS = '0123456789abcdef',\r\n\r\n // The natural logarithm of 10 (1025 digits).\r\n LN10 = '2.3025850929940456840179914546843642076011014886287729760333279009675726096773524802359972050895982983419677840422862486334095254650828067566662873690987816894829072083255546808437998948262331985283935053089653777326288461633662222876982198867465436674744042432743651550489343149393914796194044002221051017141748003688084012647080685567743216228355220114804663715659121373450747856947683463616792101806445070648000277502684916746550586856935673420670581136429224554405758925724208241314695689016758940256776311356919292033376587141660230105703089634572075440370847469940168269282808481184289314848524948644871927809676271275775397027668605952496716674183485704422507197965004714951050492214776567636938662976979522110718264549734772662425709429322582798502585509785265383207606726317164309505995087807523710333101197857547331541421808427543863591778117054309827482385045648019095610299291824318237525357709750539565187697510374970888692180205189339507238539205144634197265287286965110862571492198849978748873771345686209167058',\r\n\r\n // Pi (1025 digits).\r\n PI = '3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989380952572010654858632789',\r\n\r\n\r\n // The initial configuration properties of the Decimal constructor.\r\n DEFAULTS = {\r\n\r\n // These values must be integers within the stated ranges (inclusive).\r\n // Most of these values can be changed at run-time using the `Decimal.config` method.\r\n\r\n // The maximum number of significant digits of the result of a calculation or base conversion.\r\n // E.g. `Decimal.config({ precision: 20 });`\r\n precision: 20, // 1 to MAX_DIGITS\r\n\r\n // The rounding mode used when rounding to `precision`.\r\n //\r\n // ROUND_UP 0 Away from zero.\r\n // ROUND_DOWN 1 Towards zero.\r\n // ROUND_CEIL