From 485b0db1a2ad689018fef1b9584863c4b9a4b264 Mon Sep 17 00:00:00 2001 From: Kobe Date: Fri, 20 Dec 2024 10:20:37 +0100 Subject: [PATCH] fix: simulation errors & added debug logging --- .../src/components/common/Header/Header.tsx | 1 - .../hooks/use-trade-simulation.ts | 1 - .../trade-box-v2/utils/trade-action.utils.ts | 116 ++++++++++-------- .../utils/trade-simulation.utils.ts | 1 - .../src/store/tradeStoreV2.ts | 2 - .../src/models/account/wrapper.ts | 29 +++++ .../transaction/helpers/bundle-simulation.ts | 1 + .../src/actions/flashloans/builders.ts | 15 ++- .../src/actions/flashloans/helpers.ts | 1 + 9 files changed, 105 insertions(+), 62 deletions(-) diff --git a/apps/marginfi-v2-trading/src/components/common/Header/Header.tsx b/apps/marginfi-v2-trading/src/components/common/Header/Header.tsx index dbf3209322..af6b4d0019 100644 --- a/apps/marginfi-v2-trading/src/components/common/Header/Header.tsx +++ b/apps/marginfi-v2-trading/src/components/common/Header/Header.tsx @@ -64,7 +64,6 @@ export const Header = () => { const banks = Object.values(banksByBankPk); const uniqueBanksMap = new Map(banks.map((bank) => [bank.info.state.mint.toBase58(), bank])); const uniqueBanks = Array.from(uniqueBanksMap.values()); - console.log(uniqueBanksMap, uniqueBanks); return uniqueBanks; }, [banksByBankPk]); diff --git a/apps/marginfi-v2-trading/src/components/common/trade-box-v2/hooks/use-trade-simulation.ts b/apps/marginfi-v2-trading/src/components/common/trade-box-v2/hooks/use-trade-simulation.ts index 86876ee6a3..724da49d56 100644 --- a/apps/marginfi-v2-trading/src/components/common/trade-box-v2/hooks/use-trade-simulation.ts +++ b/apps/marginfi-v2-trading/src/components/common/trade-box-v2/hooks/use-trade-simulation.ts @@ -105,7 +105,6 @@ export function useTradeSimulation({ actionMessage: ActionMessageType | null; }> => { if (props.txns.length > 0) { - console.log("getting simulation result,"); const simulationResult = await getSimulationResult(props); console.log("simulationResult", simulationResult); diff --git a/apps/marginfi-v2-trading/src/components/common/trade-box-v2/utils/trade-action.utils.ts b/apps/marginfi-v2-trading/src/components/common/trade-box-v2/utils/trade-action.utils.ts index 012bc8e1c7..8c6f97f8f4 100644 --- a/apps/marginfi-v2-trading/src/components/common/trade-box-v2/utils/trade-action.utils.ts +++ b/apps/marginfi-v2-trading/src/components/common/trade-box-v2/utils/trade-action.utils.ts @@ -83,26 +83,30 @@ export const handleExecuteTradeAction = async ({ export async function generateTradeTx(props: CalculateLoopingProps): Promise { // USDC Swap tx + let swapTx: { quote?: QuoteResponse; tx?: SolanaTransaction; error?: ActionMessageType } | undefined; + const swapNeeded = props.depositBank.meta.tokenSymbol !== "USDC"; - let swapTx: { quote?: QuoteResponse; tx?: VersionedTransaction; error?: ActionMessageType } | undefined; if (swapNeeded) { console.log("Creating swap transaction..."); try { swapTx = await createSwapTx( props, { - slippageBps: props.slippageBps ?? 0, + slippageBps: props.slippageBps, }, props.marginfiClient.wallet.publicKey, props.marginfiClient.provider.connection ); - console.log("swapTx", swapTx); if (swapTx.error) { - console.error("Swap transaction error:", swapTx.error); + console.error("USDC swap transaction error:", swapTx.error); return swapTx.error; + } else { + if (!swapTx.tx || !swapTx.quote) { + return STATIC_SIMULATION_ERRORS.FL_FAILED; + } } } catch (error) { - console.error("Error creating swap transaction:", error); + console.error("Error creating USDC swap transaction:", error); return STATIC_SIMULATION_ERRORS.FL_FAILED; } } @@ -112,56 +116,33 @@ export async function generateTradeTx(props: CalculateLoopingProps): Promise 0, + hasAdditionalTxns: result.additionalTxns?.length > 0, + result, + }); return { ...result, additionalTxns: [...(swapTx?.tx ? [swapTx.tx] : []), ...accountCreationTx, ...(result.additionalTxns ?? [])], @@ -172,12 +153,49 @@ export async function generateTradeTx(props: CalculateLoopingProps): Promise { + // if no marginfi account, we need to create one + console.log("Creating new marginfi account transaction..."); + const authority = props.marginfiAccount?.authority ?? props.marginfiClient.provider.publicKey; + + const marginfiAccountKeypair = Keypair.generate(); + + const dummyWrappedI80F48 = bigNumberToWrappedI80F48(new BigNumber(0)); + + const dummyBalances: BalanceRaw[] = Array(15).fill({ + active: false, + bankPk: new PublicKey("11111111111111111111111111111111"), + assetShares: dummyWrappedI80F48, + liabilityShares: dummyWrappedI80F48, + emissionsOutstanding: dummyWrappedI80F48, + lastUpdate: new BN(0), + }); + + const rawAccount: MarginfiAccountRaw = { + group: props.marginfiClient.group.address, + authority: authority, + lendingAccount: { balances: dummyBalances }, + accountFlags: new BN([0, 0, 0]), + }; + + const account = new MarginfiAccount(marginfiAccountKeypair.publicKey, rawAccount); + + const wrappedAccount = new MarginfiAccountWrapper(marginfiAccountKeypair.publicKey, props.marginfiClient, account); + + return { + account: wrappedAccount, + tx: await props.marginfiClient.createMarginfiAccountTx({ accountKeypair: marginfiAccountKeypair }), + }; +} + export async function createSwapTx( props: CalculateLoopingProps, jupOpts: { slippageBps: number }, - feepayer: PublicKey, + authority: PublicKey, connection: Connection -): Promise<{ quote?: QuoteResponse; tx?: VersionedTransaction; error?: ActionMessageType }> { +): Promise<{ quote?: QuoteResponse; tx?: SolanaTransaction; error?: ActionMessageType }> { try { const jupiterQuoteApi = createJupiterApiClient(); @@ -202,7 +220,7 @@ export async function createSwapTx( } = await jupiterQuoteApi.swapInstructionsPost({ swapRequest: { quoteResponse: swapQuote, - userPublicKey: feepayer.toBase58(), + userPublicKey: authority.toBase58(), programAuthorityId: LUT_PROGRAM_AUTHORITY_INDEX, }, }); @@ -215,7 +233,7 @@ export async function createSwapTx( const finalBlockhash = (await connection.getLatestBlockhash()).blockhash; const swapMessage = new TransactionMessage({ - payerKey: feepayer, + payerKey: authority, recentBlockhash: finalBlockhash, instructions: [...cuInstructionsIxs, ...setupInstructionsIxs, swapIx], }); diff --git a/apps/marginfi-v2-trading/src/components/common/trade-box-v2/utils/trade-simulation.utils.ts b/apps/marginfi-v2-trading/src/components/common/trade-box-v2/utils/trade-simulation.utils.ts index 714c2acb2c..2d832159fa 100644 --- a/apps/marginfi-v2-trading/src/components/common/trade-box-v2/utils/trade-simulation.utils.ts +++ b/apps/marginfi-v2-trading/src/components/common/trade-box-v2/utils/trade-simulation.utils.ts @@ -23,7 +23,6 @@ export const getSimulationResult = async (props: SimulateActionProps) => { simulationResult = await simulateFlashLoan(props); } catch (error: any) { const actionString = "Looping"; - console.log("error", error); actionMethod = handleSimulationError(error, props.bank, false, actionString); } diff --git a/apps/marginfi-v2-trading/src/store/tradeStoreV2.ts b/apps/marginfi-v2-trading/src/store/tradeStoreV2.ts index bf6e4ea832..56845161bd 100644 --- a/apps/marginfi-v2-trading/src/store/tradeStoreV2.ts +++ b/apps/marginfi-v2-trading/src/store/tradeStoreV2.ts @@ -359,9 +359,7 @@ const stateCreator: StateCreator = (set, get) => ({ let positionsByGroupPk: Record = {}; if (wallet.publicKey && !wallet.publicKey.equals(PublicKey.default)) { - console.log("fetching user positions"); const userPositions = await fetchUserPositions(wallet.publicKey); - console.log("userPositions", userPositions); positionsByGroupPk = userPositions.reduce((acc, position) => { acc[position.groupPk.toBase58()] = position; return acc; diff --git a/packages/marginfi-client-v2/src/models/account/wrapper.ts b/packages/marginfi-client-v2/src/models/account/wrapper.ts index db4e5c88ba..e070e4b87b 100644 --- a/packages/marginfi-client-v2/src/models/account/wrapper.ts +++ b/packages/marginfi-client-v2/src/models/account/wrapper.ts @@ -688,6 +688,27 @@ class MarginfiAccountWrapper { const blockhash = blockhashArg ?? (await this._program.provider.connection.getLatestBlockhash("confirmed")).blockhash; + console.log("DEBUG: TRANSACTION DEBUG"); + + console.log("Setup Bank Addresses:", setupBankAddresses ?? [borrowBankAddress, depositBankAddress]); + + console.log("Borrow Arguments:", { + borrowAmount: borrowAmount.toString(), + borrowBankAddress: borrowBankAddress, + borrowOpts: { + createAtas: borrowOpts?.createAtas ?? false, + wrapAndUnwrapSol: borrowOpts?.wrapAndUnwrapSol ?? false, + }, + }); + + console.log("Deposit Arguments:", { + depositAmount: depositAmount, + depositBankAddress: depositBankAddress, + depositOpts: { + wrapAndUnwrapSol: depositOpts?.wrapAndUnwrapSol ?? false, + }, + }); + // creates atas if needed const setupIxs = await this.makeSetupIx(setupBankAddresses ?? [borrowBankAddress, depositBankAddress]); const cuRequestIxs = @@ -758,6 +779,14 @@ class MarginfiAccountWrapper { // if cuRequestIxs are not present, priority fee ix is needed // wallets add a priority fee ix by default breaking the flashloan tx so we need to add a placeholder priority fee ix // docs: https://docs.phantom.app/developer-powertools/solana-priority-fees + console.log("DEBUG: building flashloan tx"); + console.log("instructions:", [ + ...cuRequestIxs, + priorityFeeIx, + ...borrowIxs.instructions, + ...swapIxs, + ...depositIxs.instructions, + ]); flashloanTx = await this.buildFlashLoanTx({ ixs: [...cuRequestIxs, priorityFeeIx, ...borrowIxs.instructions, ...swapIxs, ...depositIxs.instructions], addressLookupTableAccounts, diff --git a/packages/marginfi-client-v2/src/services/transaction/helpers/bundle-simulation.ts b/packages/marginfi-client-v2/src/services/transaction/helpers/bundle-simulation.ts index 5e2d6fc60f..6b3aa0f0d0 100644 --- a/packages/marginfi-client-v2/src/services/transaction/helpers/bundle-simulation.ts +++ b/packages/marginfi-client-v2/src/services/transaction/helpers/bundle-simulation.ts @@ -160,6 +160,7 @@ async function executeBundleSimulation( } const jsonResponse = (await response.json()) as JsonRpcResponse; + console.log("response", jsonResponse); if ("error" in jsonResponse) { throw jsonResponse.error; diff --git a/packages/mrgn-utils/src/actions/flashloans/builders.ts b/packages/mrgn-utils/src/actions/flashloans/builders.ts index 125d6a63b7..ab7aa1bd16 100644 --- a/packages/mrgn-utils/src/actions/flashloans/builders.ts +++ b/packages/mrgn-utils/src/actions/flashloans/builders.ts @@ -207,7 +207,6 @@ export async function calculateLoopingParams({ return STATIC_SIMULATION_ERRORS.NOT_INITIALIZED; } - console.log("loopingProps", loopingProps); let borrowAmount: BigNumber, depositAmount: BigNumber, borrowAmountNative: number; if (loopingProps.marginfiAccount) { const params = getLoopingParamsForAccount( @@ -222,6 +221,7 @@ export async function calculateLoopingParams({ depositAmount = params.depositAmount; borrowAmountNative = params.borrowAmountNative; } else { + console.log("DEBUG: this code should not be accesed in the arena"); const params = getLoopingParamsForClient( marginfiClient, loopingProps.depositBank, @@ -235,17 +235,14 @@ export async function calculateLoopingParams({ depositAmount = params.depositAmount; borrowAmountNative = params.borrowAmountNative; } - // const principalBufferAmountUi = amount * targetLeverage * (slippageBps / 10000); - // const adjustedPrincipalAmountUi = amount - principalBufferAmountUi; - // const maxLoopAmount = depositBank.isActive ? depositBank?.position.amount : 0; - - // decreased maxAccounts from [undefined, 50, 40, 30] to [40, 30] const maxAccountsArr = [40, 30]; let firstQuote; for (const maxAccounts of maxAccountsArr) { + console.log(`%cDEBUG: calculating flashloan swap quote`, "color: blue; font-weight: bold; font-size: 14px;"); + console.log(`slippageBps: ${slippageBps}, platformFeeBps: ${platformFeeBps}, maxAccounts: ${maxAccounts}`); const quoteParams: QuoteGetRequest = { amount: borrowAmountNative, inputMint: loopingProps.borrowBank.info.state.mint.toBase58(), // borrow @@ -257,7 +254,6 @@ export async function calculateLoopingParams({ }; try { const swapQuote = await getSwapQuoteWithRetry(quoteParams); - console.log("swapQuote", swapQuote); if (!maxAccounts) { firstQuote = swapQuote; @@ -287,7 +283,6 @@ export async function calculateLoopingParams({ actualDepositAmount: actualDepositAmountUi, setupBankAddresses, }); - console.log("txn", txn); } if (txn.flashloanTx || !loopingProps.marginfiAccount) { return { @@ -362,6 +357,10 @@ export async function loopingBuilder({ feeAccountInfo = await connection.getAccountInfo(new PublicKey(feeAccount)); } + if (!feeAccountInfo) { + console.log("DEBUG: feeAccountInfo is undefined"); + } + const { swapInstruction, addressLookupTableAddresses } = await jupiterQuoteApi.swapInstructionsPost({ swapRequest: { quoteResponse: quote, diff --git a/packages/mrgn-utils/src/actions/flashloans/helpers.ts b/packages/mrgn-utils/src/actions/flashloans/helpers.ts index 58921d945d..d455348d57 100644 --- a/packages/mrgn-utils/src/actions/flashloans/helpers.ts +++ b/packages/mrgn-utils/src/actions/flashloans/helpers.ts @@ -33,6 +33,7 @@ export async function verifyTxSizeLooping(props: LoopingProps): Promise