import { Keypair, PublicKey, Signer, Transaction, TransactionInstruction, } from "@solana/web3.js"; import BN from "bn.js"; import { Action, ActionLib, ActionOptions, ActionType, ActionTypeStr, BuildIsolatedActionFn, BuildIsolatedActionParams, EstimateOutFN, IsolatedAction, } from "../index"; import { actionMetasToAccountsArray } from "./object"; const truncateData = (data: Buffer, actionType: ActionTypeStr): Buffer => { if (actionType === "fungibleToken") { const arr = new Uint8Array([...data]); // Remove the last 8 bytes const newArr = arr.slice(0, data.length - 8); return Buffer.from(newArr); } else if (actionType === "normalCpi") { return data; } else { throw `Expected an action type to be specified`; } }; interface InstrToActionLibOpts extends ActionOptions { tokenMintsOut?: PublicKey[]; estimateOuts?: EstimateOutFN; } /** * Given a function which builds a transaction, create an action lib * * @param instBuilder - build the instructions. This assumes that the main instruction * is the last one given. */ export const instructionToActionLib = ( instBuilder: (args: BuildIsolatedActionParams) => Promise<{ insts: TransactionInstruction[]; additionalSigners?: Signer[]; mintOuts?: PublicKey[]; estimateOuts?: EstimateOutFN; }>, actionTypeUID: string, actionType: ActionTypeStr, opts?: InstrToActionLibOpts ): ActionLib => { if (actionType === "multiFungibleTokens") { throw "Auto building an instruction for multi fungible tokens is not allowed"; } const expectedNumberOutMints = opts?.tokenMintsOut?.length ?? 1; const buildIsolatedAction: BuildIsolatedActionFn = async ( params ) => { const { insts, additionalSigners, mintOuts: tokMintsOut, estimateOuts, } = await instBuilder(params); const mainActionInst = insts.pop(); const data = truncateData(mainActionInst.data, actionType); const actionTypeObj = {}; actionTypeObj[actionType] = {}; return { isolatedAction: { actionAccounts: actionMetasToAccountsArray(mainActionInst.keys), actionData: data, actionProgram: mainActionInst.programId, tokenMintOuts: opts?.tokenMintsOut ?? tokMintsOut ?? Array(expectedNumberOutMints).fill(PublicKey.default), opts: { ...(opts || {}), instructions: [...(opts?.instructions || []), ...insts], additionalSigners: [ ...(opts?.additionalSigners || []), ...(additionalSigners || []), ], actionType: actionTypeObj, }, }, // return no estimate outs unless specified estimateOuts: opts?.estimateOuts ?? estimateOuts ?? (((_amountIn) => Array(expectedNumberOutMints).fill({ mint: PublicKey.default, amount: new BN(0), })) as EstimateOutFN), }; }; return { actionTypeUID, expectedNumberOutMints, buildIsolatedAction, }; };