Skip to content

Commit

Permalink
fix: simulation errors & added debug logging
Browse files Browse the repository at this point in the history
  • Loading branch information
k0beLeenders committed Dec 20, 2024
1 parent 54bb404 commit 485b0db
Show file tree
Hide file tree
Showing 9 changed files with 105 additions and 62 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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]);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,26 +83,30 @@ export const handleExecuteTradeAction = async ({

export async function generateTradeTx(props: CalculateLoopingProps): Promise<TradeActionTxns | ActionMessageType> {
// 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;
}
}
Expand All @@ -112,56 +116,33 @@ export async function generateTradeTx(props: CalculateLoopingProps): Promise<Tra
let accountCreationTx: SolanaTransaction[] = [];
let finalAccount: MarginfiAccountWrapper | null = props.marginfiAccount;
if (!hasMarginfiAccount) {
// 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);

finalAccount = wrappedAccount;
const { account, tx } = await createMarginfiAccountTx(props);
finalAccount = account;
accountCreationTx.push(tx);
}

accountCreationTx.push(
await props.marginfiClient.createMarginfiAccountTx({ accountKeypair: marginfiAccountKeypair })
);
let finalDepositAmount = props.depositAmount;

console.log("accountCreationTx", accountCreationTx);
if (swapNeeded && !swapTx?.quote) {
return STATIC_SIMULATION_ERRORS.FL_FAILED;
} else if (swapNeeded && swapTx?.quote) {
finalDepositAmount = Number(nativeToUi(swapTx?.quote?.outAmount, props.depositBank.info.state.mintDecimals));
}

const result = await calculateLoopingParams({
...props,
setupBankAddresses: [props.borrowBank.info.state.mint],
setupBankAddresses: [props.borrowBank.address],
marginfiAccount: finalAccount,
depositAmount:
swapNeeded && swapTx?.quote?.outAmount
? Number(nativeToUi(swapTx?.quote?.outAmount, props.depositBank.info.state.mintDecimals))
: props.depositAmount,
depositAmount: finalDepositAmount,
});

console.log("result", result);

if (result && "actionQuote" in result) {
console.log("DEBUG: result", {
hasSwapTx: !!swapTx?.tx,
hasAccountCreationTx: accountCreationTx.length > 0,
hasAdditionalTxns: result.additionalTxns?.length > 0,
result,
});
return {
...result,
additionalTxns: [...(swapTx?.tx ? [swapTx.tx] : []), ...accountCreationTx, ...(result.additionalTxns ?? [])],
Expand All @@ -172,12 +153,49 @@ export async function generateTradeTx(props: CalculateLoopingProps): Promise<Tra
return result;
}

async function createMarginfiAccountTx(
props: CalculateLoopingProps
): Promise<{ account: MarginfiAccountWrapper; tx: SolanaTransaction }> {
// 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();

Expand All @@ -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,
},
});
Expand All @@ -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],
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
2 changes: 0 additions & 2 deletions apps/marginfi-v2-trading/src/store/tradeStoreV2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -359,9 +359,7 @@ const stateCreator: StateCreator<TradeStoreV2State, [], []> = (set, get) => ({
let positionsByGroupPk: Record<string, ArenaPoolPositions> = {};

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;
Expand Down
29 changes: 29 additions & 0 deletions packages/marginfi-client-v2/src/models/account/wrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ async function executeBundleSimulation(
}

const jsonResponse = (await response.json()) as JsonRpcResponse<RpcSimulateBundleResult>;
console.log("response", jsonResponse);

if ("error" in jsonResponse) {
throw jsonResponse.error;
Expand Down
15 changes: 7 additions & 8 deletions packages/mrgn-utils/src/actions/flashloans/builders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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,
Expand All @@ -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
Expand All @@ -257,7 +254,6 @@ export async function calculateLoopingParams({
};
try {
const swapQuote = await getSwapQuoteWithRetry(quoteParams);
console.log("swapQuote", swapQuote);

if (!maxAccounts) {
firstQuote = swapQuote;
Expand Down Expand Up @@ -287,7 +283,6 @@ export async function calculateLoopingParams({
actualDepositAmount: actualDepositAmountUi,
setupBankAddresses,
});
console.log("txn", txn);
}
if (txn.flashloanTx || !loopingProps.marginfiAccount) {
return {
Expand Down Expand Up @@ -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,
Expand Down
1 change: 1 addition & 0 deletions packages/mrgn-utils/src/actions/flashloans/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export async function verifyTxSizeLooping(props: LoopingProps): Promise<VerifyTx
const builder = await loopingBuilder(props);

if (builder.txOverflown) {
console.log("DEBUG: transaction size is too large");
return {
flashloanTx: null,
additionalTxs: [],
Expand Down

0 comments on commit 485b0db

Please sign in to comment.