Skip to content

Instantly share code, notes, and snippets.

@NotoriousPyro
Last active May 21, 2024 19:38
Show Gist options
  • Save NotoriousPyro/75213c245717bad24813ab5fd96609a4 to your computer and use it in GitHub Desktop.
Save NotoriousPyro/75213c245717bad24813ab5fd96609a4 to your computer and use it in GitHub Desktop.
Jupiter IDL types and decompiling swap data
const decodedA = await decodeSwapInstructionData<Route["Arguments"]>(swapinstA.swapInstruction.data);
const decodedB = await decodeSwapInstructionData<Route["Arguments"]>(swapinstB.swapInstruction.data);
// do whatever you want
const Route_AccountsStrict: Route["AccountsStrict"] = {
tokenProgram: TOKEN_PROGRAM_ID,
userTransferAuthority: keypair.publicKey,
userSourceTokenAccount: inputMintATA,
userDestinationTokenAccount: inputMintATA,
destinationTokenAccount: program.programId,
destinationMint: new PublicKey(Solana),
platformFeeAccount: program.programId,
eventAuthority: new PublicKey("D8cy77BBepLMngZx6ZukaTff5hCt1HrWyKk3Hnd9oitf"), // Does it ever change for jupiter?
program: program.programId,
}
const prepared = createSwapInstruction(
Route_AccountsStrict,
await Promise.all([...swapinstA.swapInstruction.accounts.slice(9), ...swapinstB.swapInstruction.accounts.slice(9)].map(
async account => Promise.resolve(({
...account,
pubkey: new PublicKey(account.pubkey),
}))
)),
[decodedA.routePlan, decodedB.routePlan].flat(),
new BN(amount.toString()),
new BN(amount.toString()),
keypair
)
const instruction = prepared.instruction;
import BN from "bn.js";
import { BorshCoder } from "@coral-xyz/anchor";
import { MethodsBuilder } from "@coral-xyz/anchor/dist/cjs/program/namespace/methods";
import { AllInstructions, IdlTypes } from "@coral-xyz/anchor/dist/cjs/program/namespace/types";
import { Keypair, PublicKey } from "@solana/web3.js";
import { program } from '@jup-ag/instruction-parser'
export { program } from '@jup-ag/instruction-parser'
export const decoder = new BorshCoder(program.idl);
export type IDL = typeof program.idl;
export class DecodeInstructionError extends Error {
constructor(message: string) {
super(message);
this.name = "DecodeInstructionError";
}
}
type _AllInstructions = AllInstructions<IDL>;
type _AllTypes = IdlTypes<IDL>;
type RemainingAccounts = Parameters<MethodsBuilder<IDL, _AllInstructions>["remainingAccounts"]>[0];
type AccountsStrict = Parameters<MethodsBuilder<IDL, _AllInstructions>["accountsStrict"]>[0];
export type RoutePlanStep = _AllTypes["RoutePlanStep"];
export type Route = {
AccountsStrict: Pick<AccountsStrict,
"tokenProgram" |
"userTransferAuthority" |
"userSourceTokenAccount" |
"userDestinationTokenAccount" |
"destinationTokenAccount" |
"destinationMint" |
"platformFeeAccount" |
"eventAuthority" |
"program"
>;
RemainingAccounts: RemainingAccounts;
Arguments: {
routePlan: RoutePlanStep[],
inAmount: BN,
quotedOutAmount: BN,
slippageBps: number,
platformFeeBps: number,
}
}
export const createSwapInstruction = async (
accountsStrict: Route["AccountsStrict"],
remainingAccounts: Route["RemainingAccounts"],
routePlan: Route["Arguments"]["routePlan"],
inAmount: Route["Arguments"]["inAmount"],
quotedOutAmount: Route["Arguments"]["quotedOutAmount"],
keypair: Keypair
) => (
program.methods.route(
routePlan,
inAmount, // input amount
quotedOutAmount, // output amount
0, // slippage
0, // platform fee
)
.accountsStrict(accountsStrict)
.remainingAccounts(remainingAccounts)
.signers([keypair])
).prepare();
export const decodeSwapInstructionData = async <T>(
data: string,
): Promise<T> => {
try {
return decoder.instruction.decode(
Buffer.from(data, "base64"),
"base58"
).data as T;
} catch (e) {
if (e.message.includes("Cannot read properties of null (reading 'property')")) {
return Promise.reject(new DecodeInstructionError(`Failed to decode instruction data: ${data}. IDL possibly outdated.`));
}
return Promise.reject(e);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment