Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion modules/sdk-coin-sol/src/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
TOKEN_PROGRAM_ID,
TOKEN_2022_PROGRAM_ID,
decodeInstruction,
DecodedInstruction,
TokenInstruction,
TransferFeeInstruction,
} from '@solana/spl-token';
Expand Down Expand Up @@ -414,7 +415,18 @@ export function getInstructionType(instruction: TransactionInstruction): ValidIn
) {
return 'TokenTransfer';
}
const decodedInstruction = decodeInstruction(instruction, instruction.programId);
let decodedInstruction: DecodedInstruction;
try {
decodedInstruction = decodeInstruction(instruction, instruction.programId);
} catch (e) {
// decodeInstruction only supports the base token instruction set —
// extension-family instructions (Pause, PermissionedBurn, transfer
// fee ops, ...) throw TokenInvalidInstructionTypeError at EVERY
// @solana/spl-token version. Those must not crash classification:
// fall back to CustomInstruction, the same path used below for
// decodable-but-unmapped instruction types.
return 'CustomInstruction';
}
const instructionTypeMap: Map<TokenInstruction, ValidInstructionTypes> = new Map();
instructionTypeMap.set(TokenInstruction.CloseAccount, 'CloseAssociatedTokenAccount');
instructionTypeMap.set(TokenInstruction.Burn, 'Burn');
Expand Down
19 changes: 19 additions & 0 deletions modules/sdk-coin-sol/test/unit/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,25 @@ describe('SOL util library', function () {
});
Utils.getInstructionType(invalidInstruction).should.equal('CustomInstruction');
});
it('should fallback to customInstruction for token instructions that cannot be decoded', function () {
// decodeInstruction only covers the base token instruction set;
// extension-family instructions (e.g. PermissionedBurnExtension = 46,
// PausableExtension = 44) throw TokenInvalidInstructionTypeError at
// every @solana/spl-token version. They must classify as
// CustomInstruction instead of crashing customTx validation.
const permissionedBurnChecked = new TransactionInstruction({
keys: [
{ pubkey: new PublicKey(testData.authAccount.pub), isSigner: false, isWritable: true },
{ pubkey: new PublicKey(testData.nonceAccount.pub), isSigner: false, isWritable: true },
{ pubkey: new PublicKey(testData.authAccount.pub), isSigner: true, isWritable: false },
{ pubkey: new PublicKey(testData.authAccount.pub), isSigner: true, isWritable: false },
],
programId: TOKEN_2022_PROGRAM_ID,
// [46 = PermissionedBurnExtension, 2 = BurnChecked, u64 amount, u8 decimals]
data: Buffer.from([46, 2, 0, 202, 154, 59, 0, 0, 0, 0, 9]),
});
Utils.getInstructionType(permissionedBurnChecked).should.equal('CustomInstruction');
});
it('should succeed for ComputeBudget SetComputeUnitLimit instruction', function () {
const setComputeUnitLimitInstruction = ComputeBudgetProgram.setComputeUnitLimit({
units: 300000,
Expand Down
Loading