From 45fd36e0b2782141ca5a40fb407f20e929602ee0 Mon Sep 17 00:00:00 2001 From: Gopi Karath Date: Fri, 11 Sep 2026 22:56:13 +0000 Subject: [PATCH] fix(sol): decode Token-2022 unknown data as base64 Decode unknown Token-2022 instruction data as base64 before checking confidential-transfer discriminators. This prevents BurnChecked pending approvals from throwing Non-base58 character during transaction explanation. Ticket: CHALO-1512 Session-Id: b8d737f7-739a-42bb-81a7-a9fbaf1ec4a6 Task-Id: 6288c7bd-acc3-46ee-a0bf-b5f2d595384e --- .../src/lib/explainTransactionWasm.ts | 3 +-- .../test/unit/explainTransactionWasm.ts | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/modules/sdk-coin-sol/src/lib/explainTransactionWasm.ts b/modules/sdk-coin-sol/src/lib/explainTransactionWasm.ts index 560cdff615..c2f92cfa4b 100644 --- a/modules/sdk-coin-sol/src/lib/explainTransactionWasm.ts +++ b/modules/sdk-coin-sol/src/lib/explainTransactionWasm.ts @@ -9,7 +9,6 @@ import { } from './constants'; import { StakingAuthorizeParams, TransactionExplanation as SolLibTransactionExplanation } from './iface'; import { findTokenName } from './instructionParamsFactory'; -import bs58 from 'bs58'; export interface ExplainTransactionWasmOptions { txBase64: string; @@ -110,7 +109,7 @@ function isWasmConfidentialTransferInstruction(instr: InstructionParams): boolea // Token-2022 CT extension: byte 0 = CT_EXT_DISCRIMINATOR, byte 1 ∈ CT_SUB_DISCRIMINATORS const TOKEN_2022_PROGRAM_ID = 'TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb'; if (programId === TOKEN_2022_PROGRAM_ID) { - const dataBytes = bs58.decode(instr.data); + const dataBytes = Buffer.from(instr.data, 'base64'); if (dataBytes.length >= 2) { return dataBytes[0] === CT_EXT_DISCRIMINATOR && CT_SUB_DISCRIMINATORS.has(dataBytes[1]); } diff --git a/modules/sdk-coin-sol/test/unit/explainTransactionWasm.ts b/modules/sdk-coin-sol/test/unit/explainTransactionWasm.ts index a0bd07bdb6..24e46f5e2d 100644 --- a/modules/sdk-coin-sol/test/unit/explainTransactionWasm.ts +++ b/modules/sdk-coin-sol/test/unit/explainTransactionWasm.ts @@ -45,6 +45,21 @@ describe('explainTransactionWasm', function () { explained.tokenEnablements?.[0].tokenName.should.equal('3VDBJWgzRUscjQzzAp52na1dDquExZmD1PkCvH9svGF6'); }); + it('should classify a Token-2022 BurnChecked unknown instruction as CustomTx', function () { + // BurnChecked is not decoded by the WASM parser, so it is emitted as Unknown with + // base64-encoded data. This must not throw while checking for confidential transfers. + const TOKEN_2022_BURN_CHECKED_BASE64 = + 'AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAIEd4VubrtXALIH766Ipu/Fvh26FyvOPjpBMkYBe3UO30SFN5lu5h+qbiflw3DnoJGsdJ035d0WtazcVkIoE5FhOgk/IBzpsSfv2fKcdhTIHFEQKNBi10zrLtUIacusFNtQBt324e51j94YQl285GzN2rYa/E2DuQ0n/r35KNihi/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEDAwECAAoKQEIPAAAAAAAG'; + + const explained = explainSolTransaction({ + txBase64: TOKEN_2022_BURN_CHECKED_BASE64, + feeInfo: { fee: '5000' }, + coinName: 'tsol', + }); + + explained.type.should.equal('CustomTx'); + }); + it('should classify token transfer with Token ACL permissionless thaw as Send', function () { // TokenTransfer (transferChecked, Token-2022) + Token ACL ThawPermissionlessIdempotent for // the destination ATA. The Unknown thaw instruction previously triggered the CustomTx