@raydium-io/raydium-sdk-v2
Version:
An SDK for building applications on top of Raydium.
1 lines • 350 kB
Source Map (JSON)
{"version":3,"sources":["../../src/common/logger.ts","../../src/common/txTool/txTool.ts","../../src/common/txTool/lookupTable.ts","../../src/common/accountInfo.ts","../../src/common/bignumber.ts","../../node_modules/decimal.js/decimal.mjs","../../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/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/utility.ts","../../src/common/fee.ts","../../src/raydium/moduleBase.ts"],"sourcesContent":["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 {\n Commitment,\n Connection,\n PublicKey,\n sendAndConfirmTransaction,\n SignatureResult,\n Signer,\n SystemProgram,\n Transaction,\n TransactionInstruction,\n TransactionMessage,\n VersionedTransaction,\n} from \"@solana/web3.js\";\nimport axios from \"axios\";\n\nimport { Api } from \"../../api\";\nimport { ComputeBudgetConfig, SignAllTransactions, TxTipConfig } from \"../../raydium/type\";\nimport { Cluster } from \"../../solana\";\nimport { Owner } from \"../owner\";\nimport { CacheLTA, getDevLookupTableCache, getMainLookupTableCache, getMultipleLookupTableInfo } from \"./lookupTable\";\nimport { InstructionType, TxVersion } from \"./txType\";\nimport {\n addComputeBudget,\n checkLegacyTxSize,\n checkV0TxSize,\n confirmTransaction,\n getRecentBlockHash,\n printSimulate,\n} from \"./txUtils\";\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 ExecuteParams {\n skipPreflight?: boolean;\n recentBlockHash?: string;\n sendAndConfirm?: boolean;\n notSendToRpc?: boolean;\n}\n\ninterface TxBuilderInit {\n connection: Connection;\n feePayer: PublicKey;\n cluster: Cluster;\n owner?: Owner;\n blockhashCommitment?: Commitment;\n loopMultiTxStatus?: boolean;\n api?: Api;\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: (params?: ExecuteParams) => 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: (params?: ExecuteParams) => Promise<{ txId: string; signedTx: VersionedTransaction }>;\n}\n\ntype TxUpdateParams = {\n txId: string;\n status: \"success\" | \"error\" | \"sent\";\n signedTx: Transaction | VersionedTransaction;\n};\nexport interface MultiTxExecuteParam extends ExecuteParams {\n sequentially: boolean;\n skipTxCount?: number;\n onTxUpdate?: (completeTxs: TxUpdateParams[]) => void;\n}\nexport interface MultiTxBuildData<T = Record<string, any>> {\n builder: TxBuilder;\n transactions: Transaction[];\n instructionTypes: string[];\n signers: Signer[][];\n execute: (executeParams?: MultiTxExecuteParam) => 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?: MultiTxExecuteParam) => 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\nconst LOOP_INTERVAL = 2000;\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 cluster: Cluster;\n private signAllTransactions?: SignAllTransactions;\n private blockhashCommitment?: Commitment;\n private loopMultiTxStatus: boolean;\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 this.cluster = params.cluster;\n this.blockhashCommitment = params.blockhashCommitment;\n this.loopMultiTxStatus = !!params.loopMultiTxStatus;\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): boolean {\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 addTipInstruction(tipConfig?: TxTipConfig): boolean {\n if (tipConfig) {\n this.endInstructions.push(\n SystemProgram.transfer({\n fromPubkey: tipConfig.feePayer ?? this.feePayer,\n toPubkey: new PublicKey(tipConfig.address),\n lamports: BigInt(tipConfig.amount.toString()),\n }),\n );\n this.endInstructionTypes.push(InstructionType.TransferTip);\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 if (this.owner?.signer && !this.signers.some((s) => s.publicKey.equals(this.owner!.publicKey)))\n this.signers.push(this.owner.signer);\n\n return {\n builder: this,\n transaction,\n signers: this.signers,\n instructionTypes: [...this.instructionTypes, ...this.endInstructionTypes],\n execute: async (params) => {\n const { recentBlockHash: propBlockHash, skipPreflight = true, sendAndConfirm, notSendToRpc } = params || {};\n const recentBlockHash = propBlockHash ?? (await getRecentBlockHash(this.connection, this.blockhashCommitment));\n transaction.recentBlockhash = recentBlockHash;\n if (this.signers.length) transaction.sign(...this.signers);\n\n printSimulate([transaction]);\n if (this.owner?.isKeyPair) {\n const txId = sendAndConfirm\n ? await sendAndConfirmTransaction(\n this.connection,\n transaction,\n this.signers.find((s) => s.publicKey.equals(this.owner!.publicKey))\n ? this.signers\n : [...this.signers, this.owner.signer!],\n { skipPreflight },\n )\n : await this.connection.sendRawTransaction(transaction.serialize(), { skipPreflight });\n\n return {\n txId,\n signedTx: transaction,\n };\n }\n if (this.signAllTransactions) {\n const txs = await this.signAllTransactions([transaction]);\n if (this.signers.length) {\n for (const item of txs) {\n try {\n item.sign(...this.signers);\n } catch (e) {\n //\n }\n }\n }\n return {\n txId: notSendToRpc ? \"\" : await this.connection.sendRawTransaction(txs[0].serialize(), { skipPreflight }),\n signedTx: txs[0],\n };\n }\n throw new Error(\"please provide owner in keypair format or signAllTransactions function\");\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 if (this.owner?.signer) {\n allSigners.forEach((signers) => {\n if (!signers.some((s) => s.publicKey.equals(this.owner!.publicKey))) this.signers.push(this.owner!.signer!);\n });\n }\n\n return {\n builder: this,\n transactions: allTransactions,\n signers: allSigners,\n instructionTypes: allInstructionTypes,\n execute: async (executeParams?: MultiTxExecuteParam) => {\n const {\n sequentially,\n onTxUpdate,\n skipTxCount = 0,\n recentBlockHash: propBlockHash,\n skipPreflight = true,\n } = executeParams || {};\n const recentBlockHash = propBlockHash ?? (await getRecentBlockHash(this.connection, this.blockhashCommitment));\n if (this.owner?.isKeyPair) {\n if (sequentially) {\n const txIds: string[] = [];\n let i = 0;\n for (const tx of allTransactions) {\n ++i;\n if (i <= skipTxCount) continue;\n const txId = await sendAndConfirmTransaction(\n this.connection,\n tx,\n this.signers.find((s) => s.publicKey.equals(this.owner!.publicKey))\n ? this.signers\n : [...this.signers, this.owner.signer!],\n { skipPreflight },\n );\n txIds.push(txId);\n }\n\n return {\n txIds,\n signedTxs: allTransactions,\n };\n }\n return {\n txIds: await await Promise.all(\n allTransactions.map(async (tx) => {\n tx.recentBlockhash = recentBlockHash;\n return await this.connection.sendRawTransaction(tx.serialize(), { skipPreflight });\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: TxUpdateParams[] = [];\n const checkSendTx = async (): Promise<void> => {\n if (!signedTxs[i]) return;\n const txId = await this.connection.sendRawTransaction(signedTxs[i].serialize(), { skipPreflight });\n processedTxs.push({ txId, status: \"sent\", signedTx: signedTxs[i] });\n onTxUpdate?.([...processedTxs]);\n i++;\n let confirmed = false;\n // eslint-disable-next-line\n let intervalId: NodeJS.Timer | null = null,\n subSignatureId: number | null = null;\n const cbk = (signatureResult: SignatureResult): void => {\n intervalId !== null && clearInterval(intervalId);\n subSignatureId !== null && this.connection.removeSignatureListener(subSignatureId);\n const targetTxIdx = processedTxs.findIndex((tx) => tx.txId === txId);\n if (targetTxIdx > -1) {\n if (processedTxs[targetTxIdx].status === \"error\" || processedTxs[targetTxIdx].status === \"success\")\n return;\n processedTxs[targetTxIdx].status = signatureResult.err ? \"error\" : \"success\";\n }\n onTxUpdate?.([...processedTxs]);\n if (!signatureResult.err) checkSendTx();\n };\n\n if (this.loopMultiTxStatus)\n intervalId = setInterval(async () => {\n if (confirmed) {\n clearInterval(intervalId!);\n return;\n }\n try {\n const r = await this.connection.getTransaction(txId, {\n commitment: \"confirmed\",\n maxSupportedTransactionVersion: TxVersion.V0,\n });\n if (r) {\n confirmed = true;\n clearInterval(intervalId!);\n cbk({ err: r.meta?.err || null });\n console.log(\"tx status from getTransaction:\", txId);\n }\n } catch (e) {\n confirmed = true;\n clearInterval(intervalId!);\n console.error(\"getTransaction timeout:\", e, txId);\n }\n }, LOOP_INTERVAL);\n\n subSignatureId = this.connection.onSignature(\n txId,\n (result) => {\n if (confirmed) {\n this.connection.removeSignatureListener(subSignatureId!);\n return;\n }\n confirmed = true;\n cbk(result);\n },\n \"confirmed\",\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 });\n txIds.push(txId);\n }\n return {\n txIds,\n signedTxs,\n };\n }\n }\n throw new Error(\"please provide owner in keypair format or signAllTransactions function\");\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 recentBlockhash?: string;\n },\n ): Promise<MakeTxData<TxVersion.V0, O>> {\n const {\n lookupTableCache = {},\n lookupTableAddress = [],\n forerunCreate,\n recentBlockhash: propRecentBlockhash,\n ...extInfo\n } = props || {};\n\n const lookupTableAddressAccount = {\n ...(this.cluster === \"devnet\"\n ? await getDevLookupTableCache(this.connection)\n : await getMainLookupTableCache(this.connection)),\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 recentBlockhash = forerunCreate\n ? PublicKey.default.toBase58()\n : propRecentBlockhash ?? (await getRecentBlockHash(this.connection, this.blockhashCommitment));\n const messageV0 = new TransactionMessage({\n payerKey: this.feePayer,\n recentBlockhash,\n instructions: [...this.allInstructions],\n }).compileToV0Message(Object.values(lookupTableAddressAccount));\n if (this.owner?.signer && !this.signers.some((s) => s.publicKey.equals(this.owner!.publicKey)))\n this.signers.push(this.owner.signer);\n const transaction = new VersionedTransaction(messageV0);\n\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 (params) => {\n const { skipPreflight = true, sendAndConfirm, notSendToRpc } = params || {};\n printSimulate([transaction]);\n if (this.owner?.isKeyPair) {\n const txId = await this.connection.sendTransaction(transaction, { skipPreflight });\n if (sendAndConfirm) {\n await confirmTransaction(this.connection, txId);\n }\n\n return {\n txId,\n signedTx: transaction,\n };\n }\n if (this.signAllTransactions) {\n const txs = await this.signAllTransactions<VersionedTransaction>([transaction]);\n if (this.signers.length) {\n for (const item of txs) {\n try {\n item.sign(this.signers);\n } catch (e) {\n //\n }\n }\n }\n return {\n txId: notSendToRpc ? \"\" : await this.connection.sendTransaction(txs[0], { skipPreflight }),\n signedTx: txs[0],\n };\n }\n throw new Error(\"please provide owner in keypair format or signAllTransactions function\");\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 forerunCreate?: boolean;\n recentBlockhash?: 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 if (this.owner?.signer) {\n allSigners.forEach((signers) => {\n if (!signers.some((s) => s.publicKey.equals(this.owner!.publicKey))) this.signers.push(this.owner!.signer!);\n });\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?: MultiTxExecuteParam) => {\n const { sequentially, onTxUpdate, recentBlockHash: propBlockHash, skipPreflight = true } = executeParams || {};\n if (propBlockHash) allTransactions.forEach((tx) => (tx.message.recentBlockhash = propBlockHash));\n printSimulate(allTransactions);\n if (this.owner?.isKeyPair) {\n if (sequentially) {\n const txIds: string[] = [];\n for (const tx of allTransactions) {\n const txId = await this.connection.sendTransaction(tx, { skipPreflight });\n await confirmTransaction(this.connection, txId);\n txIds.push(txId);\n }\n\n return { txIds, signedTxs: allTransactions };\n }\n\n return {\n txIds: await Promise.all(\n allTransactions.map(async (tx) => {\n return await this.connection.sendTransaction(tx, { skipPreflight });\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: TxUpdateParams[] = [];\n const checkSendTx = async (): Promise<void> => {\n if (!signedTxs[i]) return;\n const txId = await this.connection.sendTransaction(signedTxs[i], { skipPreflight });\n processedTxs.push({ txId, status: \"sent\", signedTx: signedTxs[i] });\n onTxUpdate?.([...processedTxs]);\n i++;\n\n let confirmed = false;\n // eslint-disable-next-line\n let intervalId: NodeJS.Timer | null = null,\n subSignatureId: number | null = null;\n const cbk = (signatureResult: SignatureResult): void => {\n intervalId !== null && clearInterval(intervalId);\n subSignatureId !== null && this.connection.removeSignatureListener(subSignatureId);\n const targetTxIdx = processedTxs.findIndex((tx) => tx.txId === txId);\n if (targetTxIdx > -1) {\n if (processedTxs[targetTxIdx].status === \"error\" || processedTxs[targetTxIdx].status === \"success\")\n return;\n processedTxs[targetTxIdx].status = signatureResult.err ? \"error\" : \"success\";\n }\n onTxUpdate?.([...processedTxs]);\n if (!signatureResult.err) checkSendTx();\n };\n\n if (this.loopMultiTxStatus)\n intervalId = setInterval(async () => {\n if (confirmed) {\n clearInterval(intervalId!);\n return;\n }\n try {\n const r = await this.connection.getTransaction(txId, {\n commitment: \"confirmed\",\n maxSupportedTransactionVersion: TxVersion.V0,\n });\n if (r) {\n confirmed = true;\n clearInterval(intervalId!);\n cbk({ err: r.meta?.err || null });\n console.log(\"tx status from getTransaction:\", txId);\n }\n } catch (e) {\n confirmed = true;\n clearInterval(intervalId!);\n console.error(\"getTransaction timeout:\", e, txId);\n }\n }, LOOP_INTERVAL);\n\n subSignatureId = this.connection.onSignature(\n txId,\n (result) => {\n if (confirmed) {\n this.connection.removeSignatureListener(subSignatureId!);\n return;\n }\n confirmed = true;\n cbk(result);\n },\n \"confirmed\",\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 });\n txIds.push(txId);\n }\n return { txIds, signedTxs };\n }\n }\n throw new Error(\"please provide owner in keypair format or signAllTransactions function\");\n },\n extInfo: buildProps || {},\n };\n }\n\n public async sizeCheckBuild(\n props?: Record<string, any> & { computeBudgetConfig?: ComputeBudgetConfig; splitIns?: TransactionInstruction[] },\n ): Promise<MultiTxBuildData> {\n const { splitIns = [], computeBudgetConfig, ...extInfo } = props || {};\n const computeBudgetData: { instructions: TransactionInstruction[]; instructionTypes: string[] } =\n computeBudgetConfig\n ? addComputeBudget(computeBudgetConfig)\n : {\n instructions: [],\n 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 let splitInsIdx = 0;\n this.allInstructions.forEach((item) => {\n const _itemIns = [...instructionQueue, item];\n const _itemInsWithCompute = computeBudgetConfig ? [...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 item !== splitIns[splitInsIdx] &&\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 splitInsIdx += item === splitIns[splitInsIdx] ? 1 : 0;\n // if add computeBudget still not exceed tx size limit\n if (\n checkLegacyTxSize({\n instructions: computeBudgetConfig\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: computeBudgetConfig\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 if (this.owner?.signer) {\n allSigners.forEach((signers) => {\n if (!signers.some((s) => s.publicKey.equals(this.owner!.publicKey))) signers.push(this.owner!.signer!);\n });\n }\n\n return {\n builder: this,\n transactions: allTransactions,\n signers: allSigners,\n instructionTypes: this.instructionTypes,\n execute: async (executeParams?: MultiTxExecuteParam) => {\n const {\n sequentially,\n onTxUpdate,\n skipTxCount = 0,\n recentBlockHash: propBlockHash,\n skipPreflight = true,\n } = executeParams || {};\n const recentBlockHash = propBlockHash ?? (await getRecentBlockHash(this.connection, this.blockhashCommitment));\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 if (sequentially) {\n let i = 0;\n const txIds: string[] = [];\n for (const tx of allTransactions) {\n ++i;\n if (i <= skipTxCount) {\n txIds.push(\"tx skipped\");\n continue;\n }\n const txId = await sendAndConfirmTransaction(\n this.connection,\n tx,\n this.signers.find((s) => s.publicKey.equals(this.owner!.publicKey))\n ? this.signers\n : [...this.signers, this.owner.signer!],\n { skipPreflight },\n );\n txIds.push(txId);\n }\n\n return {\n txIds,\n signedTxs: allTransactions,\n };\n }\n return {\n txIds: await Promise.all(\n allTransactions.map(async (tx) => {\n return await this.connection.sendRawTransaction(tx.serialize(), { skipPreflight });\n }),\n ),\n signedTxs: allTransactions,\n };\n }\n if (this.signAllTransactions) {\n const needSignedTx = await this.signAllTransactions(\n allTransactions.slice(skipTxCount, allTransactions.length),\n );\n const signedTxs = [...allTransactions.slice(0, skipTxCount), ...needSignedTx];\n if (sequentially) {\n let i = 0;\n const processedTxs: TxUpdateParams[] = [];\n const checkSendTx = async (): Promise<void> => {\n if (!signedTxs[i]) return;\n if (i < skipTxCount) {\n // success before, do not send again\n processedTxs.push({ txId: \"\", status: \"success\", signedTx: signedTxs[i] });\n onTxUpdate?.([...processedTxs]);\n i++;\n checkSendTx();\n }\n const txId = await this.connection.sendRawTransaction(signedTxs[i].serialize(), { skipPreflight });\n processedTxs.push({ txId, status: \"sent\", signedTx: signedTxs[i] });\n onTxUpdate?.([...processedTxs]);\n i++;\n\n let confirmed = false;\n // eslint-disable-next-line\n let intervalId: NodeJS.Timer | null = null,\n subSignatureId: number | null = null;\n const cbk = (signatureResult: SignatureResult): void => {\n intervalId !== null && clearInterval(intervalId);\n subSignatureId !== null && this.connection.removeSignatureListener(subSignatureId);\n const targetTxIdx = processedTxs.findIndex((tx) => tx.txId === txId);\n if (targetTxIdx > -1) {\n if (processedTxs[targetTxIdx].status === \"error\" || processedTxs[targetTxIdx].status === \"success\")\n return;\n processedTxs[targetTxIdx].status = signatureResult.err ? \"error\" : \"success\";\n }\n onTxUpdate?.([...processedTxs]);\n if (!signatureResult.err) checkSendTx();\n };\n\n if (this.loopMultiTxStatus)\n intervalId = setInterval(async () => {\n if (confirmed) {\n clearInterval(intervalId!);\n return;\n }\n try {\n const r = await this.connection.getTransaction(txId, {\n commitment: \"confirmed\",\n maxSupportedTransactionVersion: TxVersion.V0,\n });\n if (r) {\n confirmed = true;\n clearInterval(intervalId!);\n cbk({ err: r.meta?.err || null });\n console.log(\"tx status from getTransaction:\", txId);\n }\n } catch (e) {\n confirmed = true;\n clearInterval(intervalId!);\n console.error(\"getTransaction timeout:\", e, txId);\n }\n }, LOOP_INTERVAL);\n\n subSignatureId = this.connection.onSignature(\n txId,\n (result) => {\n if (confirmed) {\n this.connection.removeSignatureListener(subSignatureId!);\n return;\n }\n confirmed = true;\n cbk(result);\n },\n \"confirmed\",\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 });\n txIds.push(txId);\n }\n return { txIds, signedTxs };\n }\n }\n throw new Error(\"please provide owner in keypair format or signAllTransactions function\");\n },\n extInfo: extInfo || {},\n };\n }\n\n public async sizeCheckBuildV0(\n props?: Record<string, any> & {\n computeBudgetConfig?: ComputeBudgetConfig;\n lookupTableCache?: CacheLTA;\n lookupTableAddress?: string[];\n splitIns?: TransactionInstruction[];\n },\n ): Promise<MultiTxV0BuildData> {\n const {\n computeBudgetConfig,\n splitIns = [],\n lookupTableCache = {},\n lookupTableAddress = [],\n ...extInfo\n } = props || {};\n const lookupTableAddressAccount = {\n ...(this.cluster === \"devnet\"\n ? await getDevLookupTableCache(this.connection)\n : await getMainLookupTableCache(this.connection)),\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 const computeBudgetData: { instructions: TransactionInstruction[]; instructionTypes: string[] } =\n computeBudgetConfig\n ? addComputeBudget(computeBudgetConfig)\n : {\n instructions: [],\n instructionTypes: [],\n };\n\n const blockHash = await getRecentBlockHash(this.connection, this.blockhashCommitment);\n\n const signerKey: { [key: string]: Signer } = this.signers.reduce(\n (acc, cur) => ({ ...acc, [cur.publicKey.toBase58()]: cur }),\n {},\n );\n const allTransactions: VersionedTransaction[] = [];\n const allSigners: Signer[][] = [];\n\n let instructionQueue: TransactionInstruction[] = [];\n let splitInsIdx = 0;\n this.allInstructions.forEach((item) => {\n const _itemIns = [...instructionQueue, item];\n const _itemInsWithCompute = computeBudgetConfig ? [...computeBudgetData.instructions, ..._itemIns] : _itemIns;\n if (\n item !== splitIns[splitInsIdx] &&\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 splitInsIdx += item === splitIns[splitInsIdx] ? 1 : 0;\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 computeBudgetConfig &&\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 computeBudgetConfig &&\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\n allSigners.push(_signers);\n }\n\n if (this.owner?.signer) {\n allSigners.forEach((signers) => {\n if (!signers.some((s) => s.publicKey.equals(this.owner!.publicKey))) signers.push(this.owner!.signer!);\n });\n }\n\n allTransactions.forEach((tx, idx) => {\n tx.sign(allSigners[idx]);\n });\n\n return {\n builder: this,\n transactions: allTransactions,\n buildProps: props,\n signers: allSigners,\n instructionTypes: this.instructionTypes,\n execute: async (executeParams?: MultiTxExecuteParam) => {\n const {\n sequentially,\n onTxUpdate,\n skipTxCount = 0,\n recentBlockHash: propBlockHash,\n skipPreflight = true,\n } = executeParams || {};\n allTransactions.map(async (tx, idx) => {\n if (allSigners[idx].length) tx.sign(allSigners[idx]);\n if (propBlockHash) tx.message.recentBlockhash = propBlockHash;\n });\n printSimulate(allTransactions);\n if (this.owner?.isKeyPair) {\n if (sequentially) {\n let i = 0;\n const txIds: string[] = [];\n for (const tx of allTransactions) {\n ++i;\n if (i <= skipTxCount) {\n console.log(\"skip tx: \", i);\n txIds.push(\"tx skipped\");\n continue;\n }\n const txId = await this.connection.sendTransaction(tx, { skipPreflight });\n await confirmTransaction(this.connection, txId);\n\n txIds.push(txId);\n }\n\n return { txIds, signedTxs: allTransactions };\n }\n\n return {\n txIds: await Promise.all(\n allTransactions.map(async (tx) => {\n return await this.connection.sendTransaction(tx, { skipPreflight });\n }),\n ),\n signedTxs: allTransactions,\n };\n }\n if (this.signAllTransactions) {\n const needSignedTx = await this.signAllTransactions(\n allTransactions.slice(skipTxCount, allTransactions.length),\n );\n const signedTxs = [...allTransactions.slice(0, skipTxCount), ...needSignedTx];\n if (sequentially) {\n let i = 0;\n const processedTxs: TxUpdateParams[] = [];\n const checkSendTx = async (): Promise<void> => {\n if (!signedTxs[i]) return;\n if (i < skipTxCount) {\n // success before, do not send again\n processedTxs.push({ txId: \"\", status: \"success\", signedTx: signedTxs[i] });\n onTxUpdate?.([...processedTxs]);\n i++;\n checkSendTx();\n return;\n }\n const txId = await this.connection.sendTransaction(signedTxs[i], { skipPreflight });\n processedTxs.push({ txId, status: \"sent\", signedTx: signedTxs[i] });\n onTxUpdate?.([...processedTxs]);\n i++;\n\n let confirmed = false;\n // eslint-disable-next-line\n let intervalId: NodeJS.Timer | null = null,\n subSignatureId: number | null = null;\n const cbk = (signatureResult: SignatureResult): void => {\n intervalId !== null && clearInterval(intervalId);\n subSignatureId !== null && this.connection.removeSignatureList