@shyft-to/solana-transaction-parser
Version:
Tool for parsing arbitrary Solana transactions with IDL/custom parsers
833 lines • 44.1 kB
JavaScript
import { PublicKey } from "@solana/web3.js";
import { AuthorityType, TokenInstruction, decodeApproveCheckedInstruction, decodeApproveInstruction, decodeBurnCheckedInstruction, decodeBurnInstruction, decodeCloseAccountInstruction, decodeFreezeAccountInstruction, decodeInitializeAccountInstruction, decodeInitializeMintInstructionUnchecked, decodeInitializeMultisigInstruction, decodeMintToCheckedInstruction, decodeMintToInstruction, decodeRevokeInstruction, decodeSetAuthorityInstruction, decodeThawAccountInstruction, decodeTransferCheckedInstruction, decodeTransferInstruction, decodeAmountToUiAmountInstruction, decodeInitializeAccount2Instruction, decodeInitializeAccount3Instruction, decodeInitializeMint2Instruction, decodeInitializeImmutableOwnerInstruction, decodeInitializeMintCloseAuthorityInstruction, decodeUiAmountToAmountInstruction, TOKEN_2022_PROGRAM_ID, ExtensionType, TransferFeeInstruction, decodeInitializeTransferFeeConfigInstruction, decodeTransferCheckedWithFeeInstruction, decodeWithdrawWithheldTokensFromMintInstruction, decodeWithdrawWithheldTokensFromAccountsInstruction, decodeHarvestWithheldTokensToMintInstruction, DefaultAccountStateInstruction, AccountState, defaultAccountStateInstructionData, memoTransferInstructionData, MemoTransferInstruction, cpiGuardInstructionData, CpiGuardInstruction, decodeInitializePermanentDelegateInstruction, TransferHookInstruction, initializeTransferHookInstructionData, updateTransferHookInstructionData, MetadataPointerInstruction, initializeMetadataPointerData, updateMetadataPointerData, GroupPointerInstruction, initializeGroupPointerData, updateGroupPointerData, GroupMemberPointerInstruction, initializeGroupMemberPointerData, updateGroupMemberPointerData, decodeSetTransferFeeInstruction, } from "@solana/spl-token";
import { BN } from "@coral-xyz/anchor";
import { splDiscriminate } from "@solana/spl-type-length-value";
import { emitLayout, getAccountDataSizeLayout, metadataLayout, removeKeyLayout, updateAuthorityLayout, updateMetadataLayout, } from "../programs/token-extensions";
function decodeToken2022Instruction(instruction) {
let parsed;
const decoded = instruction.data[0];
switch (decoded) {
case TokenInstruction.InitializeMint: {
const decodedIx = decodeInitializeMintInstructionUnchecked(instruction);
parsed = {
name: "initializeMint",
accounts: [
{ name: "mint", ...decodedIx.keys.mint },
{ name: "rent", ...decodedIx.keys.rent },
],
args: { decimals: decodedIx.data.decimals, mintAuthority: decodedIx.data.mintAuthority, freezeAuthority: decodedIx.data.freezeAuthority },
};
break;
}
case TokenInstruction.InitializeAccount: {
const decodedIx = decodeInitializeAccountInstruction(instruction, TOKEN_2022_PROGRAM_ID);
parsed = {
name: "initializeAccount",
accounts: [
{ name: "account", ...decodedIx.keys.account },
{ name: "mint", ...decodedIx.keys.mint },
{ name: "owner", ...decodedIx.keys.owner },
{ name: "rent", ...decodedIx.keys.rent },
],
args: {},
};
break;
}
case TokenInstruction.InitializeMultisig: {
const decodedIx = decodeInitializeMultisigInstruction(instruction, TOKEN_2022_PROGRAM_ID);
const multisig = decodedIx.keys.signers.map((meta, idx) => ({ name: `signer_${idx}`, ...meta }));
parsed = {
name: "initializeMultisig",
accounts: [{ name: "multisig", ...decodedIx.keys.account }, { name: "rent", ...decodedIx.keys.rent }, ...multisig],
args: { m: decodedIx.data.m },
};
break;
}
case TokenInstruction.Transfer: {
const decodedIx = decodeTransferInstruction(instruction, TOKEN_2022_PROGRAM_ID);
const multisig = decodedIx.keys.multiSigners.map((meta, idx) => ({ name: `signer_${idx}`, ...meta }));
parsed = {
name: "transfer",
accounts: [
{ name: "source", ...decodedIx.keys.source },
{ name: "destination", ...decodedIx.keys.destination },
{ name: "authority", ...decodedIx.keys.owner },
...multisig,
],
args: { amount: new BN(decodedIx.data.amount.toString()) },
};
break;
}
case TokenInstruction.Approve: {
const decodedIx = decodeApproveInstruction(instruction, TOKEN_2022_PROGRAM_ID);
const multisig = decodedIx.keys.multiSigners.map((meta, idx) => ({ name: `signer_${idx}`, ...meta }));
parsed = {
name: "approve",
accounts: [
{ name: "source", ...decodedIx.keys.account },
{ name: "delegate", ...decodedIx.keys.delegate },
{ name: "owner", ...decodedIx.keys.owner },
...multisig,
],
args: { amount: new BN(decodedIx.data.amount.toString()) },
};
break;
}
case TokenInstruction.Revoke: {
const decodedIx = decodeRevokeInstruction(instruction, TOKEN_2022_PROGRAM_ID);
const multisig = decodedIx.keys.multiSigners.map((meta, idx) => ({ name: `signer_${idx}`, ...meta }));
parsed = {
name: "revoke",
accounts: [{ name: "source", ...decodedIx.keys.account }, { name: "owner", ...decodedIx.keys.owner }, ...multisig],
args: {},
};
break;
}
case TokenInstruction.SetAuthority: {
const decodedIx = decodeSetAuthorityInstruction(instruction, TOKEN_2022_PROGRAM_ID);
const multisig = decodedIx.keys.multiSigners.map((meta, idx) => ({ name: `signer_${idx}`, ...meta }));
const authrorityTypeMap = {
[AuthorityType.AccountOwner]: { AccountOwner: {} },
[AuthorityType.CloseAccount]: { CloseAccount: {} },
[AuthorityType.FreezeAccount]: { FreezeAccount: {} },
[AuthorityType.MintTokens]: { MintTokens: {} },
[AuthorityType.CloseMint]: { CloseMint: {} },
[AuthorityType.ConfidentialTransferFeeConfig]: { ConfidentialTransferFeeConfig: {} },
[AuthorityType.ConfidentialTransferMint]: { ConfidentialTransferMint: {} },
[AuthorityType.GroupMemberPointer]: { GroupMemberPointer: {} },
[AuthorityType.GroupPointer]: { GroupPointer: {} },
[AuthorityType.InterestRate]: { InterestRate: {} },
[AuthorityType.MetadataPointer]: { MetadataPointer: {} },
[AuthorityType.PermanentDelegate]: { PermanentDelegate: {} },
[AuthorityType.TransferFeeConfig]: { TransferFeeConfig: {} },
[AuthorityType.TransferHookProgramId]: { TransferHookProgramId: {} },
[AuthorityType.WithheldWithdraw]: { WithheldWithdraw: {} },
};
parsed = {
name: "setAuthority",
accounts: [{ name: "owned", ...decodedIx.keys.account }, { name: "owner", ...decodedIx.keys.currentAuthority }, ...multisig],
args: { authorityType: authrorityTypeMap[decodedIx.data.authorityType], newAuthority: decodedIx.data.newAuthority },
programId: TOKEN_2022_PROGRAM_ID,
};
break;
}
case TokenInstruction.MintTo: {
const decodedIx = decodeMintToInstruction(instruction, TOKEN_2022_PROGRAM_ID);
const multisig = decodedIx.keys.multiSigners.map((meta, idx) => ({ name: `signer_${idx}`, ...meta }));
parsed = {
name: "mintTo",
accounts: [
{ name: "mint", ...decodedIx.keys.mint },
{ name: "account", ...decodedIx.keys.destination },
{ name: "owner", ...decodedIx.keys.authority },
...multisig,
],
args: { amount: new BN(decodedIx.data.amount.toString()) },
};
break;
}
case TokenInstruction.Burn: {
const decodedIx = decodeBurnInstruction(instruction, TOKEN_2022_PROGRAM_ID);
const multisig = decodedIx.keys.multiSigners.map((meta, idx) => ({ name: `signer_${idx}`, ...meta }));
parsed = {
name: "burn",
accounts: [
{ name: "account", ...decodedIx.keys.account },
{ name: "mint", ...decodedIx.keys.mint },
{ name: "authority", ...decodedIx.keys.owner },
...multisig,
],
args: { amount: new BN(decodedIx.data.amount.toString()) },
};
break;
}
case TokenInstruction.CloseAccount: {
const decodedIx = decodeCloseAccountInstruction(instruction, TOKEN_2022_PROGRAM_ID);
const multisig = decodedIx.keys.multiSigners.map((meta, idx) => ({ name: `signer_${idx}`, ...meta }));
parsed = {
name: "closeAccount",
accounts: [
{ name: "account", ...decodedIx.keys.account },
{ name: "destination", ...decodedIx.keys.destination },
{ name: "owner", ...decodedIx.keys.authority },
...multisig,
],
args: {},
};
break;
}
case TokenInstruction.FreezeAccount: {
const decodedIx = decodeFreezeAccountInstruction(instruction, TOKEN_2022_PROGRAM_ID);
const multisig = decodedIx.keys.multiSigners.map((meta, idx) => ({ name: `signer_${idx}`, ...meta }));
parsed = {
name: "freezeAccount",
accounts: [
{ name: "account", ...decodedIx.keys.account },
{ name: "mint", ...decodedIx.keys.mint },
{ name: "owner", ...decodedIx.keys.authority },
...multisig,
],
args: {},
};
break;
}
case TokenInstruction.ThawAccount: {
const decodedIx = decodeThawAccountInstruction(instruction, TOKEN_2022_PROGRAM_ID);
const multisig = decodedIx.keys.multiSigners.map((meta, idx) => ({ name: `signer_${idx}`, ...meta }));
parsed = {
name: "thawAccount",
accounts: [
{ name: "account", ...decodedIx.keys.account },
{ name: "mint", ...decodedIx.keys.mint },
{ name: "owner", ...decodedIx.keys.authority },
...multisig,
],
args: {},
};
break;
}
case TokenInstruction.TransferChecked: {
const decodedIx = decodeTransferCheckedInstruction(instruction, TOKEN_2022_PROGRAM_ID);
const multisig = decodedIx.keys.multiSigners.map((meta, idx) => ({ name: `signer_${idx}`, ...meta }));
parsed = {
name: "transferChecked",
accounts: [
{ name: "source", ...decodedIx.keys.source },
{ name: "mint", ...decodedIx.keys.mint },
{ name: "destination", ...decodedIx.keys.destination },
{ name: "authority", ...decodedIx.keys.owner },
...multisig,
],
args: { amount: new BN(decodedIx.data.amount.toString()), decimals: decodedIx.data.decimals },
};
break;
}
case TokenInstruction.ApproveChecked: {
const decodedIx = decodeApproveCheckedInstruction(instruction, TOKEN_2022_PROGRAM_ID);
const multisig = decodedIx.keys.multiSigners.map((meta, idx) => ({ name: `signer_${idx}`, ...meta }));
parsed = {
name: "approveChecked",
accounts: [
{ name: "source", ...decodedIx.keys.account },
{ name: "mint", ...decodedIx.keys.mint },
{ name: "delegate", ...decodedIx.keys.delegate },
{ name: "owner", ...decodedIx.keys.owner },
...multisig,
],
args: { amount: new BN(decodedIx.data.amount.toString()), decimals: decodedIx.data.decimals },
};
break;
}
case TokenInstruction.MintToChecked: {
const decodedIx = decodeMintToCheckedInstruction(instruction, TOKEN_2022_PROGRAM_ID);
const multisig = decodedIx.keys.multiSigners.map((meta, idx) => ({ name: `signer_${idx}`, ...meta }));
parsed = {
name: "mintToChecked",
accounts: [
{ name: "mint", ...decodedIx.keys.mint },
{ name: "account", ...decodedIx.keys.destination },
{ name: "owner", ...decodedIx.keys.authority },
...multisig,
],
args: { amount: new BN(decodedIx.data.amount.toString()), decimals: decodedIx.data.decimals },
};
break;
}
case TokenInstruction.BurnChecked: {
const decodedIx = decodeBurnCheckedInstruction(instruction, TOKEN_2022_PROGRAM_ID);
const multisig = decodedIx.keys.multiSigners.map((meta, idx) => ({ name: `signer_${idx}`, ...meta }));
parsed = {
name: "burnChecked",
accounts: [
{ name: "account", ...decodedIx.keys.account },
{ name: "mint", ...decodedIx.keys.mint },
{ name: "authority", ...decodedIx.keys.owner },
...multisig,
],
args: { amount: new BN(decodedIx.data.amount.toString()), decimals: decodedIx.data.decimals },
};
break;
}
case TokenInstruction.InitializeAccount2: {
const decodedIx = decodeInitializeAccount2Instruction(instruction, TOKEN_2022_PROGRAM_ID);
parsed = {
name: "initializeAccount2",
accounts: [
{ name: "account", ...instruction.keys[0] },
{ name: "mint", ...instruction.keys[1] },
{ name: "rent", ...instruction.keys[2] },
],
args: { owner: new PublicKey(decodedIx.data.owner) },
};
break;
}
case TokenInstruction.SyncNative: {
parsed = {
name: "syncNative",
accounts: [{ name: "account", ...instruction.keys[0] }],
args: {},
};
break;
}
case TokenInstruction.InitializeAccount3: {
const decodedIx = decodeInitializeAccount3Instruction(instruction, instruction.programId);
parsed = {
name: "initializeAccount3",
accounts: [
{ name: "account", ...instruction.keys[0] },
{ name: "mint", ...instruction.keys[1] },
],
args: { owner: new PublicKey(decodedIx.data.owner) },
};
break;
}
case TokenInstruction.InitializeMultisig2: {
const multisig = instruction.keys.slice(1).map((meta, idx) => ({ name: `signer_${idx}`, ...meta }));
parsed = {
name: "initializeMultisig2",
accounts: [{ name: "multisig", ...instruction.keys[0] }, ...multisig],
args: { m: instruction.data[1] },
};
break;
}
case TokenInstruction.InitializeMint2: {
const decodedIx = decodeInitializeMint2Instruction(instruction, instruction.programId);
const tokenMint = decodedIx.keys.mint;
if (!tokenMint)
throw new Error(`Failed to parse InitializeMint2 instruction`);
parsed = {
name: "initializeMint2",
accounts: [{ name: "mint", ...decodedIx.keys.mint }],
args: { decimals: decodedIx.data.decimals, mintAuthority: decodedIx.data.mintAuthority, freezeAuthority: decodedIx.data.freezeAuthority },
};
break;
}
case TokenInstruction.GetAccountDataSize: {
const tokenMint = instruction.keys[0].pubkey;
if (!tokenMint)
throw new Error(`Failed to parse GetAccountDataSize instruction`);
const instructionData = getAccountDataSizeLayout.decode(instruction.data);
const types = instructionData.extensions.map((ext) => ({
[ExtensionType[ext]]: {},
}));
parsed = {
name: "getAccountDataSize",
programId: instruction.programId,
accounts: [{ name: "mint", isSigner: false, isWritable: false, pubkey: instruction.keys[0].pubkey }],
args: {
extensionTypes: types,
},
};
break;
}
case TokenInstruction.InitializeImmutableOwner: {
const decodedIx = decodeInitializeImmutableOwnerInstruction(instruction, TOKEN_2022_PROGRAM_ID);
const account = decodedIx.keys.account;
if (!account)
throw new Error(`Failed to parse InitializeImmutableOwner instruction`);
parsed = {
name: "initializeImmutableOwner",
accounts: [{ name: "tokenAccount", ...decodedIx.keys.account }],
args: {},
};
break;
}
case TokenInstruction.AmountToUiAmount: {
const decodedIx = decodeAmountToUiAmountInstruction(instruction, TOKEN_2022_PROGRAM_ID);
const tokenMint = decodedIx.keys.mint;
if (!tokenMint)
throw new Error(`Failed to parse AmountToUiAmount instruction`);
parsed = {
name: "amountToUiAmount",
accounts: [{ name: "mint", ...decodedIx.keys.mint }],
args: { amount: new BN(decodedIx.data.amount.toString()) },
};
break;
}
case TokenInstruction.UiAmountToAmount: {
const decodedIx = decodeUiAmountToAmountInstruction(instruction, TOKEN_2022_PROGRAM_ID);
const tokenMint = decodedIx.keys.mint;
if (!tokenMint)
throw new Error(`Failed to parse UiAmountToAmount instruction`);
parsed = {
name: "uiAmountToAmount",
accounts: [{ name: "mint", ...decodedIx.keys.mint }],
args: { uiAmount: decodedIx.data.amount },
};
break;
}
case TokenInstruction.InitializeMintCloseAuthority: {
const decodedIx = decodeInitializeMintCloseAuthorityInstruction(instruction, TOKEN_2022_PROGRAM_ID);
const tokenMint = decodedIx.keys.mint;
if (!tokenMint)
throw new Error(`Failed to parse InitializeMintCloseAuthority instruction`);
parsed = {
name: "initializeMintCloseAuthority",
accounts: [{ name: "mint", ...decodedIx.keys.mint }],
args: { closeAuthority: decodedIx.data.closeAuthority },
};
break;
}
case TokenInstruction.CreateNativeMint: {
const payer = instruction.keys[0].pubkey;
if (!payer)
throw new Error(`Failed to parse CreateNativeMint instruction`);
parsed = {
name: "createNativeMint",
accounts: [
{ name: "payer", isSigner: true, isWritable: true, pubkey: instruction.keys[0].pubkey },
{ name: "crateNativeMint", isSigner: false, isWritable: true, pubkey: instruction.keys[1].pubkey },
{ name: "systemProgram", isSigner: false, isWritable: false, pubkey: instruction.keys[2].pubkey },
],
args: {},
};
break;
}
case TokenInstruction.TransferFeeExtension: {
const discriminator = instruction.data[1];
switch (discriminator) {
case TransferFeeInstruction.InitializeTransferFeeConfig: {
const decodedIx = decodeInitializeTransferFeeConfigInstruction(instruction, TOKEN_2022_PROGRAM_ID);
const tokenMint = decodedIx.keys.mint;
if (!tokenMint)
throw new Error(`Failed to parse InitializeTransferFeeConfig instruction`);
parsed = {
name: "initializeTransferFeeConfig",
accounts: [{ name: "mint", ...decodedIx.keys.mint }],
args: {
transferFeeConfigAuthority: decodedIx.data.transferFeeConfigAuthority,
withdrawWithheldAuthority: decodedIx.data.withdrawWithheldAuthority,
transferFeeBasisPoints: decodedIx.data.transferFeeBasisPoints,
maximumFee: decodedIx.data.maximumFee,
},
};
break;
}
case TransferFeeInstruction.TransferCheckedWithFee: {
const decodedIx = decodeTransferCheckedWithFeeInstruction(instruction, TOKEN_2022_PROGRAM_ID);
const tokenMint = decodedIx.keys.mint;
if (!tokenMint)
throw new Error(`Failed to parse TransferCheckedWithFee instruction`);
parsed = {
name: "transferCheckedWithFee",
accounts: [
{ name: "source", ...decodedIx.keys.source },
{ name: "mint", ...decodedIx.keys.mint },
{ name: "destination", ...decodedIx.keys.destination },
{ name: "authority", ...decodedIx.keys.authority },
],
args: {
amount: decodedIx.data.amount,
decimals: decodedIx.data.decimals,
fee: decodedIx.data.fee,
},
};
if (decodedIx.keys.signers) {
const multisig = decodedIx.keys.signers.map((meta, idx) => ({ name: `signer_${idx}`, ...meta }));
// @ts-ignore - Expression produces a union type that is too complex to represent. We don't need type checks here
parsed.accounts.push(...multisig);
}
break;
}
case TransferFeeInstruction.WithdrawWithheldTokensFromMint: {
const decodedIx = decodeWithdrawWithheldTokensFromMintInstruction(instruction, TOKEN_2022_PROGRAM_ID);
const tokenMint = decodedIx.keys.mint;
if (!tokenMint)
throw new Error(`Failed to parse WithdrawWithheldTokensFromMint instruction`);
parsed = {
name: "withdrawWithheldTokensFromMint",
accounts: [
{ name: "mint", ...decodedIx.keys.mint },
{ name: "destination", ...decodedIx.keys.destination },
{ name: "authority", ...decodedIx.keys.authority },
],
args: {},
};
if (decodedIx.keys.signers) {
const multisig = decodedIx.keys.signers.map((meta, idx) => ({ name: `signer_${idx}`, ...meta }));
parsed.accounts.push(...multisig);
}
break;
}
case TransferFeeInstruction.WithdrawWithheldTokensFromAccounts: {
const decodedIx = decodeWithdrawWithheldTokensFromAccountsInstruction(instruction, TOKEN_2022_PROGRAM_ID);
const tokenMint = decodedIx.keys.mint;
if (!tokenMint)
throw new Error(`Failed to parse WithdrawWithheldTokensFromAccounts instruction`);
parsed = {
name: "withdrawWithheldTokensFromAccounts",
accounts: [
{ name: "mint", ...decodedIx.keys.mint },
{ name: "destination", ...decodedIx.keys.destination },
{ name: "authority", ...decodedIx.keys.authority },
],
args: {},
};
if (decodedIx.keys.signers) {
const multisig = decodedIx.keys.signers.map((meta, idx) => ({ name: `signer_${idx}`, ...meta }));
parsed.accounts.push(...multisig);
}
if (decodedIx.keys.sources) {
const multisig = decodedIx.keys.sources.map((meta, idx) => ({ name: `source_${idx}`, ...meta }));
parsed.accounts.push(...multisig);
}
break;
}
case TransferFeeInstruction.HarvestWithheldTokensToMint: {
const decodedIx = decodeHarvestWithheldTokensToMintInstruction(instruction, TOKEN_2022_PROGRAM_ID);
const tokenMint = decodedIx.keys.mint;
if (!tokenMint)
throw new Error(`Failed to parse HarvestWithheldTokensToMint instruction`);
parsed = {
name: "harvestWithheldTokensToMint",
accounts: [{ name: "mint", ...decodedIx.keys.mint }],
args: {},
};
if (decodedIx.keys.sources) {
const multisig = decodedIx.keys.sources.map((meta, idx) => ({ name: `source_${idx}`, ...meta }));
parsed.accounts.push(...multisig);
}
break;
}
case TransferFeeInstruction.SetTransferFee: {
const decodedIx = decodeSetTransferFeeInstruction(instruction, TOKEN_2022_PROGRAM_ID);
const tokenMint = decodedIx.keys.mint;
if (!tokenMint)
throw new Error(`Failed to parse SetTransferFee instruction`);
parsed = {
name: "setTransferFee",
accounts: [
{ name: "mint", ...decodedIx.keys.mint },
{ name: "authority", ...decodedIx.keys.authority },
],
args: { transferFeeBasisPoints: decodedIx.data.transferFeeBasisPoints, maximumFee: decodedIx.data.maximumFee },
};
if (decodedIx.keys.signers) {
const multisig = decodedIx.keys.signers.map((meta, idx) => ({ name: `signer_${idx}`, ...meta }));
parsed.accounts.push(...multisig);
}
break;
}
default: {
parsed = null;
break;
}
}
break;
}
case TokenInstruction.DefaultAccountStateExtension: {
const discriminator = instruction.data[1];
switch (discriminator) {
case DefaultAccountStateInstruction.Initialize: {
const tokenMint = instruction.keys[0].pubkey;
if (!tokenMint)
throw new Error(`Failed to parse InitializeDefaultAccountState instruction`);
const instructionData = defaultAccountStateInstructionData.decode(instruction.data);
parsed = {
name: "initializeDefaultAccountState",
accounts: [{ name: "mint", ...instruction.keys[0] }],
args: { accountState: AccountState[instructionData.accountState] },
};
break;
}
case DefaultAccountStateInstruction.Update: {
const tokenMint = instruction.keys[0].pubkey;
if (!tokenMint)
throw new Error(`Failed to parse UpdateDefaultAccountState instruction`);
const multisig = instruction.keys.slice(2).map((meta, idx) => ({ name: `signer_${idx}`, ...meta }));
const instructionData = defaultAccountStateInstructionData.decode(instruction.data);
parsed = {
name: "updateDefaultAccountState",
accounts: [{ name: "mint", ...instruction.keys[0] }, { name: "freezeAuthority", ...instruction.keys[1] }, { ...multisig }],
args: { accountState: AccountState[instructionData.accountState] },
};
break;
}
default: {
parsed = null;
break;
}
}
break;
}
case TokenInstruction.MemoTransferExtension: {
const account = instruction.keys[0].pubkey;
if (!account)
throw new Error(`Failed to parse MemoTransfersInstruction instruction`);
const instructionData = memoTransferInstructionData.decode(instruction.data);
parsed = {
name: "memoTransfersInstruction",
accounts: [{ name: "account", ...instruction.keys[0] }, { name: "authority", ...instruction.keys[1] }, { ...instruction.keys.slice(2) }],
args: { memoTransferInstruction: MemoTransferInstruction[instructionData.memoTransferInstruction] },
};
break;
}
case TokenInstruction.InitializeNonTransferableMint: {
const mint = instruction.keys[0].pubkey;
if (!mint)
throw new Error(`Failed to parse InitializeNonTransferableMint instruction`);
parsed = {
name: "initializeNonTransferableMint",
accounts: [{ name: "mint", ...instruction.keys[0] }],
args: {},
};
break;
}
case TokenInstruction.CpiGuardExtension: {
const account = instruction.keys[0].pubkey;
if (!account)
throw new Error(`Failed to parse CreateCpiGuardInstruction instruction`);
const multisig = instruction.keys.slice(2).map((meta, idx) => ({ name: `signer_${idx}`, ...meta }));
const instructionData = cpiGuardInstructionData.decode(instruction.data);
parsed = {
name: "createCpiGuardInstruction",
accounts: [{ name: "account", ...instruction.keys[0] }, { name: "authority", ...instruction.keys[1] }, { ...multisig }],
args: { cpiGuardInstruction: CpiGuardInstruction[instructionData.cpiGuardInstruction] },
};
break;
}
case TokenInstruction.InitializePermanentDelegate: {
const mint = instruction.keys[0].pubkey;
if (!mint)
throw new Error(`Failed to parse InitializePermanentDelegate instruction`);
const decodedIx = decodeInitializePermanentDelegateInstruction(instruction, TOKEN_2022_PROGRAM_ID);
parsed = {
name: "initializePermanentDelegate",
accounts: [{ name: "account", ...decodedIx.keys.mint }],
args: { delegate: decodedIx.data.delegate },
};
break;
}
case TokenInstruction.TransferHookExtension: {
const discriminator = instruction.data[1];
switch (discriminator) {
case TransferHookInstruction.Initialize: {
const tokenMint = instruction.keys[0].pubkey;
if (!tokenMint)
throw new Error(`Failed to parse InitializeTransferHook instruction`);
const instructionData = initializeTransferHookInstructionData.decode(instruction.data);
parsed = {
name: "initializeTransferHook",
accounts: [{ name: "mint", ...instruction.keys[0] }],
args: { authority: instructionData.authority, transferHookProgramId: instructionData.transferHookProgramId },
};
break;
}
case TransferHookInstruction.Update: {
const tokenMint = instruction.keys[0].pubkey;
if (!tokenMint)
throw new Error(`Failed to parse UpdateTransferHook instruction`);
const multisig = instruction.keys.slice(2).map((meta, idx) => ({ name: `signer_${idx}`, ...meta }));
const instructionData = updateTransferHookInstructionData.decode(instruction.data);
parsed = {
name: "updateTransferHook",
accounts: [{ name: "mint", ...instruction.keys[0] }, { name: "authority", ...instruction.keys[1] }, { ...multisig }],
args: { transferHookProgramId: instructionData.transferHookProgramId },
};
break;
}
default: {
parsed = null;
break;
}
}
break;
}
case TokenInstruction.MetadataPointerExtension: {
const discriminator = instruction.data[1];
switch (discriminator) {
case MetadataPointerInstruction.Initialize: {
const tokenMint = instruction.keys[0].pubkey;
if (!tokenMint)
throw new Error(`Failed to parse InitializeMetadataPointer instruction`);
const instructionData = initializeMetadataPointerData.decode(instruction.data);
parsed = {
name: "initializeMetadataPointer",
accounts: [{ name: "mint", ...instruction.keys[0] }],
args: { authority: instructionData.authority, metadataAddress: instructionData.metadataAddress },
};
break;
}
case MetadataPointerInstruction.Update: {
const tokenMint = instruction.keys[0].pubkey;
if (!tokenMint)
throw new Error(`Failed to parse UpdateMetadataPointer instruction`);
const multisig = instruction.keys.slice(2).map((meta, idx) => ({ name: `signer_${idx}`, ...meta }));
const instructionData = updateMetadataPointerData.decode(instruction.data);
parsed = {
name: "updateMetadataPointer",
accounts: [{ name: "mint", ...instruction.keys[0] }, { name: "authority", ...instruction.keys[1] }, { ...multisig }],
args: { metadataAddress: instructionData.metadataAddress },
};
break;
}
default: {
parsed = null;
break;
}
}
break;
}
case TokenInstruction.GroupPointerExtension: {
const discriminator = instruction.data[1];
switch (discriminator) {
case GroupPointerInstruction.Initialize: {
const tokenMint = instruction.keys[0].pubkey;
if (!tokenMint)
throw new Error(`Failed to parse InitializeGroupPointer instruction`);
const instructionData = initializeGroupPointerData.decode(instruction.data);
parsed = {
name: "initializeGroupPointer",
accounts: [{ name: "mint", ...instruction.keys[0] }],
args: { authority: instructionData.authority, groupAddress: instructionData.groupAddress },
};
break;
}
case GroupPointerInstruction.Update: {
const tokenMint = instruction.keys[0].pubkey;
if (!tokenMint)
throw new Error(`Failed to parse UpdateGroupPointer instruction`);
const multisig = instruction.keys.slice(2).map((meta, idx) => ({ name: `signer_${idx}`, ...meta }));
const instructionData = updateGroupPointerData.decode(instruction.data);
parsed = {
name: "updateGroupPointer",
accounts: [{ name: "mint", ...instruction.keys[0] }, { name: "authority", ...instruction.keys[1] }, { ...multisig }],
args: { groupAddress: instructionData.groupAddress },
};
break;
}
default: {
parsed = null;
break;
}
}
break;
}
case TokenInstruction.GroupMemberPointerExtension: {
const discriminator = instruction.data[1];
switch (discriminator) {
case GroupMemberPointerInstruction.Initialize: {
const tokenMint = instruction.keys[0].pubkey;
if (!tokenMint)
throw new Error(`Failed to parse InitializeGroupMemberPointer instruction`);
const instructionData = initializeGroupMemberPointerData.decode(instruction.data);
parsed = {
name: "initializeGroupMemberPointer",
accounts: [{ name: "mint", ...instruction.keys[0] }],
args: { authority: instructionData.authority, memberAddress: instructionData.memberAddress },
};
break;
}
case GroupMemberPointerInstruction.Update: {
const tokenMint = instruction.keys[0].pubkey;
if (!tokenMint)
throw new Error(`Failed to parse UpdateGroupMemberPointer instruction`);
const multisig = instruction.keys.slice(2).map((meta, idx) => ({ name: `signer_${idx}`, ...meta }));
const instructionData = updateGroupMemberPointerData.decode(instruction.data);
parsed = {
name: "updateGroupMemberPointer",
accounts: [{ name: "mint", ...instruction.keys[0] }, { name: "authority", ...instruction.keys[1] }, { ...multisig }],
args: { memberAddress: instructionData.memberAddress },
};
break;
}
default: {
parsed = null;
break;
}
}
break;
}
default: {
const discriminator = instruction.data.slice(0, 8).toString("hex");
const [splDiscriminateInit, splDiscriminateUpdating, splDiscriminateRemove, splDiscriminateUpdate, splDiscriminateEmitter] = [
"spl_token_metadata_interface:initialize_account",
"spl_token_metadata_interface:updating_field",
"spl_token_metadata_interface:remove_key_ix",
"spl_token_metadata_interface:update_the_authority",
"spl_token_metadata_interface:emitter",
].map((s) => splDiscriminate(s));
switch (discriminator) {
case splDiscriminateInit.toString(): {
const metadata = metadataLayout.decode(instruction.data);
parsed = {
name: "initializeMetadata",
accounts: [
{ name: "metadata", ...instruction.keys[0] },
{ name: "updateAuthority", ...instruction.keys[1] },
{ name: "mint", ...instruction.keys[2] },
{ name: "mintAuthority", ...instruction.keys[3] },
],
args: {
name: metadata.name,
symbol: metadata.symbol,
uri: metadata.uri,
},
};
break;
}
case splDiscriminateUpdating.toString(): {
const data = updateMetadataLayout.decode(instruction.data);
parsed = {
name: "updateField",
accounts: [
{ name: "metadata", ...instruction.keys[0] },
{ name: "updateAuthority", ...instruction.keys[1] },
],
args: {
field: data.field,
value: data.value,
},
};
break;
}
case splDiscriminateRemove.toString(): {
const data = removeKeyLayout.decode(instruction.data);
parsed = {
name: "removeKey",
accounts: [
{ name: "metadata", ...instruction.keys[0] },
{ name: "updateAuthority", ...instruction.keys[1] },
],
args: {
idempotent: data.idempotent,
value: data.key,
},
};
break;
}
case splDiscriminateUpdate.toString(): {
const data = updateAuthorityLayout.decode(instruction.data);
parsed = {
name: "updateAuthority",
accounts: [
{ name: "metadata", ...instruction.keys[0] },
{ name: "oldAuthority", ...instruction.keys[1] },
],
args: {
newAuthority: new PublicKey(data.newAuthority),
},
};
break;
}
case splDiscriminateEmitter.toString(): {
const data = emitLayout.decode(instruction.data);
parsed = {
name: "emit",
accounts: [{ name: "metadata", ...instruction.keys[0] }],
args: data,
};
break;
}
default:
parsed = null;
}
break;
}
}
return parsed
? { ...parsed, programId: TOKEN_2022_PROGRAM_ID }
: { programId: TOKEN_2022_PROGRAM_ID, name: "unknown", accounts: instruction.keys, args: { unknown: instruction.data } };
}
export { decodeToken2022Instruction };
//# sourceMappingURL=token22.js.map