UNPKG

test-raydium-sdk-v2

Version:

An SDK for building applications on top of Raydium.

1 lines 351 kB
{"version":3,"sources":["../../../src/raydium/ido/ido.ts","../../../src/common/logger.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/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/lodash.ts","../../../src/common/programId.ts","../../../src/common/pda.ts","../../../src/common/transfer.ts","../../../src/raydium/moduleBase.ts","../../../src/raydium/ido/instruction.ts","../../../src/marshmallow/index.ts","../../../src/marshmallow/buffer-layout.ts","../../../src/raydium/ido/layout.ts"],"sourcesContent":["import { PublicKey } from \"@solana/web3.js\";\nimport ModuleBase from \"../moduleBase\";\nimport { makeClaimInstruction, makeClaimInstructionV4 } from \"./instruction\";\nimport { jsonInfo2PoolKeys } from \"@/common/utility\";\nimport { OwnerIdoInfo, IdoKeysData } from \"@/api/type\";\nimport { IDO_ALL_PROGRAM } from \"@/common/programId\";\nimport { WSOLMint } from \"@/common/pubKey\";\nimport { TxVersion } from \"@/common/txTool/txType\";\nimport { MakeTxData } from \"@/common/txTool/txTool\";\nimport BN from \"bn.js\";\nimport { userInfo } from \"os\";\n\nconst PROGRAM_TO_VERSION = {\n [IDO_ALL_PROGRAM.IDO_PROGRAM_ID_V1.toString()]: 1,\n [IDO_ALL_PROGRAM.IDO_PROGRAM_ID_V2.toString()]: 2,\n [IDO_ALL_PROGRAM.IDO_PROGRAM_ID_V3.toString()]: 3,\n [IDO_ALL_PROGRAM.IDO_PROGRAM_ID_V4.toString()]: 4,\n};\n\nexport default class MarketV2 extends ModuleBase {\n public async claim<T extends TxVersion>({\n ownerInfo,\n idoKeys,\n associatedOnly = true,\n checkCreateATAOwner = false,\n txVersion,\n }: {\n ownerInfo: OwnerIdoInfo[keyof OwnerIdoInfo] & { userIdoInfo: string };\n idoKeys: IdoKeysData;\n associatedOnly?: boolean;\n checkCreateATAOwner?: boolean;\n txVersion?: T;\n }): Promise<MakeTxData> {\n const txBuilder = this.createTxBuilder();\n const version = PROGRAM_TO_VERSION[idoKeys.programId];\n\n if (!version) this.logAndCreateError(\"invalid version\", version);\n const poolConfigKey = jsonInfo2PoolKeys(idoKeys);\n\n const [hasUnClaimedProject, hasUnClaimedBuy] = [!new BN(ownerInfo.coin).isZero(), !new BN(ownerInfo.pc).isZero()];\n\n const userProjectUseSolBalance = poolConfigKey.projectInfo.mint.address.equals(WSOLMint);\n const { account: userProjectTokenAccount, instructionParams: userProjectInstructionParams } =\n await this.scope.account.getOrCreateTokenAccount({\n tokenProgram: poolConfigKey.projectInfo.mint.programId,\n mint: poolConfigKey.projectInfo.mint.address,\n owner: this.scope.ownerPubKey,\n createInfo: {\n payer: this.scope.ownerPubKey,\n amount: 0,\n },\n skipCloseAccount: !userProjectUseSolBalance,\n notUseTokenAccount: userProjectUseSolBalance,\n associatedOnly: userProjectUseSolBalance ? false : associatedOnly,\n checkCreateATAOwner,\n });\n\n if (!userProjectTokenAccount && hasUnClaimedProject)\n this.logAndCreateError(\"target token accounts not found\", \"mint\", idoKeys.projectInfo.mint.address);\n hasUnClaimedProject && userProjectInstructionParams && txBuilder.addInstruction(userProjectInstructionParams);\n\n const buyMintUseSolBalance = poolConfigKey.buyInfo.mint.address.equals(WSOLMint);\n const { account: userBuyTokenAccount, instructionParams } = await this.scope.account.getOrCreateTokenAccount({\n tokenProgram: poolConfigKey.buyInfo.mint.programId,\n mint: poolConfigKey.buyInfo.mint.address,\n owner: this.scope.ownerPubKey,\n createInfo: {\n payer: this.scope.ownerPubKey,\n amount: 0,\n },\n skipCloseAccount: !buyMintUseSolBalance,\n notUseTokenAccount: buyMintUseSolBalance,\n associatedOnly: buyMintUseSolBalance ? false : associatedOnly,\n checkCreateATAOwner,\n });\n if (!userProjectTokenAccount && hasUnClaimedBuy)\n this.logAndCreateError(\"target token accounts not found\", \"mint\", idoKeys.projectInfo.mint.address);\n hasUnClaimedBuy && instructionParams && txBuilder.addInstruction(instructionParams);\n\n if (!userProjectTokenAccount || !userBuyTokenAccount)\n this.logAndCreateError(\n \"target token accounts not found\",\n \"mint\",\n idoKeys.projectInfo.mint.address,\n idoKeys.buyInfo.mint.address,\n );\n\n if (version === 3) {\n return txBuilder\n .addInstruction({\n instructions: [\n ...(hasUnClaimedProject\n ? [\n makeClaimInstruction<\"3\">(\n { programId: poolConfigKey.programId },\n {\n idoId: poolConfigKey.id,\n authority: poolConfigKey.authority,\n poolTokenAccount: poolConfigKey.projectInfo.vault,\n userTokenAccount: userProjectTokenAccount!,\n userIdoInfo: new PublicKey(ownerInfo.userIdoInfo),\n userOwner: this.scope.ownerPubKey,\n },\n ),\n ]\n : []),\n ...(hasUnClaimedBuy\n ? [\n makeClaimInstruction<\"3\">(\n { programId: new PublicKey(idoKeys.programId) },\n {\n idoId: poolConfigKey.id,\n authority: poolConfigKey.authority,\n poolTokenAccount: poolConfigKey.buyInfo.vault,\n userTokenAccount: userBuyTokenAccount!,\n userIdoInfo: new PublicKey(ownerInfo.userIdoInfo),\n userOwner: this.scope.ownerPubKey,\n },\n ),\n ]\n : []),\n ],\n })\n .versionBuild({ txVersion }) as Promise<MakeTxData>;\n }\n if (version < 3) {\n if (!hasUnClaimedProject && !hasUnClaimedBuy) this.logAndCreateError(\"no claimable rewards\");\n return txBuilder\n .addInstruction({\n instructions: [\n makeClaimInstruction<\"\">(\n { programId: poolConfigKey.programId },\n {\n idoId: poolConfigKey.id,\n authority: poolConfigKey.authority,\n poolQuoteTokenAccount: poolConfigKey.buyInfo.vault,\n poolBaseTokenAccount: poolConfigKey.projectInfo.vault,\n userQuoteTokenAccount: userBuyTokenAccount!,\n userBaseTokenAccount: userProjectTokenAccount!,\n userIdoInfo: new PublicKey(ownerInfo.userIdoInfo),\n userOwner: this.scope.ownerPubKey,\n },\n ),\n ],\n })\n .versionBuild({ txVersion }) as Promise<MakeTxData>;\n }\n\n const keys = {\n poolConfig: {\n id: poolConfigKey.id,\n programId: poolConfigKey.programId,\n authority: poolConfigKey.authority,\n baseVault: poolConfigKey.projectInfo.vault,\n quoteVault: poolConfigKey.buyInfo.vault,\n baseToken: idoKeys.projectInfo.mint,\n quoteToken: idoKeys.buyInfo.mint,\n },\n userKeys: {\n baseTokenAccount: userProjectTokenAccount!,\n quoteTokenAccount: userBuyTokenAccount!,\n ledgerAccount: new PublicKey(ownerInfo.userIdoInfo),\n owner: this.scope.ownerPubKey,\n },\n };\n\n return txBuilder\n .addInstruction({\n instructions: [\n ...(hasUnClaimedProject ? [makeClaimInstructionV4({ ...keys, side: \"base\" })] : []),\n ...(hasUnClaimedBuy ? [makeClaimInstructionV4({ ...keys, side: \"quote\" })] : []),\n ],\n })\n .versionBuild({ txVersion }) as Promise<MakeTxData>;\n }\n}\n","import { get, set } from \"lodash\";\nimport dayjs from \"dayjs\";\nimport utc from \"dayjs/plugin/utc\";\ndayjs.extend(utc);\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 dayjs().utc().format(\"YYYY/MM/DD HH:mm:ss UTC\");\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 {\n Connection,\n PublicKey,\n sendAndConfirmTransaction,\n Signer,\n Transaction,\n TransactionInstruction,\n TransactionMessage,\n VersionedTransaction,\n} from \"@solana/web3.js\";\nimport axios from \"axios\";\n\nimport { SignAllTransactions, ComputeBudgetConfig } from \"@/raydium/type\";\nimport { TxVersion } from \"./txType\";\nimport { Owner } from \"../owner\";\nimport { getRecentBlockHash, addComputeBudget, checkLegacyTxSize, checkV0TxSize, printSimulate } from \"./txUtils\";\nimport { CacheLTA, getMultipleLookupTableInfo, LOOKUP_TABLE_CACHE } from \"./lookupTable\";\n\ninterface SolanaFeeInfo {\n min: number;\n max: number;\n avg: number;\n priorityTx: number;\n nonVotes: number;\n priorityRatio: number;\n avgCuPerBlock: number;\n blockspaceUsageRatio: number;\n}\ntype SolanaFeeInfoJson = {\n \"1\": SolanaFeeInfo;\n \"5\": SolanaFeeInfo;\n \"15\": SolanaFeeInfo;\n};\n\ninterface TxBuilderInit {\n connection: Connection;\n feePayer: PublicKey;\n owner?: Owner;\n signAllTransactions?: SignAllTransactions;\n}\n\nexport interface AddInstructionParam {\n addresses?: Record<string, PublicKey>;\n instructions?: TransactionInstruction[];\n endInstructions?: TransactionInstruction[];\n lookupTableAddress?: string[];\n signers?: Signer[];\n instructionTypes?: string[];\n endInstructionTypes?: string[];\n}\n\nexport interface TxBuildData<T = Record<string, any>> {\n builder: TxBuilder;\n transaction: Transaction;\n instructionTypes: string[];\n signers: Signer[];\n execute: () => Promise<{ txId: string; signedTx: Transaction }>;\n extInfo: T;\n}\n\nexport interface TxV0BuildData<T = Record<string, any>> extends Omit<TxBuildData<T>, \"transaction\" | \"execute\"> {\n builder: TxBuilder;\n transaction: VersionedTransaction;\n buildProps?: {\n lookupTableCache?: CacheLTA;\n lookupTableAddress?: string[];\n };\n execute: () => Promise<{ txId: string; signedTx: VersionedTransaction }>;\n}\n\nexport interface ExecuteParam {\n sequentially: boolean;\n onTxUpdate?: (completeTxs: { txId: string; status: \"success\" | \"error\" | \"sent\" }[]) => void;\n}\nexport interface MultiTxBuildData<T = Record<string, any>> {\n builder: TxBuilder;\n transactions: Transaction[];\n instructionTypes: string[];\n signers: Signer[][];\n execute: (executeParams?: ExecuteParam) => Promise<{ txIds: string[]; signedTxs: Transaction[] }>;\n extInfo: T;\n}\n\nexport interface MultiTxV0BuildData<T = Record<string, any>>\n extends Omit<MultiTxBuildData<T>, \"transactions\" | \"execute\"> {\n builder: TxBuilder;\n transactions: VersionedTransaction[];\n buildProps?: {\n lookupTableCache?: CacheLTA;\n lookupTableAddress?: string[];\n };\n execute: (executeParams?: ExecuteParam) => Promise<{ txIds: string[]; signedTxs: VersionedTransaction[] }>;\n}\n\nexport type MakeMultiTxData<T = TxVersion.LEGACY, O = Record<string, any>> = T extends TxVersion.LEGACY\n ? MultiTxBuildData<O>\n : MultiTxV0BuildData<O>;\n\nexport type MakeTxData<T = TxVersion.LEGACY, O = Record<string, any>> = T extends TxVersion.LEGACY\n ? TxBuildData<O>\n : TxV0BuildData<O>;\n\nexport class TxBuilder {\n private connection: Connection;\n private owner?: Owner;\n private instructions: TransactionInstruction[] = [];\n private endInstructions: TransactionInstruction[] = [];\n private lookupTableAddress: string[] = [];\n private signers: Signer[] = [];\n private instructionTypes: string[] = [];\n private endInstructionTypes: string[] = [];\n private feePayer: PublicKey;\n private signAllTransactions?: SignAllTransactions;\n\n constructor(params: TxBuilderInit) {\n this.connection = params.connection;\n this.feePayer = params.feePayer;\n this.signAllTransactions = params.signAllTransactions;\n this.owner = params.owner;\n }\n\n get AllTxData(): {\n instructions: TransactionInstruction[];\n endInstructions: TransactionInstruction[];\n signers: Signer[];\n instructionTypes: string[];\n endInstructionTypes: string[];\n lookupTableAddress: string[];\n } {\n return {\n instructions: this.instructions,\n endInstructions: this.endInstructions,\n signers: this.signers,\n instructionTypes: this.instructionTypes,\n endInstructionTypes: this.endInstructionTypes,\n lookupTableAddress: this.lookupTableAddress,\n };\n }\n\n get allInstructions(): TransactionInstruction[] {\n return [...this.instructions, ...this.endInstructions];\n }\n\n public async getComputeBudgetConfig(): Promise<ComputeBudgetConfig | undefined> {\n const json = (\n await axios.get<SolanaFeeInfoJson>(`https://solanacompass.com/api/fees?cacheFreshTime=${5 * 60 * 1000}`)\n ).data;\n const { avg } = json?.[15] ?? {};\n if (!avg) return undefined;\n return {\n units: 600000,\n microLamports: Math.min(Math.ceil((avg * 1000000) / 600000), 25000),\n };\n }\n\n public addCustomComputeBudget(config?: ComputeBudgetConfig) {\n if (config) {\n const { instructions, instructionTypes } = addComputeBudget(config);\n this.instructions.unshift(...instructions);\n this.instructionTypes.unshift(...instructionTypes);\n return true;\n }\n return false;\n }\n\n public async calComputeBudget({\n config: propConfig,\n defaultIns,\n }: {\n config?: ComputeBudgetConfig;\n defaultIns?: TransactionInstruction[];\n }): Promise<void> {\n try {\n const config = propConfig || (await this.getComputeBudgetConfig());\n if (this.addCustomComputeBudget(config)) return;\n defaultIns && this.instructions.unshift(...defaultIns);\n } catch {\n defaultIns && this.instructions.unshift(...defaultIns);\n }\n }\n\n public addInstruction({\n instructions = [],\n endInstructions = [],\n signers = [],\n instructionTypes = [],\n endInstructionTypes = [],\n lookupTableAddress = [],\n }: AddInstructionParam): TxBuilder {\n this.instructions.push(...instructions);\n this.endInstructions.push(...endInstructions);\n this.signers.push(...signers);\n this.instructionTypes.push(...instructionTypes);\n this.endInstructionTypes.push(...endInstructionTypes);\n this.lookupTableAddress.push(...lookupTableAddress.filter((address) => address !== PublicKey.default.toString()));\n return this;\n }\n\n public async versionBuild<O = Record<string, any>>({\n txVersion,\n extInfo,\n }: {\n txVersion?: TxVersion;\n extInfo?: O;\n }): Promise<MakeTxData<TxVersion.LEGACY, O> | MakeTxData<TxVersion.V0, O>> {\n if (txVersion === TxVersion.V0) return (await this.buildV0({ ...(extInfo || {}) })) as MakeTxData<TxVersion.V0, O>;\n return this.build<O>(extInfo) as MakeTxData<TxVersion.LEGACY, O>;\n }\n\n public build<O = Record<string, any>>(extInfo?: O): MakeTxData<TxVersion.LEGACY, O> {\n const transaction = new Transaction();\n if (this.allInstructions.length) transaction.add(...this.allInstructions);\n transaction.feePayer = this.feePayer;\n\n return {\n builder: this,\n transaction,\n signers: this.signers,\n instructionTypes: [...this.instructionTypes, ...this.endInstructionTypes],\n execute: async () => {\n const recentBlockHash = await getRecentBlockHash(this.connection);\n transaction.recentBlockhash = recentBlockHash;\n if (this.signers.length) transaction.sign(...this.signers);\n printSimulate([transaction]);\n if (this.owner?.isKeyPair) {\n return {\n txId: await sendAndConfirmTransaction(this.connection, transaction, this.signers),\n signedTx: transaction,\n };\n }\n if (this.signAllTransactions) {\n const txs = await this.signAllTransactions([transaction]);\n return {\n txId: await this.connection.sendRawTransaction(txs[0].serialize(), { skipPreflight: true }),\n signedTx: txs[0],\n };\n }\n throw new Error(\"please connect wallet first\");\n },\n extInfo: extInfo || ({} as O),\n };\n }\n\n public buildMultiTx<T = Record<string, any>>(params: {\n extraPreBuildData?: MakeTxData<TxVersion.LEGACY>[];\n extInfo?: T;\n }): MultiTxBuildData {\n const { extraPreBuildData = [], extInfo } = params;\n const { transaction } = this.build(extInfo);\n\n const filterExtraBuildData = extraPreBuildData.filter((data) => data.transaction.instructions.length > 0);\n\n const allTransactions: Transaction[] = [transaction, ...filterExtraBuildData.map((data) => data.transaction)];\n const allSigners: Signer[][] = [this.signers, ...filterExtraBuildData.map((data) => data.signers)];\n const allInstructionTypes: string[] = [\n ...this.instructionTypes,\n ...filterExtraBuildData.map((data) => data.instructionTypes).flat(),\n ];\n\n return {\n builder: this,\n transactions: allTransactions,\n signers: allSigners,\n instructionTypes: allInstructionTypes,\n execute: async (executeParams?: ExecuteParam) => {\n const { sequentially, onTxUpdate } = executeParams || {};\n const recentBlockHash = await getRecentBlockHash(this.connection);\n if (this.owner?.isKeyPair) {\n return {\n txIds: await await Promise.all(\n allTransactions.map(async (tx, idx) => {\n tx.recentBlockhash = recentBlockHash;\n return await sendAndConfirmTransaction(this.connection, tx, allSigners[idx]);\n }),\n ),\n signedTxs: allTransactions,\n };\n }\n\n if (this.signAllTransactions) {\n const partialSignedTxs = allTransactions.map((tx, idx) => {\n tx.recentBlockhash = recentBlockHash;\n if (allSigners[idx].length) tx.sign(...allSigners[idx]);\n return tx;\n });\n printSimulate(partialSignedTxs);\n const signedTxs = await this.signAllTransactions(partialSignedTxs);\n if (sequentially) {\n let i = 0;\n const processedTxs: { txId: string; status: \"success\" | \"error\" | \"sent\" }[] = [];\n const checkSendTx = async (): Promise<void> => {\n if (!signedTxs[i]) return;\n const txId = await this.connection.sendRawTransaction(signedTxs[i].serialize(), { skipPreflight: true });\n processedTxs.push({ txId, status: \"sent\" });\n onTxUpdate?.([...processedTxs]);\n i++;\n this.connection.onSignature(\n txId,\n (signatureResult) => {\n const targetTxIdx = processedTxs.findIndex((tx) => tx.txId === txId);\n if (targetTxIdx > -1) processedTxs[targetTxIdx].status = signatureResult.err ? \"error\" : \"success\";\n onTxUpdate?.([...processedTxs]);\n checkSendTx();\n },\n \"processed\",\n );\n this.connection.getSignatureStatus(txId);\n };\n await checkSendTx();\n return {\n txIds: processedTxs.map((d) => d.txId),\n signedTxs,\n };\n } else {\n const txIds: string[] = [];\n for (let i = 0; i < signedTxs.length; i += 1) {\n const txId = await this.connection.sendRawTransaction(signedTxs[i].serialize(), { skipPreflight: true });\n txIds.push(txId);\n }\n return {\n txIds,\n signedTxs,\n };\n }\n }\n throw new Error(\"please connect wallet first\");\n },\n extInfo: extInfo || {},\n };\n }\n\n public async versionMultiBuild<T extends TxVersion, O = Record<string, any>>({\n extraPreBuildData,\n txVersion,\n extInfo,\n }: {\n extraPreBuildData?: MakeTxData<TxVersion.V0>[] | MakeTxData<TxVersion.LEGACY>[];\n txVersion?: T;\n extInfo?: O;\n }): Promise<MakeMultiTxData<T, O>> {\n if (txVersion === TxVersion.V0)\n return (await this.buildV0MultiTx({\n extraPreBuildData: extraPreBuildData as MakeTxData<TxVersion.V0>[],\n buildProps: extInfo || {},\n })) as MakeMultiTxData<T, O>;\n return this.buildMultiTx<O>({\n extraPreBuildData: extraPreBuildData as MakeTxData<TxVersion.LEGACY>[],\n extInfo,\n }) as MakeMultiTxData<T, O>;\n }\n\n public async buildV0<O = Record<string, any>>(\n props?: O & {\n lookupTableCache?: CacheLTA;\n lookupTableAddress?: string[];\n forerunCreate?: boolean;\n },\n ): Promise<MakeTxData<TxVersion.V0, O>> {\n const { lookupTableCache = {}, lookupTableAddress = [], forerunCreate, ...extInfo } = props || {};\n const lookupTableAddressAccount = {\n ...LOOKUP_TABLE_CACHE,\n ...lookupTableCache,\n };\n const allLTA = Array.from(new Set<string>([...lookupTableAddress, ...this.lookupTableAddress]));\n const needCacheLTA: PublicKey[] = [];\n for (const item of allLTA) {\n if (lookupTableAddressAccount[item] === undefined) needCacheLTA.push(new PublicKey(item));\n }\n const newCacheLTA = await getMultipleLookupTableInfo({ connection: this.connection, address: needCacheLTA });\n for (const [key, value] of Object.entries(newCacheLTA)) lookupTableAddressAccount[key] = value;\n\n const messageV0 = new TransactionMessage({\n payerKey: this.feePayer,\n recentBlockhash: forerunCreate ? PublicKey.default.toBase58() : await getRecentBlockHash(this.connection),\n instructions: [...this.allInstructions],\n }).compileToV0Message(Object.values(lookupTableAddressAccount));\n const transaction = new VersionedTransaction(messageV0);\n transaction.sign(this.signers);\n\n return {\n builder: this,\n transaction,\n signers: this.signers,\n instructionTypes: [...this.instructionTypes, ...this.endInstructionTypes],\n execute: async () => {\n printSimulate([transaction]);\n if (this.owner?.isKeyPair) {\n transaction.sign([this.owner.signer as Signer]);\n return {\n txId: await this.connection.sendTransaction(transaction, { skipPreflight: true }),\n signedTx: transaction,\n };\n }\n if (this.signAllTransactions) {\n const txs = await this.signAllTransactions<VersionedTransaction>([transaction]);\n return {\n txId: await this.connection.sendTransaction(txs[0], { skipPreflight: true }),\n signedTx: txs[0],\n };\n }\n throw new Error(\"please connect wallet first\");\n },\n extInfo: (extInfo || {}) as O,\n };\n }\n\n public async buildV0MultiTx<T = Record<string, any>>(params: {\n extraPreBuildData?: MakeTxData<TxVersion.V0>[];\n buildProps?: T & {\n lookupTableCache?: CacheLTA;\n lookupTableAddress?: string[];\n };\n }): Promise<MultiTxV0BuildData> {\n const { extraPreBuildData = [], buildProps } = params;\n const { transaction } = await this.buildV0(buildProps);\n\n const filterExtraBuildData = extraPreBuildData.filter((data) => data.builder.instructions.length > 0);\n\n const allTransactions: VersionedTransaction[] = [\n transaction,\n ...filterExtraBuildData.map((data) => data.transaction),\n ];\n const allSigners: Signer[][] = [this.signers, ...filterExtraBuildData.map((data) => data.signers)];\n const allInstructionTypes: string[] = [\n ...this.instructionTypes,\n ...filterExtraBuildData.map((data) => data.instructionTypes).flat(),\n ];\n\n allTransactions.forEach(async (tx, idx) => {\n tx.sign(allSigners[idx]);\n });\n\n return {\n builder: this,\n transactions: allTransactions,\n signers: allSigners,\n instructionTypes: allInstructionTypes,\n buildProps,\n execute: async (executeParams?: ExecuteParam) => {\n printSimulate(allTransactions);\n const { sequentially, onTxUpdate } = executeParams || {};\n if (this.owner?.isKeyPair) {\n allTransactions.forEach((tx) => tx.sign([this.owner!.signer as Signer]));\n return {\n txIds: await Promise.all(\n allTransactions.map(async (tx) => {\n return await this.connection.sendTransaction(tx);\n }),\n ),\n signedTxs: allTransactions,\n };\n }\n\n if (this.signAllTransactions) {\n const signedTxs = await this.signAllTransactions(allTransactions);\n\n if (sequentially) {\n let i = 0;\n const processedTxs: { txId: string; status: \"success\" | \"error\" | \"sent\" }[] = [];\n const checkSendTx = async (): Promise<void> => {\n if (!signedTxs[i]) return;\n const txId = await this.connection.sendTransaction(signedTxs[i], { skipPreflight: true });\n processedTxs.push({ txId, status: \"sent\" });\n onTxUpdate?.([...processedTxs]);\n i++;\n this.connection.onSignature(\n txId,\n (signatureResult) => {\n const targetTxIdx = processedTxs.findIndex((tx) => tx.txId === txId);\n if (targetTxIdx > -1) processedTxs[targetTxIdx].status = signatureResult.err ? \"error\" : \"success\";\n onTxUpdate?.([...processedTxs]);\n checkSendTx();\n },\n \"processed\",\n );\n this.connection.getSignatureStatus(txId);\n };\n checkSendTx();\n return {\n txIds: [],\n signedTxs,\n };\n } else {\n const txIds: string[] = [];\n for (let i = 0; i < signedTxs.length; i += 1) {\n const txId = await this.connection.sendTransaction(signedTxs[i], { skipPreflight: true });\n txIds.push(txId);\n }\n return { txIds, signedTxs };\n }\n }\n throw new Error(\"please connect wallet first\");\n },\n extInfo: buildProps || {},\n };\n }\n\n public async sizeCheckBuild(\n props?: Record<string, any> & { autoComputeBudget?: boolean },\n ): Promise<MultiTxBuildData> {\n const { autoComputeBudget = false, ...extInfo } = props || {};\n\n let computeBudgetData: { instructions: TransactionInstruction[]; instructionTypes: string[] } = {\n instructions: [],\n instructionTypes: [],\n };\n\n if (autoComputeBudget) {\n const computeConfig = autoComputeBudget ? await this.getComputeBudgetConfig() : undefined;\n computeBudgetData =\n autoComputeBudget && computeConfig\n ? addComputeBudget(computeConfig)\n : { instructions: [], instructionTypes: [] };\n }\n\n const signerKey: { [key: string]: Signer } = this.signers.reduce(\n (acc, cur) => ({ ...acc, [cur.publicKey.toBase58()]: cur }),\n {},\n );\n\n const allTransactions: Transaction[] = [];\n const allSigners: Signer[][] = [];\n\n let instructionQueue: TransactionInstruction[] = [];\n this.allInstructions.forEach((item) => {\n const _itemIns = [...instructionQueue, item];\n const _itemInsWithCompute = autoComputeBudget ? [...computeBudgetData.instructions, ..._itemIns] : _itemIns;\n const _signerStrs = new Set<string>(\n _itemIns.map((i) => i.keys.filter((ii) => ii.isSigner).map((ii) => ii.pubkey.toString())).flat(),\n );\n const _signer = [..._signerStrs.values()].map((i) => new PublicKey(i));\n\n if (\n (instructionQueue.length < 12 &&\n checkLegacyTxSize({ instructions: _itemInsWithCompute, payer: this.feePayer, signers: _signer })) ||\n checkLegacyTxSize({ instructions: _itemIns, payer: this.feePayer, signers: _signer })\n ) {\n // current ins add to queue still not exceed tx size limit\n instructionQueue.push(item);\n } else {\n if (instructionQueue.length === 0) throw Error(\"item ins too big\");\n\n // if add computeBudget still not exceed tx size limit\n if (\n checkLegacyTxSize({\n instructions: autoComputeBudget\n ? [...computeBudgetData.instructions, ...instructionQueue]\n : [...instructionQueue],\n payer: this.feePayer,\n signers: _signer,\n })\n ) {\n allTransactions.push(new Transaction().add(...computeBudgetData.instructions, ...instructionQueue));\n } else {\n allTransactions.push(new Transaction().add(...instructionQueue));\n }\n allSigners.push(\n Array.from(\n new Set<string>(\n instructionQueue.map((i) => i.keys.filter((ii) => ii.isSigner).map((ii) => ii.pubkey.toString())).flat(),\n ),\n )\n .map((i) => signerKey[i])\n .filter((i) => i !== undefined),\n );\n instructionQueue = [item];\n }\n });\n\n if (instructionQueue.length > 0) {\n const _signerStrs = new Set<string>(\n instructionQueue.map((i) => i.keys.filter((ii) => ii.isSigner).map((ii) => ii.pubkey.toString())).flat(),\n );\n const _signers = [..._signerStrs.values()].map((i) => signerKey[i]).filter((i) => i !== undefined);\n\n if (\n checkLegacyTxSize({\n instructions: autoComputeBudget\n ? [...computeBudgetData.instructions, ...instructionQueue]\n : [...instructionQueue],\n payer: this.feePayer,\n signers: _signers.map((s) => s.publicKey),\n })\n ) {\n allTransactions.push(new Transaction().add(...computeBudgetData.instructions, ...instructionQueue));\n } else {\n allTransactions.push(new Transaction().add(...instructionQueue));\n }\n allSigners.push(_signers);\n }\n allTransactions.forEach((tx) => (tx.feePayer = this.feePayer));\n\n return {\n builder: this,\n transactions: allTransactions,\n signers: allSigners,\n instructionTypes: this.instructionTypes,\n execute: async (executeParams?: ExecuteParam) => {\n const { sequentially, onTxUpdate } = executeParams || {};\n const recentBlockHash = await getRecentBlockHash(this.connection);\n allTransactions.forEach(async (tx, idx) => {\n tx.recentBlockhash = recentBlockHash;\n if (allSigners[idx].length) tx.sign(...allSigners[idx]);\n });\n printSimulate(allTransactions);\n if (this.owner?.isKeyPair) {\n return {\n txIds: await Promise.all(\n allTransactions.map(async (tx, idx) => {\n return await sendAndConfirmTransaction(this.connection, tx, allSigners[idx]);\n }),\n ),\n signedTxs: allTransactions,\n };\n }\n if (this.signAllTransactions) {\n const signedTxs = await this.signAllTransactions(allTransactions);\n if (sequentially) {\n let i = 0;\n const processedTxs: { txId: string; status: \"success\" | \"error\" | \"sent\" }[] = [];\n const checkSendTx = async (): Promise<void> => {\n if (!signedTxs[i]) return;\n const txId = await this.connection.sendRawTransaction(signedTxs[i].serialize(), { skipPreflight: true });\n processedTxs.push({ txId, status: \"sent\" });\n onTxUpdate?.([...processedTxs]);\n i++;\n this.connection.onSignature(\n txId,\n (signatureResult) => {\n const targetTxIdx = processedTxs.findIndex((tx) => tx.txId === txId);\n if (targetTxIdx > -1) processedTxs[targetTxIdx].status = signatureResult.err ? \"error\" : \"success\";\n onTxUpdate?.([...processedTxs]);\n checkSendTx();\n },\n \"processed\",\n );\n this.connection.getSignatureStatus(txId);\n };\n await checkSendTx();\n return {\n txIds: processedTxs.map((d) => d.txId),\n signedTxs,\n };\n } else {\n const txIds: string[] = [];\n for (let i = 0; i < signedTxs.length; i += 1) {\n const txId = await this.connection.sendRawTransaction(signedTxs[i].serialize(), { skipPreflight: true });\n txIds.push(txId);\n }\n return { txIds, signedTxs };\n }\n }\n throw new Error(\"please connect wallet first\");\n },\n extInfo: extInfo || {},\n };\n }\n\n public async sizeCheckBuildV0(\n props?: Record<string, any> & {\n autoComputeBudget?: boolean;\n lookupTableCache?: CacheLTA;\n lookupTableAddress?: string[];\n },\n ): Promise<MultiTxV0BuildData> {\n const { autoComputeBudget = false, lookupTableCache = {}, lookupTableAddress = [], ...extInfo } = props || {};\n const lookupTableAddressAccount = {\n ...LOOKUP_TABLE_CACHE,\n ...lookupTableCache,\n };\n const allLTA = Array.from(new Set<string>([...this.lookupTableAddress, ...lookupTableAddress]));\n const needCacheLTA: PublicKey[] = [];\n for (const item of allLTA) {\n if (lookupTableAddressAccount[item] === undefined) needCacheLTA.push(new PublicKey(item));\n }\n const newCacheLTA = await getMultipleLookupTableInfo({ connection: this.connection, address: needCacheLTA });\n for (const [key, value] of Object.entries(newCacheLTA)) lookupTableAddressAccount[key] = value;\n\n let computeBudgetData: { instructions: TransactionInstruction[]; instructionTypes: string[] } = {\n instructions: [],\n instructionTypes: [],\n };\n\n if (autoComputeBudget) {\n const computeConfig = autoComputeBudget ? await this.getComputeBudgetConfig() : undefined;\n computeBudgetData =\n autoComputeBudget && computeConfig\n ? addComputeBudget(computeConfig)\n : { instructions: [], instructionTypes: [] };\n }\n\n const blockHash = await getRecentBlockHash(this.connection);\n\n const signerKey: { [key: string]: Signer } = this.signers.reduce(\n (acc, cur) => ({ ...acc, [cur.publicKey.toBase58()]: cur }),\n {},\n );\n\n const allTransactions: VersionedTransaction[] = [];\n const allSigners: Signer[][] = [];\n\n let instructionQueue: TransactionInstruction[] = [];\n this.allInstructions.forEach((item) => {\n const _itemIns = [...instructionQueue, item];\n const _itemInsWithCompute = autoComputeBudget ? [...computeBudgetData.instructions, ..._itemIns] : _itemIns;\n if (\n (instructionQueue.length < 12 &&\n checkV0TxSize({ instructions: _itemInsWithCompute, payer: this.feePayer, lookupTableAddressAccount })) ||\n checkV0TxSize({ instructions: _itemIns, payer: this.feePayer, lookupTableAddressAccount })\n ) {\n // current ins add to queue still not exceed tx size limit\n instructionQueue.push(item);\n } else {\n if (instructionQueue.length === 0) throw Error(\"item ins too big\");\n\n const lookupTableAddress: undefined | CacheLTA = {};\n for (const item of [...new Set<string>(allLTA)]) {\n if (lookupTableAddressAccount[item] !== undefined) lookupTableAddress[item] = lookupTableAddressAccount[item];\n }\n // if add computeBudget still not exceed tx size limit\n if (\n autoComputeBudget &&\n checkV0TxSize({\n instructions: [...computeBudgetData.instructions, ...instructionQueue],\n payer: this.feePayer,\n lookupTableAddressAccount,\n recentBlockhash: blockHash,\n })\n ) {\n const messageV0 = new TransactionMessage({\n payerKey: this.feePayer,\n recentBlockhash: blockHash,\n\n instructions: [...computeBudgetData.instructions, ...instructionQueue],\n }).compileToV0Message(Object.values(lookupTableAddressAccount));\n allTransactions.push(new VersionedTransaction(messageV0));\n } else {\n const messageV0 = new TransactionMessage({\n payerKey: this.feePayer,\n recentBlockhash: blockHash,\n instructions: [...instructionQueue],\n }).compileToV0Message(Object.values(lookupTableAddressAccount));\n allTransactions.push(new VersionedTransaction(messageV0));\n }\n allSigners.push(\n Array.from(\n new Set<string>(\n instructionQueue.map((i) => i.keys.filter((ii) => ii.isSigner).map((ii) => ii.pubkey.toString())).flat(),\n ),\n )\n .map((i) => signerKey[i])\n .filter((i) => i !== undefined),\n );\n instructionQueue = [item];\n }\n });\n\n if (instructionQueue.length > 0) {\n const _signerStrs = new Set<string>(\n instructionQueue.map((i) => i.keys.filter((ii) => ii.isSigner).map((ii) => ii.pubkey.toString())).flat(),\n );\n const _signers = [..._signerStrs.values()].map((i) => signerKey[i]).filter((i) => i !== undefined);\n\n if (\n autoComputeBudget &&\n checkV0TxSize({\n instructions: [...computeBudgetData.instructions, ...instructionQueue],\n payer: this.feePayer,\n lookupTableAddressAccount,\n recentBlockhash: blockHash,\n })\n ) {\n const messageV0 = new TransactionMessage({\n payerKey: this.feePayer,\n recentBlockhash: blockHash,\n instructions: [...computeBudgetData.instructions, ...instructionQueue],\n }).compileToV0Message(Object.values(lookupTableAddressAccount));\n allTransactions.push(new VersionedTransaction(messageV0));\n } else {\n const messageV0 = new TransactionMessage({\n payerKey: this.feePayer,\n recentBlockhash: blockHash,\n instructions: [...instructionQueue],\n }).compileToV0Message(Object.values(lookupTableAddressAccount));\n allTransactions.push(new VersionedTransaction(messageV0));\n }\n allSigners.push(_signers);\n }\n\n return {\n builder: this,\n transactions: allTransactions,\n buildProps: props,\n signers: allSigners,\n instructionTypes: this.instructionTypes,\n execute: async (executeParams?: ExecuteParam) => {\n const { sequentially, onTxUpdate } = executeParams || {};\n allTransactions.map(async (tx, idx) => {\n if (allSigners[idx].length) tx.sign(allSigners[idx]);\n });\n printSimulate(allTransactions);\n if (this.owner?.isKeyPair) {\n return {\n txIds: await Promise.all(\n allTransactions.map(async (tx) => {\n return await this.connection.sendTransaction(tx, { skipPreflight: true });\n }),\n ),\n signedTxs: allTransactions,\n };\n }\n if (this.signAllTransactions) {\n const signedTxs = await this.signAllTransactions(allTransactions);\n if (sequentially) {\n let i = 0;\n const processedTxs: { txId: string; status: \"success\" | \"error\" | \"sent\" }[] = [];\n const checkSendTx = async (): Promise<void> => {\n if (!signedTxs[i]) return;\n const txId = await this.connection.sendTransaction(signedTxs[i], { skipPreflight: true });\n processedTxs.push({ txId, status: \"sent\" });\n onTxUpdate?.([...processedTxs]);\n i++;\n this.connection.onSignature(\n txId,\n (signatureResult) => {\n const targetTxIdx = processedTxs.findIndex((tx) => tx.txId === txId);\n if (targetTxIdx > -1) processedTxs[targetTxIdx].status = signatureResult.err ? \"error\" : \"success\";\n onTxUpdate?.([...processedTxs]);\n checkSendTx();\n },\n \"processed\",\n );\n this.connection.getSignatureStatus(txId);\n };\n checkSendTx();\n return {\n txIds: [],\n signedTxs,\n };\n } else {\n const txIds: string[] = [];\n for (let i = 0; i < signedTxs.length; i += 1) {\n const txId = await this.connection.sendTransaction(signedTxs[i], { skipPreflight: true });\n txIds.push(txId);\n }\n return { txIds, signedTxs };\n }\n }\n throw new Error(\"please connect wallet first\");\n },\n extInfo: extInfo || {},\n };\n }\n}\n","export enum TxVersion {\n \"V0\",\n \"LEGACY\",\n}\n\nexport const InstructionType = {\n CreateAccount: \"CreateAccount\",\n InitAccount: \"InitAccount\",\n CreateATA: \"CreateATA\",\n CloseAccount: \"CloseAccount\",\n TransferAmount: \"TransferAmount\",\n InitMint: \"InitMint\",\n MintTo: \"MintTo\",\n\n InitMarket: \"InitMarket\", // create market main ins\n Util1216OwnerClaim: \"Util1216OwnerClaim\", // owner claim token ins\n\n SetComputeUnitPrice: \"SetComputeUnitPrice\",\n SetComputeUnitLimit: \"SetComputeUnitLimit\",\n\n // CLMM\n ClmmCreatePool: \"ClmmCreatePool\",\n ClmmOpenPosition: \"ClmmOpenPosition\",\n ClmmIncreasePosition: \"ClmmIncreasePosition\",\n ClmmDecreasePosition: \"ClmmDecreasePosition\",\n ClmmClosePosition: \"ClmmClosePosition\",\n ClmmSwapBaseIn: \"ClmmSwapBaseIn\",\n ClmmSwapBaseOut: \"ClmmSwapBaseOut\",\n ClmmInitReward: \"ClmmInitReward\",\n ClmmSetReward: \"ClmmSetReward\",\n ClmmCollectReward: \"ClmmCollectReward\",\n\n AmmV4Swap: \"AmmV4Swap\",\n AmmV4AddLiquidity: \"AmmV4AddLiquidity\",\n AmmV4RemoveLiquidity: \"AmmV4RemoveLiquidity\",\n AmmV4SimulatePoolInfo: \"AmmV4SimulatePoolInfo\",\n AmmV4SwapBaseIn: \"AmmV4SwapBaseIn\",\n AmmV4SwapBaseOut: \"AmmV4SwapBaseOut\",\n AmmV4CreatePool: \"AmmV4CreatePool\",\n AmmV4InitPool: \"AmmV4InitPool\",\n\n AmmV5AddLiquidity: \"AmmV5AddLiquidity\",\n AmmV5RemoveLiquidity: \"AmmV5RemoveLiquidity\",\n AmmV5SimulatePoolInfo: \"AmmV5SimulatePoolInfo\",\n AmmV5SwapBaseIn: \"AmmV5SwapBaseIn\",\n AmmV5SwapBaseOut: \"AmmV5SwapBaseOut\",\n\n RouteSwap: \"RouteSwap\",\n RouteSwap1: \"RouteSwap1\",\n RouteSwap2: \"RouteSwap2\",\n\n FarmV3Deposit: \"FarmV3Deposit\",\n FarmV3Withdraw: \"FarmV3Withdraw\",\n FarmV3CreateLedger: \"FarmV3CreateLedger\",\n\n FarmV5Deposit: \"FarmV5Deposit\",\n FarmV5Withdraw: \"FarmV5Withdraw\",\n FarmV5CreateLedger: \"FarmV5CreateLedger\",\n\n FarmV6Deposit: \"FarmV6Deposit\",\n FarmV6Withdraw: \"FarmV6Withdraw\",\n FarmV6Create: \"FarmV6Create\",\n FarmV6Restart: \"FarmV6Restart\",\n FarmV6CreatorAddReward: \"FarmV6CreatorAddReward\",\n FarmV6CreatorWithdraw: \"FarmV6CreatorWithdraw\",\n};\n","import {\n Connection,\n PublicKey,\n ComputeBudgetProgram,\n SimulatedTransactionResponse,\n Transaction,\n TransactionInstruction,\n TransactionMessage,\n Keypair,\n EpochInfo,\n VersionedTransaction,\n} from \"@solana/web3.js\";\nimport { TOKEN_PROGRAM_ID } from \"@solana/spl-token\";\n\nimport { createLogger } from \"../logger\";\nimport { InstructionType } from \"./txType\";\nimport { CacheLTA } from \"./lookupTable\";\n\nimport { ComputeBudgetConfig } from \"@/raydium/type\";\n\nconst logger = createLogger(\"Raydium_txUtil\");\n\nexport const MAX_BASE64_SIZE = 1644;\n\nexport function addComputeBudget(config: ComputeBudgetConfig): {\n instructions: TransactionInstruction[];\n instructionTypes: string[];\n} {\n const ins: TransactionInstruction[] = [];\n const insTypes: string[] = [];\n if (config.microLamports) {\n ins.push(ComputeBudgetProgram.setComputeUnitPrice({ microLamports: config.microLamports }));\n insTypes.push(InstructionType.SetComputeUnitPrice);\n }\n if (config.units) {\n ins.push(ComputeBudgetProgram.setComputeUnitLimit({ units: config.units }));\n insTypes.push(InstructionType.SetComputeUnitLimit);\n }\n\n return {\n instructions: ins,\n instructionTypes: insTypes,\n };\n}\n\nexport async function getRecentBlockHash(connection: Connection): Promise<string> {\n try {\n return (await connection.getLatestBlockhash?.())?.blockhash || (await connection.getRecentBlockhash()).blockhash;\n } catch {\n return (await connection.getRecentBlockhash()).blockhash;\n }\n}\n\n/**\n * Forecast transaction size\n */\nexport function forecastTransactionSize(instructions: TransactionInstruction[], signers: PublicKey[]): boolean {\n if (instructions.length < 1) logger.logWithError(`no instructions provided: ${instructions.toString()}`);\n if (signers.length < 1) logger.logWithError(`no signers provided:, ${signers.toString()}`);\n\n const transaction = new Transaction();\n transaction.recentBlockhash = \"11111111111111111111111111111111\";\n transaction.feePayer = signers[0];\n transaction.add(...instructions);\n\n try {\n return Buffer.from(transaction.serialize({ verifySignatures: false })).toString(\"base64\").length < MAX_BASE64_SIZE;\n } catch (error) {\n return false;\n }\n}\n\n/**\n * Simulates multiple instruction\n */\n/**\n * Simulates multiple instruction\n */\nexport async function simulateMultipleInstruction(\n connection: Connection,\n instructions: TransactionInstruction[],\n keyword: string,\n batchRequest = true,\n): Promise<string[]> {\n const feePayer = new PublicKey(\"RaydiumSimuLateTransaction11111111111111111\");\n\n const transactions: Transaction[] = [];\n\n let transaction = new Transaction();\n transaction.feePayer = feePayer;\n\n for (const instruction of instructions) {\n if (!forecastTransactionSize([...transaction.instructions, instruction], [feePayer])) {\n transactions.push(transaction);\n transaction = new Transaction();\n transaction.feePayer = feePayer;\n }\n transaction.add(instruction);\n }\n if (transaction.instructions.length > 0) {\n transactions.push(transaction);\n }\n\n let results: SimulatedTransactionResponse[] = [];\n\n try {\n results = await simulateTransaction(connection, transactions, batchRequest);\n if (results.find((i) => i.err !== null)) throw Error(\"rpc simulateTransaction error\");\n } catch (error) {\n if (error instanceof Error) {\n logger.logWithError(\"failed to simulate for instructions\", \"RPC_ERROR\", {\n message: error.message,\n });\n }\n }\n\n const logs: string[] = [];\n for (const result of results) {\n logger.debug(\"simulate result:\", result);\n\n if (result.logs) {\n const filteredLog = result.logs.filter((log) => log && log.includes(keyword));\n logger.debug(\"filteredLog:\", logs);\n if (!filteredLog.length) logger.logWithError(\"simulate log not match keyword\", \"keyword\", keyword);\n logs.push(...filteredLog);\n }\n }\n\n return logs;\n}\n\nexport function parseSimulateLogToJson(log: string, keyword: string): any {\n const results = log.match(/{[\"\\w:,]+}/g