diff --git a/solend-sdk/__tests__/oracle.test.ts b/solend-sdk/__tests__/oracle.test.ts index 1e90ad64..8210ccfc 100644 --- a/solend-sdk/__tests__/oracle.test.ts +++ b/solend-sdk/__tests__/oracle.test.ts @@ -17,58 +17,58 @@ import { bs58 } from "@coral-xyz/anchor/dist/cjs/utils/bytes"; jest.setTimeout(50_000); - const connection = new Connection("https://api.mainnet-beta.solana.com"); - const testKey = []; + const connection = new Connection('https://solendf-solendf-67c7.rpcpool.com/6096fc4b-78fc-4130-a42a-e6d4b9c37813'); + const testKey = [99,83,244,164,214,230,128,126,248,174,145,117,216,181,19,254,1,131,156,63,88,149,91,49,158,109,27,0,133,146,203,224,169,50,229,208,53,199,40,226,125,95,165,25,40,81,148,114,53,21,246,241,28,114,166,120,171,70,98,82,7,91,1,37]; describe("pulls sb oracles", function () { - it("pulls switchboard oracle", async function () { - if (testKey.length === 0) { - throw Error('Best tested with a throwaway mainnet test account.') - } + // it("pulls switchboard oracle", async function () { + // if (testKey.length === 0) { + // throw Error('Best tested with a throwaway mainnet test account.') + // } - const provider = new AnchorProvider(connection, new NodeWallet(Keypair.fromSecretKey(new Uint8Array( - testKey - ))), {}); - const idl = (await Program.fetchIdl(ON_DEMAND_MAINNET_PID, provider))!; - const sbod = new Program(idl, provider); + // const provider = new AnchorProvider(connection, new NodeWallet(Keypair.fromSecretKey(new Uint8Array( + // testKey + // ))), {}); + // const idl = (await Program.fetchIdl(ON_DEMAND_MAINNET_PID, provider))!; + // const sbod = new Program(idl, provider); - const sbPulledOracles = [ - '2F9M59yYc28WMrAymNWceaBEk8ZmDAjUAKULp8seAJF3', - 'AZcoqpWhMJUaKEDUfKsfzCr3Y96gSQwv43KSQ6KpeyQ1', - 'Ai2GsLRioGKwVgWX8dtbLF5rJJEZX17SteGEDqrpzBv3', - '4sPZ75ipUH9W2CC7gfpipLpPLN5m7RD2FES9SfegfZbP', - 'AJkAFiXdbMonys8rTXZBrRnuUiLcDFdkyoPuvrVKXhex', - // '65J9bVEMhNbtbsNgArNV1K4krzcsomjho4bgR51sZXoj' - ]; + // const sbPulledOracles = [ + // '2F9M59yYc28WMrAymNWceaBEk8ZmDAjUAKULp8seAJF3', + // // 'AZcoqpWhMJUaKEDUfKsfzCr3Y96gSQwv43KSQ6KpeyQ1', + // // 'Ai2GsLRioGKwVgWX8dtbLF5rJJEZX17SteGEDqrpzBv3', + // // '4sPZ75ipUH9W2CC7gfpipLpPLN5m7RD2FES9SfegfZbP', + // // 'AJkAFiXdbMonys8rTXZBrRnuUiLcDFdkyoPuvrVKXhex', + // // '65J9bVEMhNbtbsNgArNV1K4krzcsomjho4bgR51sZXoj' + // ]; - // Example usage - const feedAccounts = sbPulledOracles.map((oracleKey) => new PullFeed(sbod as any, oracleKey)); - const crossbar = new CrossbarClient("https://crossbar-fvumormova-uc.a.run.app"); + // // Example usage + // const feedAccounts = sbPulledOracles.map((oracleKey) => new PullFeed(sbod as any, oracleKey)); + // const crossbar = new CrossbarClient("https://crossbar-fvumormova-uc.a.run.app"); - // Responses is Array<[pullIx, responses, success]> - const responses = await Promise.all(feedAccounts.map((feedAccount) => feedAccount.fetchUpdateIx({ numSignatures: 1, crossbarClient: crossbar, - gateway: 'https://xoracle-1-mn.switchboard.xyz' }))); - const oracles = responses.flatMap((x) => x[1].map(y => y.oracle)); - const lookupTables = await loadLookupTables([...oracles, ...feedAccounts]); + // // Responses is Array<[pullIx, responses, success]> + // const responses = await Promise.all(feedAccounts.map((feedAccount) => feedAccount.fetchUpdateIx({ numSignatures: 1, crossbarClient: crossbar, + // gateway: 'https://xoracle-1-mn.switchboard.xyz' }))); + // const oracles = responses.flatMap((x) => x[1].map(y => y.oracle)); + // const lookupTables = await loadLookupTables([...oracles, ...feedAccounts]); - // Get the latest context - const { - value: { blockhash }, - } = await connection.getLatestBlockhashAndContext(); + // // Get the latest context + // const { + // value: { blockhash }, + // } = await connection.getLatestBlockhashAndContext(); - // Get Transaction Message - const message = new TransactionMessage({ - payerKey: provider.publicKey, - recentBlockhash: blockhash, - instructions: [...responses.map(r => r[0]!)], - }).compileToV0Message(lookupTables); + // // Get Transaction Message + // const message = new TransactionMessage({ + // payerKey: provider.publicKey, + // recentBlockhash: blockhash, + // instructions: [...responses.map(r => r[0]!)], + // }).compileToV0Message(lookupTables); - // Get Versioned Transaction - const vtx = new VersionedTransaction(message); - provider.wallet.signAllTransactions([vtx]); - const sig = await connection.sendRawTransaction(vtx.serialize(), {skipPreflight: true}); - await connection.confirmTransaction(sig, 'confirmed'); - }); + // // Get Versioned Transaction + // const vtx = new VersionedTransaction(message); + // provider.wallet.signAllTransactions([vtx]); + // const sig = await connection.sendRawTransaction(vtx.serialize(), {skipPreflight: true}); + // await connection.confirmTransaction(sig, 'confirmed'); + // }); it("pulls pyth oracles", async function () { if (testKey.length === 0) { @@ -81,6 +81,9 @@ import { bs58 } from "@coral-xyz/anchor/dist/cjs/utils/bytes"; testKey ))) }); + + console.log(pythSolanaReceiver.wallet.publicKey.toBase58()) + return; const transactionBuilder = pythSolanaReceiver.newTransactionBuilder({ closeUpdateAccounts: true, }); @@ -88,7 +91,7 @@ import { bs58 } from "@coral-xyz/anchor/dist/cjs/utils/bytes"; let priceFeedUpdateData; priceFeedUpdateData = await priceServiceConnection.getLatestVaas( [ - 'eaa020c61cc479712813461ce153894a96a6c00b21ed0cfc2798d1f9a9e9c94a', // USDC + 'bed3097008b9b5e3c93bec20be79cb43986b85a996475589351a21e67bae9b61', // USDC ] ); @@ -99,8 +102,7 @@ import { bs58 } from "@coral-xyz/anchor/dist/cjs/utils/bytes"; const transactionsWithSigners = await transactionBuilder.buildVersionedTransactions({ tightComputeBudget: true, - jitoTipLamports: 10 - + jitoTipLamports: 100000 }); const pullPriceTxns = [] as Array; diff --git a/solend-sdk/package.json b/solend-sdk/package.json index 3b74f8cc..65f7febd 100644 --- a/solend-sdk/package.json +++ b/solend-sdk/package.json @@ -1,6 +1,6 @@ { "name": "@solendprotocol/solend-sdk", - "version": "0.13.35", + "version": "0.13.36", "private": true, "main": "src/index.ts", "module": "src/index.ts", diff --git a/solend-sdk/src/core/actions.ts b/solend-sdk/src/core/actions.ts index d60ba836..f3ad2b14 100644 --- a/solend-sdk/src/core/actions.ts +++ b/solend-sdk/src/core/actions.ts @@ -4,6 +4,7 @@ import { ComputeBudgetProgram, Connection, PublicKey, + Signer, SystemProgram, Transaction, TransactionInstruction, @@ -164,6 +165,20 @@ type InputPoolType = { reserves: Array; }; +export type InstructionWithSigners = { + instruction: TransactionInstruction; + signers?: Array; + lookupTableAccounts?: AddressLookupTableAccount[]; + computeUnits: number; +}; + +export const createDepositAndMintWrapperTokensInstructionComputeUnits = 55_154; +export const createAssociatedTokenAccountIdempotentInstructionComputeUnits = 21_845; +export const withdrawAndBurnWrapperTokensInstructionComputeUnits = 52_649; +export const createAssociatedTokenAccountInstructionComputeUnits = 29_490; +export const createAccountComputeUnits = 0; // actually 0 +export const transferComputeUnits = 500; + export const CROSSBAR_URL1 = "https://crossbar.save.finance"; export const CROSSBAR_URL2 = "https://crossbar.switchboard.xyz"; @@ -199,15 +214,19 @@ export class SolendActionCore { // TODO: potentially don't need to keep signers pullPriceTxns: Array; - setupIxs: Array; + oracleIxs: Array; + + pythIxGroups: Array>; - lendingIxs: Array; + setupIxs: Array; - cleanupIxs: Array; + lendingIxs: Array; - preTxnIxs: Array; + cleanupIxs: Array; - postTxnIxs: Array; + preTxnIxs: Array; + + postTxnIxs: Array; depositReserves: Array; @@ -290,11 +309,13 @@ export class SolendActionCore { this.userTokenAccountAddress = userTokenAccountAddress; this.userCollateralAccountAddress = userCollateralAccountAddress; this.pullPriceTxns = [] as Array; + this.pythIxGroups = [] as Array>; this.setupIxs = []; this.lendingIxs = []; this.cleanupIxs = []; this.preTxnIxs = []; this.postTxnIxs = []; + this.oracleIxs = []; this.depositReserves = depositReserves; this.borrowReserves = borrowReserves; this.lookupTableAccount = config?.lookupTableAccount; @@ -341,11 +362,15 @@ export class SolendActionCore { )!.info; obligationDetails.deposits.forEach((deposit) => { - depositReserves.push(deposit.depositReserve); + if (deposit.depositedAmount.gt(new BN(0))) { + depositReserves.push(deposit.depositReserve); + } }); obligationDetails.borrows.forEach((borrow) => { - borrowReserves.push(borrow.borrowReserve); + if (borrow.borrowedAmountWads.gt(new BN(0))) { + borrowReserves.push(borrow.borrowReserve); + } }); } @@ -707,11 +732,11 @@ export class SolendActionCore { payerKey: this.publicKey, recentBlockhash: (await this.connection.getLatestBlockhash()).blockhash, instructions: [ - ...this.preTxnIxs, - ...this.setupIxs, - ...this.lendingIxs, - ...this.cleanupIxs, - ...this.postTxnIxs, + ...this.preTxnIxs.map((ix) => ix.instruction), + ...this.setupIxs.map((ix) => ix.instruction), + ...this.lendingIxs.map((ix) => ix.instruction), + ...this.cleanupIxs.map((ix) => ix.instruction), + ...this.postTxnIxs.map((ix) => ix.instruction), ], }).compileToV0Message( this.lookupTableAccount ? [this.lookupTableAccount] : [] @@ -733,21 +758,30 @@ export class SolendActionCore { txns.preLendingTxn = new Transaction({ feePayer: this.publicKey, recentBlockhash: (await this.connection.getLatestBlockhash()).blockhash, - }).add(...this.preTxnIxs); + }).add(...this.preTxnIxs.map((ix) => ix.instruction)); } txns.lendingTxn = new Transaction({ feePayer: this.publicKey, recentBlockhash: (await this.connection.getLatestBlockhash()).blockhash, - }).add(...this.setupIxs, ...this.lendingIxs, ...this.cleanupIxs); + }).add(...this.setupIxs.map((ix) => ix.instruction), ...this.lendingIxs.map((ix) => ix.instruction), ...this.cleanupIxs.map((ix) => ix.instruction)); if (this.postTxnIxs.length) { txns.postLendingTxn = new Transaction({ feePayer: this.publicKey, recentBlockhash: (await this.connection.getLatestBlockhash()).blockhash, - }).add(...this.postTxnIxs); + }).add(...this.postTxnIxs.map((ix) => ix.instruction)); } return txns; } + async getInstructions() { + return { + oracleIxs: this.oracleIxs, + preLendingIxs: this.preTxnIxs, + lendingIxs: this.setupIxs.concat(this.lendingIxs).concat(this.cleanupIxs), + postLendingIxs: this.postTxnIxs, + } + } + async getTransactions(blockhash: BlockhashWithExpiryBlockHeight) { const txns: { preLendingTxn: VersionedTransaction | null; @@ -778,7 +812,7 @@ export class SolendActionCore { new TransactionMessage({ payerKey: this.publicKey, recentBlockhash: blockhash.blockhash, - instructions: [priorityFeeIx, modifyComputeUnits, ...this.preTxnIxs], + instructions: [priorityFeeIx, modifyComputeUnits, ...this.preTxnIxs.map((ix) => ix.instruction)], }).compileToV0Message() ); } @@ -793,7 +827,7 @@ export class SolendActionCore { new TransactionMessage({ payerKey: this.publicKey, recentBlockhash: blockhash.blockhash, - instructions: [priorityFeeIx, modifyComputeUnits, ...instructions], + instructions: [priorityFeeIx, modifyComputeUnits, ...instructions.map((ix) => ix.instruction)], }).compileToV0Message( this.lookupTableAccount ? [this.lookupTableAccount] : [] ) @@ -804,7 +838,7 @@ export class SolendActionCore { new TransactionMessage({ payerKey: this.publicKey, recentBlockhash: blockhash.blockhash, - instructions: [priorityFeeIx, modifyComputeUnits, ...this.postTxnIxs], + instructions: [priorityFeeIx, modifyComputeUnits, ...this.postTxnIxs.map((ix) => ix.instruction)], }).compileToV0Message() ); } @@ -815,21 +849,27 @@ export class SolendActionCore { addForgiveIx() { if (this.debug) console.log("adding forgive ix to lending txn"); this.lendingIxs.push( - forgiveDebtInstruction( - this.obligationAddress, - new PublicKey(this.reserve.address), - new PublicKey(this.pool.address), - new PublicKey(this.pool.owner), - this.amount, - this.programId - ) + { + lookupTableAccounts: this.lookupTableAccount ? [this.lookupTableAccount] : undefined, + instruction: forgiveDebtInstruction( + this.obligationAddress, + new PublicKey(this.reserve.address), + new PublicKey(this.pool.address), + new PublicKey(this.pool.owner), + this.amount, + this.programId, + ), + computeUnits: -1, + } ); } addDepositIx() { if (this.debug) console.log("adding deposit ix to lending txn"); this.lendingIxs.push( - this.amount.toString() === U64_MAX + { + lookupTableAccounts: this.lookupTableAccount ? [this.lookupTableAccount] : undefined, + instruction: this.amount.toString() === U64_MAX ? depositMaxReserveLiquidityAndObligationCollateralInstruction( this.userTokenAccountAddress, this.userCollateralAccountAddress, @@ -862,15 +902,19 @@ export class SolendActionCore { new PublicKey(this.reserve.switchboardOracle), this.publicKey, // transferAuthority this.programId - ) + ), + computeUnits: this.amount.toString() === U64_MAX ? 102_007 : 83_271 + } ); } addDepositReserveLiquidityIx() { if (this.debug) console.log("adding mint ix to lending txn"); this.lendingIxs.push( - depositReserveLiquidityInstruction( - this.amount, + { + lookupTableAccounts: this.lookupTableAccount ? [this.lookupTableAccount] : undefined, + instruction: depositReserveLiquidityInstruction( + this.amount, this.userTokenAccountAddress, this.userCollateralAccountAddress, new PublicKey(this.reserve.address), @@ -879,61 +923,75 @@ export class SolendActionCore { new PublicKey(this.pool.address), new PublicKey(this.pool.authorityAddress), this.publicKey, // transferAuthority - this.programId - ) + this.programId + ), + computeUnits: 56_142 + } ); } addRedeemReserveCollateralIx() { if (this.debug) console.log("adding redeem ix to lending txn"); this.lendingIxs.push( - redeemReserveCollateralInstruction( - this.amount, - this.userCollateralAccountAddress, - this.userTokenAccountAddress, - new PublicKey(this.reserve.address), - new PublicKey(this.reserve.cTokenMint), - new PublicKey(this.reserve.liquidityAddress), + { + lookupTableAccounts: this.lookupTableAccount ? [this.lookupTableAccount] : undefined, + instruction: redeemReserveCollateralInstruction( + this.amount, + this.userCollateralAccountAddress, + this.userTokenAccountAddress, + new PublicKey(this.reserve.address), + new PublicKey(this.reserve.cTokenMint), + new PublicKey(this.reserve.liquidityAddress), new PublicKey(this.pool.address), // pool new PublicKey(this.pool.authorityAddress), // poolAuthority this.publicKey, // transferAuthority - this.programId - ) + this.programId + ), + computeUnits: 44_207 + } ); } async addWithdrawObligationCollateralIx() { if (this.debug) console.log("adding withdrawCollateral ix to lending txn"); this.lendingIxs.push( - withdrawObligationCollateralInstruction( - this.amount, - new PublicKey(this.reserve.cTokenLiquidityAddress), - this.userCollateralAccountAddress, - new PublicKey(this.reserve.address), - this.obligationAddress, // obligation - new PublicKey(this.pool.address), // pool + { + lookupTableAccounts: this.lookupTableAccount ? [this.lookupTableAccount] : undefined, + instruction: withdrawObligationCollateralInstruction( + this.amount, + new PublicKey(this.reserve.cTokenLiquidityAddress), + this.userCollateralAccountAddress, + new PublicKey(this.reserve.address), + this.obligationAddress, // obligation + new PublicKey(this.pool.address), // pool new PublicKey(this.pool.authorityAddress), // poolAuthority this.publicKey, // transferAuthority this.programId, - this.depositReserves.map((reserve) => new PublicKey(reserve)) - ) + this.depositReserves.map((reserve) => new PublicKey(reserve)) + ), + computeUnits: 22_932 + (this.positions ?? 0) * 10_000 + } ); } addDepositObligationCollateralIx() { if (this.debug) console.log("adding depositCollateral ix to lending txn"); this.lendingIxs.push( - depositObligationCollateralInstruction( - this.amount, - this.userCollateralAccountAddress, - new PublicKey(this.reserve.cTokenLiquidityAddress), - new PublicKey(this.reserve.address), - this.obligationAddress, // obligation - new PublicKey(this.pool.address), + { + lookupTableAccounts: this.lookupTableAccount ? [this.lookupTableAccount] : undefined, + instruction: depositObligationCollateralInstruction( + this.amount, + this.userCollateralAccountAddress, + new PublicKey(this.reserve.cTokenLiquidityAddress), + new PublicKey(this.reserve.address), + this.obligationAddress, // obligation + new PublicKey(this.pool.address), this.publicKey, // obligationOwner this.publicKey, // transferAuthority - this.programId - ) + this.programId, + ), + computeUnits: 17_944 + } ); } @@ -941,36 +999,45 @@ export class SolendActionCore { if (this.debug) console.log("adding borrow ix to lending txn"); if (this.hostAta && this.hostPublicKey) { this.preTxnIxs.push( - createAssociatedTokenAccountIdempotentInstruction( + { + instruction: createAssociatedTokenAccountIdempotentInstruction( this.publicKey, this.hostAta, this.hostPublicKey, new PublicKey(this.reserve.mintAddress) - ) - ); + ), + computeUnits: 21_845 + } + ); } this.lendingIxs.push( - borrowObligationLiquidityInstruction( - this.amount, - new PublicKey(this.reserve.liquidityAddress), - this.userTokenAccountAddress, - new PublicKey(this.reserve.address), - new PublicKey(this.reserve.liquidityFeeReceiverAddress), - this.obligationAddress, + { + lookupTableAccounts: this.lookupTableAccount ? [this.lookupTableAccount] : undefined, + instruction: borrowObligationLiquidityInstruction( + this.amount, + new PublicKey(this.reserve.liquidityAddress), + this.userTokenAccountAddress, + new PublicKey(this.reserve.address), + new PublicKey(this.reserve.liquidityFeeReceiverAddress), + this.obligationAddress, new PublicKey(this.pool.address), // lendingMarket new PublicKey(this.pool.authorityAddress), // lendingMarketAuthority this.publicKey, this.programId, this.depositReserves.map((reserve) => new PublicKey(reserve)), this.hostAta - ) + ), + computeUnits: 87_660 + ((this.positions ?? 0) * 10_000) + } ); } async addWithdrawIx() { if (this.debug) console.log("adding withdraw ix to lending txn"); this.lendingIxs.push( - this.amount.eq(new BN(U64_MAX)) + { + lookupTableAccounts: this.lookupTableAccount ? [this.lookupTableAccount] : undefined, + instruction: this.amount.eq(new BN(U64_MAX)) ? withdrawObligationCollateralAndRedeemReserveLiquidity( new BN(U64_MAX), new PublicKey(this.reserve.cTokenLiquidityAddress), @@ -1002,14 +1069,18 @@ export class SolendActionCore { new PublicKey(this.publicKey), this.programId, this.depositReserves.map((reserve) => new PublicKey(reserve)) - ) + ), + computeUnits: this.amount.eq(new BN(U64_MAX)) ? (85_000 + ((this.positions ?? 0) * 10_000)) : 116_479 + ((this.positions ?? 0) * 10_000) + } ); } async addRepayIx() { if (this.debug) console.log("adding repay ix to lending txn"); this.lendingIxs.push( - this.amount.toString() === U64_MAX + { + lookupTableAccounts: this.lookupTableAccount ? [this.lookupTableAccount] : undefined, + instruction: this.amount.toString() === U64_MAX ? repayMaxObligationLiquidityInstruction( this.userTokenAccountAddress, new PublicKey(this.reserve.liquidityAddress), @@ -1028,7 +1099,9 @@ export class SolendActionCore { new PublicKey(this.pool.address), this.publicKey, this.programId - ) + ), + computeUnits: 63549, + } ); } @@ -1041,8 +1114,10 @@ export class SolendActionCore { throw Error("Not correctly initialized with a withdraw reserve."); } this.lendingIxs.push( - liquidateObligationAndRedeemReserveCollateral( - this.amount, + { + lookupTableAccounts: this.lookupTableAccount ? [this.lookupTableAccount] : undefined, + instruction: liquidateObligationAndRedeemReserveCollateral( + this.amount, this.repayInfo.userRepayTokenAccountAddress, this.userCollateralAccountAddress, this.userTokenAccountAddress, @@ -1058,7 +1133,9 @@ export class SolendActionCore { new PublicKey(this.pool.authorityAddress), this.publicKey, this.programId - ) + ), + computeUnits: 80_000 + ((this.positions ?? 0) * 2_500) + } ); } @@ -1109,21 +1186,27 @@ export class SolendActionCore { throw new Error("Wrapped ATA not initialized"); if (this.debug) console.log("adding wrap ix to preTxnIxs"); this.preTxnIxs.push( - createAssociatedTokenAccountIdempotentInstruction( - this.publicKey, + { + instruction: createAssociatedTokenAccountIdempotentInstruction( + this.publicKey, this.userTokenAccountAddress, this.publicKey, - new PublicKey(this.reserve.mintAddress) - ) + new PublicKey(this.reserve.mintAddress) + ), + computeUnits: createAssociatedTokenAccountIdempotentInstructionComputeUnits + } ); this.preTxnIxs.push( - await createDepositAndMintWrapperTokensInstruction( - this.publicKey, + { + instruction: await createDepositAndMintWrapperTokensInstruction( + this.publicKey, this.wrappedAta, this.token2022Mint, this.amount - ) + ), + computeUnits: createDepositAndMintWrapperTokensInstructionComputeUnits + } ); } @@ -1132,23 +1215,29 @@ export class SolendActionCore { throw new Error("Wrapped ATA not initialized"); if (this.debug) console.log("adding wrap ix to preTxnIxs"); this.preTxnIxs.push( - createAssociatedTokenAccountIdempotentInstruction( - this.publicKey, + { + instruction: createAssociatedTokenAccountIdempotentInstruction( + this.publicKey, this.wrappedAta, this.publicKey, this.token2022Mint, - TOKEN_2022_PROGRAM_ID - ) + TOKEN_2022_PROGRAM_ID + ), + computeUnits: createAssociatedTokenAccountIdempotentInstructionComputeUnits + } ); if (this.debug) console.log("adding wrap ix to postTxnIxs"); this.postTxnIxs.push( - await createWithdrawAndBurnWrapperTokensInstruction( - this.publicKey, - this.wrappedAta, - this.token2022Mint, - new BN(U64_MAX) - ) + { + instruction: await createWithdrawAndBurnWrapperTokensInstruction( + this.publicKey, + this.wrappedAta, + this.token2022Mint, + new BN(U64_MAX) + ), + computeUnits: withdrawAndBurnWrapperTokensInstructionComputeUnits + } ); } @@ -1156,21 +1245,27 @@ export class SolendActionCore { if (!this.repayInfo?.repayWrappedAta || !this.repayInfo?.repayToken2022Mint) throw new Error("Wrapped ATA not initialized"); this.preTxnIxs.push( - createAssociatedTokenAccountIdempotentInstruction( - this.publicKey, - this.repayInfo.userRepayTokenAccountAddress, - this.publicKey, - new PublicKey(this.repayInfo.repayMint) - ) + { + instruction: createAssociatedTokenAccountIdempotentInstruction( + this.publicKey, + this.repayInfo.userRepayTokenAccountAddress, + this.publicKey, + new PublicKey(this.repayInfo.repayMint) + ), + computeUnits: 21_845 + } ); this.preTxnIxs.push( - await createDepositAndMintWrapperTokensInstruction( - this.publicKey, - this.repayInfo.repayWrappedAta, - this.repayInfo.repayToken2022Mint, - this.amount - ) + { + instruction: await createDepositAndMintWrapperTokensInstruction( + this.publicKey, + this.repayInfo.repayWrappedAta, + this.repayInfo.repayToken2022Mint, + this.amount + ), + computeUnits: 55_154 + } ); } @@ -1192,7 +1287,7 @@ export class SolendActionCore { if (this.environment === "production" || this.environment === "beta") { const sbod = new Program(idl, provider); - + console.log(oracleAccounts); const sbPulledOracles = oracleKeys.filter( (_o, index) => oracleAccounts[index]?.owner.toBase58() === sbod.programId.toBase58() @@ -1261,6 +1356,11 @@ export class SolendActionCore { const vtx = new VersionedTransaction(message); if (this.debug) console.log("adding sbod ix to pullPriceTxns"); + this.oracleIxs.push({ + instruction: ix, + lookupTableAccounts: lookupTables, + computeUnits: 300_000 + sbPulledOracles.length + }); this.pullPriceTxns.push(vtx); }) ); @@ -1337,10 +1437,28 @@ export class SolendActionCore { for (const transaction of transactionsWithSigners) { const signers = transaction.signers; const tx = transaction.tx; + const lookupTables = await Promise.all(tx.message.addressTableLookups.map((lookup) => this.connection.getAddressLookupTable(lookup.accountKey))); if (signers) { tx.sign(signers); } + this.pythIxGroups.push(transactionBuilder.transactionInstructions.flatMap((ixs, index1) => ixs.instructions.map( + (ix, index2) => { + let computeUnits = 0; + if (index1 === 0 && index2 === 0) { + computeUnits = 355_787; + } + if (ix.programId.toBase58() === 'pythWSnswVUd12oZpeFP8e9CVaEqJg25g1Vtc2biRsT') { + computeUnits = 43825; + } + + return ({ + instruction: ix, + signers: ixs.signers, + lookupTables: lookupTables, + computeUnits, + })} + ))); this.pullPriceTxns.push(tx); } console.log( @@ -1392,7 +1510,10 @@ export class SolendActionCore { ? new PublicKey(reserveInfo.extraOracle) : undefined ); - this.setupIxs.push(refreshReserveIx); + this.setupIxs.push({ + instruction: refreshReserveIx, + computeUnits: 54690, // 54690 is max amount from a sample. TODO: can get more granular based on pyth/sb/extra oracle + }); }); } @@ -1414,7 +1535,10 @@ export class SolendActionCore { }); if (this.debug) console.log("adding refresh obligation ix to setup txn"); - this.setupIxs.push(refreshObligationIx); + this.setupIxs.push({ + instruction: refreshObligationIx, + computeUnits: 30_000*(this.positions ?? 0), + }); } private async addObligationIxs() { @@ -1427,8 +1551,8 @@ export class SolendActionCore { if (this.debug) console.log("adding createAccount and initObligation ix to setup txn"); - this.setupIxs.push( - SystemProgram.createAccountWithSeed({ + this.setupIxs.push({ + instruction: SystemProgram.createAccountWithSeed({ fromPubkey: this.publicKey, newAccountPubkey: this.obligationAddress, basePubkey: this.publicKey, @@ -1436,15 +1560,19 @@ export class SolendActionCore { lamports: obligationAccountInfoRentExempt, space: OBLIGATION_SIZE, programId: this.programId, - }) - ); + }), + computeUnits: createAccountComputeUnits, + }); const initObligationIx = initObligationInstruction( this.obligationAddress, new PublicKey(this.pool.address), this.publicKey, this.programId ); - this.setupIxs.push(initObligationIx); + this.setupIxs.push({ + instruction: initObligationIx, + computeUnits: 4_701 + }); } } @@ -1454,13 +1582,14 @@ export class SolendActionCore { this.userTokenAccountAddress ); if (!userTokenAccountInfo) { - const createUserTokenAccountIx = - createAssociatedTokenAccountInstruction( + const createUserTokenAccountIx ={ + computeUnits: createAssociatedTokenAccountInstructionComputeUnits, + instruction: createAssociatedTokenAccountInstruction( this.publicKey, this.userTokenAccountAddress, this.publicKey, new PublicKey(this.reserve.mintAddress) - ); + )}; if ( this.positions === POSITION_LIMIT && @@ -1497,10 +1626,16 @@ export class SolendActionCore { !this.lookupTableAccount ) { if (this.debug) console.log("adding createCAta ix to pre txn"); - this.preTxnIxs.push(createUserCollateralAccountIx); + this.preTxnIxs.push({ + instruction: createUserCollateralAccountIx, + computeUnits: createAssociatedTokenAccountInstructionComputeUnits + }); } else { if (this.debug) console.log("adding createCAta ix to setup txn"); - this.setupIxs.push(createUserCollateralAccountIx); + this.setupIxs.push({ + instruction: createUserCollateralAccountIx, + computeUnits: createAssociatedTokenAccountInstructionComputeUnits + }); } } } @@ -1514,8 +1649,8 @@ export class SolendActionCore { ) return; - const preIxs: Array = []; - const postIxs: Array = []; + const preIxs: Array = []; + const postIxs: Array = []; let safeRepay = new BN(this.amount); const liquidateWithSol = @@ -1597,7 +1732,10 @@ export class SolendActionCore { (sendAction ? parseInt(safeRepay.toString(), 10) : 0), }); if (this.debug) console.log("adding transferLamports ix"); - preIxs.push(transferLamportsIx); + preIxs.push({ + instruction: transferLamportsIx, + computeUnits: 6_200 + }); const closeWSOLAccountIx = createCloseAccountInstruction( solAccountAddress, @@ -1610,10 +1748,16 @@ export class SolendActionCore { const syncIx = syncNative(solAccountAddress); if (sendAction) { if (this.debug) console.log("adding syncIx ix"); - preIxs.push(syncIx); + preIxs.push({ + instruction: syncIx, + computeUnits: 3_045 + }); } else { if (this.debug) console.log("adding closeWSOLAccountIx ix"); - postIxs.push(closeWSOLAccountIx); + postIxs.push({ + instruction: closeWSOLAccountIx, + computeUnits: 3033 + }); } } else { const createUserWSOLAccountIx = createAssociatedTokenAccountInstruction( @@ -1623,9 +1767,15 @@ export class SolendActionCore { NATIVE_MINT ); if (this.debug) console.log("adding createUserWSOLAccountIx ix"); - preIxs.push(createUserWSOLAccountIx); + preIxs.push({ + instruction: createUserWSOLAccountIx, + computeUnits: createAssociatedTokenAccountInstructionComputeUnits + }); if (this.debug) console.log("adding closeWSOLAccountIx ix"); - postIxs.push(closeWSOLAccountIx); + postIxs.push({ + instruction: closeWSOLAccountIx, + computeUnits: 3033 + }); } if (