wip: add flash loan 3

This commit is contained in:
tjs 2022-06-29 23:36:57 -04:00
parent 273b8dd597
commit ecbffe499f
1 changed files with 187 additions and 9 deletions

View File

@ -1225,7 +1225,9 @@ export class MangoClient {
const inputBankKey = transferIx.keys[2];
transferIx.keys[2] = { ...inputBankKey, isWritable: true, isSigner: false };
instructions.push(transferIx);
console.log('loading jup');
// TODO: move out of client and into ui
// Start Jupiter
const jupiter = await Jupiter.load({
connection: this.program.provider.connection,
@ -1235,8 +1237,6 @@ export class MangoClient {
routeCacheDuration: 10_000, // Will not refetch data on computeRoutes for up to 10 seconds
});
console.log('computing routes');
const routes = await jupiter.computeRoutes({
inputMint: inputBank.mint, // Mint address of the input token
outputMint: outputBank.mint, // Mint address of the output token
@ -1245,8 +1245,6 @@ export class MangoClient {
forceFetch: false, // false is the default value => will use cache if not older than routeCacheDuration
});
console.log('routes', routes);
const routesInfosWithoutRaydium = routes.routesInfos.filter((r) => {
if (r.marketInfos.length > 1) {
for (const mkt of r.marketInfos) {
@ -1256,13 +1254,9 @@ export class MangoClient {
}
return true;
});
console.log('routesInfosWithoutRaydium', routesInfosWithoutRaydium);
const selectedRoute = routesInfosWithoutRaydium[0];
console.log('outAmount', selectedRoute.outAmount);
console.log('outAmountWithSlippage', selectedRoute.outAmountWithSlippage);
console.log(
`route found: ${selectedRoute.marketInfos[0].amm.label}. generating jup transaction`,
);
@ -1282,6 +1276,8 @@ export class MangoClient {
}
}
// End Jupiter
const transferIx2 = Token.createTransferInstruction(
TOKEN_PROGRAM_ID,
outputTokenAccountPk,
@ -1370,6 +1366,188 @@ export class MangoClient {
.rpc({ skipPreflight: true });
}
public async marginTrade3({
group,
mangoAccount,
inputToken,
amountIn,
outputToken,
slippage = 0.5,
}: {
group: Group;
mangoAccount: MangoAccount;
inputToken: string;
amountIn: number;
outputToken: string;
slippage: number;
}): Promise<TransactionSignature> {
const inputBank = group.banksMap.get(inputToken);
const outputBank = group.banksMap.get(outputToken);
if (!inputBank || !outputBank) throw new Error('Invalid token');
const healthRemainingAccounts: PublicKey[] =
await this.buildHealthRemainingAccounts(group, mangoAccount, [
inputBank,
outputBank,
]);
const parsedHealthAccounts = healthRemainingAccounts.map(
(pk) =>
({
pubkey: pk,
isWritable:
pk.equals(inputBank.publicKey) || pk.equals(outputBank.publicKey)
? true
: false,
isSigner: false,
} as AccountMeta),
);
/*
* Find or create associated token accounts
*/
let inputTokenAccountPk = await getAssociatedTokenAddress(
inputBank.mint,
mangoAccount.owner,
);
const inputTokenAccExists =
await this.program.provider.connection.getAccountInfo(
inputTokenAccountPk,
);
let preInstructions = [];
if (!inputTokenAccExists) {
preInstructions.push(
Token.createAssociatedTokenAccountInstruction(
mangoAccount.owner,
inputTokenAccountPk,
mangoAccount.owner,
inputBank.mint,
TOKEN_PROGRAM_ID,
ASSOCIATED_TOKEN_PROGRAM_ID,
),
);
}
let outputTokenAccountPk = await getAssociatedTokenAddress(
outputBank.mint,
mangoAccount.owner,
);
const outputTokenAccExists =
await this.program.provider.connection.getAccountInfo(
outputTokenAccountPk,
);
if (!outputTokenAccExists) {
preInstructions.push(
Token.createAssociatedTokenAccountInstruction(
mangoAccount.owner,
outputTokenAccountPk,
mangoAccount.owner,
outputBank.mint,
TOKEN_PROGRAM_ID,
ASSOCIATED_TOKEN_PROGRAM_ID,
),
);
}
const nativeInputAmount = toU64(
amountIn,
inputBank.mintDecimals,
).toNumber();
const instructions: TransactionInstruction[] = [];
// TODO: move out of client and into ui
// Start Jupiter
const jupiter = await Jupiter.load({
connection: this.program.provider.connection,
cluster: 'mainnet-beta',
user: mangoAccount.owner, // or public key
// platformFeeAndAccounts: NO_PLATFORM_FEE,
routeCacheDuration: 10_000, // Will not refetch data on computeRoutes for up to 10 seconds
});
const routes = await jupiter.computeRoutes({
inputMint: inputBank.mint, // Mint address of the input token
outputMint: outputBank.mint, // Mint address of the output token
inputAmount: nativeInputAmount, // raw input amount of tokens
slippage, // The slippage in % terms
forceFetch: false, // false is the default value => will use cache if not older than routeCacheDuration
});
const routesInfosWithoutRaydium = routes.routesInfos.filter((r) => {
if (r.marketInfos.length > 1) {
for (const mkt of r.marketInfos) {
if (mkt.amm.label === 'Raydium' || mkt.amm.label === 'Serum')
return false;
}
}
return true;
});
const selectedRoute = routesInfosWithoutRaydium[0];
const { transactions } = await jupiter.exchange({
routeInfo: selectedRoute,
});
const { setupTransaction, swapTransaction } = transactions;
for (const ix of swapTransaction.instructions) {
if (
ix.programId.toBase58() ===
'JUP2jxvXaqu7NQY1GmNF4m1vodw12LVXYxbFL2uJvfo'
) {
instructions.push(ix);
}
}
// End Jupiter
if (setupTransaction) {
await this.program.provider.sendAndConfirm(setupTransaction);
} else if (preInstructions.length) {
const tx = new Transaction();
for (const ix of preInstructions) {
tx.add(ix);
}
console.log('preInstructions', preInstructions);
await this.program.provider.sendAndConfirm(tx);
}
const bankAccounts = {
isWritable: true,
pubkey: inputBank.publicKey,
isSigner: false,
};
const bankVaults = {
isWritable: true,
pubkey: inputBank.vault,
isSigner: false,
};
const aTokenAccounts = {
isWritable: true,
pubkey: inputTokenAccountPk,
isSigner: true,
};
const flashLoanEndIx = await this.program.methods
.flashLoan3End()
.accounts({
account: mangoAccount.publicKey,
owner: (this.program.provider as AnchorProvider).wallet.publicKey,
})
.remainingAccounts([...parsedHealthAccounts, bankVaults, aTokenAccounts])
.instruction();
return await this.program.methods
.flashLoan3Begin([toU64(amountIn, inputBank.mintDecimals)])
.accounts({
group: group.publicKey,
})
.remainingAccounts([bankAccounts, bankVaults, aTokenAccounts])
.postInstructions([...instructions, flashLoanEndIx])
.rpc({ skipPreflight: true });
}
/// liquidations
// TODO