Last active
January 6, 2025 11:56
-
-
Save staccDOTsol/8b0ee614a87a0819539240692fb3cdc7 to your computer and use it in GitHub Desktop.
pissed off
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { | |
| AddressLookupTableAccount, | |
| Connection, | |
| Keypair, | |
| PublicKey, | |
| TransactionInstruction, | |
| } from "@solana/web3.js"; | |
| import { getMarginfiClient } from "./utils"; | |
| import { createJupiterApiClient } from "@jup-ag/api"; | |
| import { nativeToUi } from "@mrgnlabs/mrgn-common"; | |
| import { Wallet } from "@coral-xyz/anchor"; | |
| import { bs58 } from "@coral-xyz/anchor/dist/cjs/utils/bytes"; | |
| import { BN } from "bn.js"; | |
| import { SystemProgram } from "@solana/web3.js"; | |
| import { ComputeBudgetProgram } from "@solana/web3.js"; | |
| const wallet = new Wallet(Keypair.fromSecretKey(new Uint8Array(bs58.decode(process.env.PRIVATE_KEY!)))); | |
| async function main() { | |
| const client = await getMarginfiClient({ wallet: wallet }); | |
| console.log("signer:", client.wallet.publicKey.toBase58()); | |
| const jupiterQuoteApi = createJupiterApiClient(); | |
| const marginfiAccounts = await client.getMarginfiAccountsForAuthority(); | |
| if (marginfiAccounts.length === 0) throw Error("No marginfi account found"); | |
| const marginfiAccount = marginfiAccounts[0]; | |
| // Assumption: account has enough USDC to repay the whole USDT borrow, accounting for slippage | |
| const usdcBank = client.getBankByTokenSymbol("USDC"); | |
| if (!usdcBank) throw Error("USDC bank not found"); | |
| const usdtBank = client.getBankByTokenSymbol("USDT"); | |
| if (!usdtBank) throw Error("USDT bank not found"); | |
| while (true) { | |
| const usdtAmountToRepay = new BN(Math.floor((Math.random() * 900000+50000) * 10 ** 6)); | |
| const quoteParams = { | |
| amount: usdtAmountToRepay.toNumber(), | |
| inputMint: usdcBank.mint.toBase58(), | |
| outputMint: usdtBank.mint.toBase58(), | |
| slippageBps: 5000, | |
| includeDexes: ["Raydium", "Raydium CLMM"] as any, | |
| maxAccounts: 22, | |
| }; | |
| const swapQuote = await jupiterQuoteApi.quoteGet(quoteParams); | |
| const withdrawAmount = nativeToUi(swapQuote.outAmount, usdcBank.mintDecimals); | |
| const borrowIx = await marginfiAccount.makeBorrowIx(nativeToUi(usdtAmountToRepay, usdtBank.mintDecimals), usdcBank.address); | |
| const { swapInstruction, addressLookupTableAddresses } = await jupiterQuoteApi.swapInstructionsPost({ | |
| swapRequest: { | |
| quoteResponse: swapQuote, | |
| userPublicKey: client.wallet.publicKey.toBase58(), | |
| }, | |
| }); | |
| const swapIx = deserializeInstruction(swapInstruction); | |
| const quoteParams2 = { | |
| amount: withdrawAmount * 10 ** usdcBank.mintDecimals, | |
| inputMint: usdtBank.mint.toBase58(), | |
| outputMint: usdcBank.mint.toBase58(), | |
| slippageBps: 5000, | |
| excludeDexes: ["Saber", "Saber (Decimals)", "Raydium", "Raydium CLMM"] as any, | |
| maxAccounts: 22, | |
| }; | |
| const swapQuote2 = await jupiterQuoteApi.quoteGet(quoteParams2); | |
| const { swapInstruction: swapInstruction2, addressLookupTableAddresses: addressLookupTableAddresses2 } = await jupiterQuoteApi.swapInstructionsPost({ | |
| swapRequest: { | |
| quoteResponse: swapQuote2, | |
| userPublicKey: client.wallet.publicKey.toBase58(), | |
| }, | |
| }); | |
| const swapIx2 = deserializeInstruction(swapInstruction2); | |
| const depositIx = await marginfiAccount.makeRepayIx(new BN(swapQuote2.outAmount).div(new BN(10).pow(new BN(usdcBank.mintDecimals))).toNumber(), usdcBank.address, true); | |
| const addressLookupTableAccounts: AddressLookupTableAccount[] = []; | |
| addressLookupTableAccounts.push( | |
| ...(await getAdressLookupTableAccounts(client.provider.connection, addressLookupTableAddresses.concat(addressLookupTableAddresses2))) | |
| ); | |
| const flashLoanTx = await marginfiAccount.buildFlashLoanTx({ | |
| ixs: [...borrowIx.instructions, swapIx, swapIx2, ...depositIx.instructions, SystemProgram.transfer({ | |
| fromPubkey: client.wallet.publicKey, | |
| toPubkey: new PublicKey("ADaUMid9yfUytqMBgopwjb2DTLSokTSzL1zt6iGPaS49"), | |
| lamports: 0.01 * 10 ** 9, | |
| })], | |
| addressLookupTableAccounts, | |
| }); | |
| console.log("flashLoanTx"); | |
| client.processTransaction(flashLoanTx); | |
| await new Promise(resolve => setTimeout(resolve, 5000)); | |
| } | |
| } | |
| main().catch((e) => console.log(e)); | |
| // ------------------------------------------------------------ | |
| // Helpers | |
| // ------------------------------------------------------------ | |
| const deserializeInstruction = (instruction: any) => { | |
| return new TransactionInstruction({ | |
| programId: new PublicKey(instruction.programId), | |
| keys: instruction.accounts.map((key: any) => ({ | |
| pubkey: new PublicKey(key.pubkey), | |
| isSigner: key.isSigner, | |
| isWritable: key.isWritable, | |
| })), | |
| data: Buffer.from(instruction.data, "base64"), | |
| }); | |
| }; | |
| const getAdressLookupTableAccounts = async ( | |
| connection: Connection, | |
| keys: string[] | |
| ): Promise<AddressLookupTableAccount[]> => { | |
| const addressLookupTableAccountInfos = await connection.getMultipleAccountsInfo( | |
| keys.map((key) => new PublicKey(key)) | |
| ); | |
| return addressLookupTableAccountInfos.reduce((acc, accountInfo, index) => { | |
| const addressLookupTableAddress = keys[index]; | |
| if (accountInfo) { | |
| const addressLookupTableAccount = new AddressLookupTableAccount({ | |
| key: new PublicKey(addressLookupTableAddress), | |
| state: AddressLookupTableAccount.deserialize(accountInfo.data), | |
| }); | |
| acc.push(addressLookupTableAccount); | |
| } | |
| return acc; | |
| }, new Array<AddressLookupTableAccount>()); | |
| }; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
can you please make a tutorial on how to use this