diff --git a/.changeset/late-carrots-brake.md b/.changeset/late-carrots-brake.md new file mode 100644 index 0000000..ba84da3 --- /dev/null +++ b/.changeset/late-carrots-brake.md @@ -0,0 +1,6 @@ +--- +"@solanafm/explorer-kit": patch +"@solanafm/explorer-kit-idls": patch +--- + +release: 1.1.4 diff --git a/packages/explorerkit-idls/src/idls/IdlRepository.ts b/packages/explorerkit-idls/src/idls/IdlRepository.ts index 7d07e4f..8c6a0ee 100644 --- a/packages/explorerkit-idls/src/idls/IdlRepository.ts +++ b/packages/explorerkit-idls/src/idls/IdlRepository.ts @@ -158,7 +158,9 @@ export const getProgramIdl = async ( return null; } catch (error) { - return null; + throw new Error(`Error fetching IDL for ${programHash}`, { + cause: error, + }); } } diff --git a/packages/explorerkit-translator/src/helpers/multisig-checker.ts b/packages/explorerkit-translator/src/helpers/multisig-checker.ts index 5da12c9..3ac7adc 100644 --- a/packages/explorerkit-translator/src/helpers/multisig-checker.ts +++ b/packages/explorerkit-translator/src/helpers/multisig-checker.ts @@ -18,7 +18,7 @@ export type DataWithMappedType = { * @returns An object containing the mapped account keys and their corresponding names. */ export const mapMultisigAccountKeysToName = ( - accountKeys?: IdlAccountName[], + accountKeys?: string[], idlIxAccounts?: IdlInstructionAccount[], accountName?: string ): DataWithMappedType => { diff --git a/packages/explorerkit-translator/src/parsers/v2/account/anchor-v1.ts b/packages/explorerkit-translator/src/parsers/v2/account/anchor-v1.ts index 9a2022b..5885fac 100644 --- a/packages/explorerkit-translator/src/parsers/v2/account/anchor-v1.ts +++ b/packages/explorerkit-translator/src/parsers/v2/account/anchor-v1.ts @@ -11,27 +11,36 @@ export const createAnchorV1AccountParser: (idlItem: IdlItem) => AccountParserInt const accountLayouts = new BorshAccountsCoder(idl); const parseAccount = (accountData: string, maptypes?: boolean): ParserOutput => { - const bufferData = Buffer.from(accountData, "base64"); - const accountDiscriminator = bufferData.subarray(0, 8); - const accountName = Array.from(idl.accounts ?? []).find((key) => - accountLayouts.accountDiscriminator(key.name).equals(accountDiscriminator) - ); - - let decodedAccountData = accountLayouts.decodeAny(bufferData); - - if (decodedAccountData) { - const filteredIdlType = idl.types?.filter((type) => type.name === accountName?.name) ?? []; - - if (maptypes) { - if (filteredIdlType[0]?.type.kind === "struct" && filteredIdlType[0]?.type.fields) - decodedAccountData = mapNewAnchorDataTypeToName(decodedAccountData, filteredIdlType[0]?.type.fields); + try { + const bufferData = Buffer.from(accountData, "base64"); + const accountDiscriminator = bufferData.subarray(0, 8); + const accountName = Array.from(idl.accounts ?? []).find((key) => + accountLayouts.accountDiscriminator(key.name).equals(accountDiscriminator) + ); + + let decodedAccountData = accountLayouts.decodeAny(bufferData); + + if (decodedAccountData) { + const filteredIdlType = idl.types?.filter((type) => type.name === accountName?.name) ?? []; + + if (maptypes) { + if (filteredIdlType[0]?.type.kind === "struct" && filteredIdlType[0]?.type.fields) + decodedAccountData = mapNewAnchorDataTypeToName(decodedAccountData, filteredIdlType[0]?.type.fields); + } + + return { + name: accountName?.name as string, + data: convertBNToNumberInObject(decodedAccountData), + type: ParserType.ACCOUNT, + }; } - - return { - name: accountName?.name as string, - data: convertBNToNumberInObject(decodedAccountData), - type: ParserType.ACCOUNT, - }; + } catch (error) { + throw new Error(`Error parsing account data - ${accountData}`, { + cause: { + decoderError: error, + programId: idlItem.programId, + }, + }); } return null; diff --git a/packages/explorerkit-translator/src/parsers/v2/account/anchor.ts b/packages/explorerkit-translator/src/parsers/v2/account/anchor.ts index 40f40dc..0a1b7e7 100644 --- a/packages/explorerkit-translator/src/parsers/v2/account/anchor.ts +++ b/packages/explorerkit-translator/src/parsers/v2/account/anchor.ts @@ -16,20 +16,30 @@ export const createAnchorAccountParser: (idlItem: IdlItem) => AccountParserInter const accountName = Array.from(idl.accounts ?? []).find((key) => BorshAccountsCoder.accountDiscriminator(key.name).equals(accountDiscriminator) ); - let decodedAccountData = accountLayouts.decodeAny(bufferData); - if (decodedAccountData) { - const filteredIdlAccount = idl.accounts?.filter((account) => account.name === accountName?.name) ?? []; + try { + let decodedAccountData = accountLayouts.decodeAny(bufferData); - if (maptypes) { - decodedAccountData = mapDataTypeToName(decodedAccountData, filteredIdlAccount[0]?.type.fields); - } + if (decodedAccountData) { + const filteredIdlAccount = idl.accounts?.filter((account) => account.name === accountName?.name) ?? []; + + if (maptypes) { + decodedAccountData = mapDataTypeToName(decodedAccountData, filteredIdlAccount[0]?.type.fields); + } - return { - name: accountName?.name as string, - data: convertBNToNumberInObject(decodedAccountData), - type: ParserType.ACCOUNT, - }; + return { + name: accountName?.name as string, + data: convertBNToNumberInObject(decodedAccountData), + type: ParserType.ACCOUNT, + }; + } + } catch (error) { + throw new Error(`Error parsing account data - ${accountData}`, { + cause: { + decoderError: error, + programId: idlItem.programId, + }, + }); } return null; diff --git a/packages/explorerkit-translator/src/parsers/v2/account/config.ts b/packages/explorerkit-translator/src/parsers/v2/account/config.ts index 1402d76..b57a0fa 100644 --- a/packages/explorerkit-translator/src/parsers/v2/account/config.ts +++ b/packages/explorerkit-translator/src/parsers/v2/account/config.ts @@ -50,8 +50,12 @@ export const createShankConfigAccount: (idlItem: IdlItem, accountHash: string) = return null; } catch (error) { - console.error(error); - return null; + throw new Error(`Error parsing account data - ${accountData}`, { + cause: { + decoderError: error, + programId: idlItem.programId, + }, + }); } }; diff --git a/packages/explorerkit-translator/src/parsers/v2/account/metadata.ts b/packages/explorerkit-translator/src/parsers/v2/account/metadata.ts index d84415e..50b9a94 100644 --- a/packages/explorerkit-translator/src/parsers/v2/account/metadata.ts +++ b/packages/explorerkit-translator/src/parsers/v2/account/metadata.ts @@ -68,8 +68,12 @@ export const createShankMetaplexAccountParser: ( return null; } catch (error) { - console.error(error); - return null; + throw new Error(`Error parsing account data - ${accountData}`, { + cause: { + decoderError: error, + programId: idlItem.programId, + }, + }); } }; @@ -98,8 +102,6 @@ const sanitySerializeMetadataAccount = ( if (decodedAccountData && decodedAccountData[0]) { return decodedAccountData[0]; } - - return null; } catch (error) { if (error) { const typeLayouts = new KinobiTreeGenerator(idl).constructLayout(KinobiTreeGeneratorType.TYPES); @@ -213,8 +215,15 @@ const sanitySerializeMetadataAccount = ( } } - return null; + throw new Error(`Error parsing metadata account data - ${accountDataBuffer.toString("base64")}`, { + cause: { + decoderError: error, + programId: idl.metadata.address ?? "", + }, + }); } + + return null; }; function tryReadType( diff --git a/packages/explorerkit-translator/src/parsers/v2/account/name-service.ts b/packages/explorerkit-translator/src/parsers/v2/account/name-service.ts index 1457bf7..fcc6b2e 100644 --- a/packages/explorerkit-translator/src/parsers/v2/account/name-service.ts +++ b/packages/explorerkit-translator/src/parsers/v2/account/name-service.ts @@ -20,7 +20,7 @@ export const createShankNameServiceAccount: (idlItem: IdlItem) => AccountParserI let accountSerializer: FMShankSerializer | undefined = undefined; if (dataBuffer.byteLength < ACCOUNT_MIN_SIZE) { // account data is not within the range of the account we are trying to deserialize - return null; + throw new Error(`Account data length is less than the minimum size required for this account`); } // TODO: PLEASE ABSTRACT THIS IN THE FUTURE!!!! @@ -53,8 +53,12 @@ export const createShankNameServiceAccount: (idlItem: IdlItem) => AccountParserI return null; } catch (error) { - console.error(error); - return null; + throw new Error(`Error parsing account data - ${accountData}`, { + cause: { + decoderError: error, + programId: idlItem.programId, + }, + }); } }; diff --git a/packages/explorerkit-translator/src/parsers/v2/account/phoenix.ts b/packages/explorerkit-translator/src/parsers/v2/account/phoenix.ts index 559701e..643c41c 100644 --- a/packages/explorerkit-translator/src/parsers/v2/account/phoenix.ts +++ b/packages/explorerkit-translator/src/parsers/v2/account/phoenix.ts @@ -53,8 +53,12 @@ export const createShankPhoenixAccount: (idlItem: IdlItem) => AccountParserInter return null; } catch (error) { - console.error(error); - return null; + throw new Error(`Error parsing account data - ${accountData}`, { + cause: { + decoderError: error, + programId: idlItem.programId, + }, + }); } }; diff --git a/packages/explorerkit-translator/src/parsers/v2/account/shank.ts b/packages/explorerkit-translator/src/parsers/v2/account/shank.ts index 994d3bf..ce74872 100644 --- a/packages/explorerkit-translator/src/parsers/v2/account/shank.ts +++ b/packages/explorerkit-translator/src/parsers/v2/account/shank.ts @@ -69,8 +69,12 @@ export const createShankAccountParser: ( return null; } catch (error) { - console.error(error); - return null; + throw new Error(`Error parsing account data - ${accountData}`, { + cause: { + decoderError: error, + programId: idlItem.programId, + }, + }); } }; diff --git a/packages/explorerkit-translator/src/parsers/v2/account/token-v2.ts b/packages/explorerkit-translator/src/parsers/v2/account/token-v2.ts index 1ca6171..e32cc0f 100644 --- a/packages/explorerkit-translator/src/parsers/v2/account/token-v2.ts +++ b/packages/explorerkit-translator/src/parsers/v2/account/token-v2.ts @@ -156,8 +156,12 @@ export const createShankTokenV2Account: (idlItem: IdlItem) => AccountParserInter return null; } catch (error) { - console.error(error); - return null; + throw new Error(`Error parsing account data - ${accountData}`, { + cause: { + decoderError: error, + programId: idlItem.programId, + }, + }); } }; @@ -230,19 +234,28 @@ export const parseAccountWithoutExtensions = ( mapTypes?: boolean ) => { if (accountSerializer) { - const decodedAccountData = accountSerializer.serializer?.deserialize(dataBuffer); + try { + const decodedAccountData = accountSerializer.serializer?.deserialize(dataBuffer); - if (decodedAccountData && decodedAccountData[0]) { - const filteredIdlAccount = - idl.accounts?.filter( - (account) => account.name.toLowerCase() === accountSerializer?.instructionName.toLowerCase() - ) ?? []; + if (decodedAccountData && decodedAccountData[0]) { + const filteredIdlAccount = + idl.accounts?.filter( + (account) => account.name.toLowerCase() === accountSerializer?.instructionName.toLowerCase() + ) ?? []; - if (mapTypes) { - decodedAccountData[0] = mapDataTypeToName(decodedAccountData[0], filteredIdlAccount[0]?.type.fields); - } + if (mapTypes) { + decodedAccountData[0] = mapDataTypeToName(decodedAccountData[0], filteredIdlAccount[0]?.type.fields); + } - return decodedAccountData[0]; + return decodedAccountData[0]; + } + } catch (error) { + throw new Error(`Error parsing account data - ${dataBuffer.toString("base64")}`, { + cause: { + decoderError: error, + programId: idl.metadata.address ?? "", + }, + }); } } diff --git a/packages/explorerkit-translator/src/parsers/v2/account/token.ts b/packages/explorerkit-translator/src/parsers/v2/account/token.ts index 4279403..06ef702 100644 --- a/packages/explorerkit-translator/src/parsers/v2/account/token.ts +++ b/packages/explorerkit-translator/src/parsers/v2/account/token.ts @@ -25,7 +25,7 @@ export const createShankTokenAccount: (idlItem: IdlItem) => AccountParserInterfa if (dataBuffer.byteLength < MINT_MAX_SIZE && dataBuffer.byteLength > MULTISIG_MAX_SIZE) { // account data is not within the range of the account we are trying to deserialize - return null; + throw new Error(`Account data length is less than the minimum size required for this account`); } // checks if the account data length is within the length of the account we are trying to deserialize @@ -87,8 +87,12 @@ export const createShankTokenAccount: (idlItem: IdlItem) => AccountParserInterfa return null; } catch (error) { - console.error(error); - return null; + throw new Error(`Error parsing account data - ${accountData}`, { + cause: { + decoderError: error, + programId: idlItem.programId, + }, + }); } }; diff --git a/packages/explorerkit-translator/src/parsers/v2/error/AnchorErrorParser.ts b/packages/explorerkit-translator/src/parsers/v2/error/AnchorErrorParser.ts index a3c8b9e..daba5e7 100644 --- a/packages/explorerkit-translator/src/parsers/v2/error/AnchorErrorParser.ts +++ b/packages/explorerkit-translator/src/parsers/v2/error/AnchorErrorParser.ts @@ -506,7 +506,12 @@ export const createAnchorErrorParser: (idlItem: IdlItem) => ErrorParserInterface }; } } catch (parseErr) { - return null; + throw new Error(`Error parsing error data - ${unparsedErrorCode}`, { + cause: { + decoderError: parseErr, + programId: idlItem.programId, + }, + }); } return null; diff --git a/packages/explorerkit-translator/src/parsers/v2/error/ShankErrorParser.ts b/packages/explorerkit-translator/src/parsers/v2/error/ShankErrorParser.ts index f0c19a7..0fee2fa 100644 --- a/packages/explorerkit-translator/src/parsers/v2/error/ShankErrorParser.ts +++ b/packages/explorerkit-translator/src/parsers/v2/error/ShankErrorParser.ts @@ -36,7 +36,12 @@ export const createShankErrorParser: (idlItem: IdlItem) => ErrorParserInterface }; } } catch (parseErr) { - return null; + throw new Error(`Error parsing error data - ${unparsedErrorCode}`, { + cause: { + decoderError: parseErr, + programId: idlItem.programId, + }, + }); } return null; diff --git a/packages/explorerkit-translator/src/parsers/v2/event/anchor.ts b/packages/explorerkit-translator/src/parsers/v2/event/anchor.ts index 94eaf23..0c51cd7 100644 --- a/packages/explorerkit-translator/src/parsers/v2/event/anchor.ts +++ b/packages/explorerkit-translator/src/parsers/v2/event/anchor.ts @@ -34,8 +34,12 @@ export const createAnchorEventParser: (idlItem: IdlItem) => EventParserInterface return null; } catch (error) { - console.error(error); - return null; + throw new Error(`Error parsing event data - ${eventData}`, { + cause: { + decoderError: error, + programId: idlItem.programId, + }, + }); } }; diff --git a/packages/explorerkit-translator/src/parsers/v2/event/anchor/bubblegum.ts b/packages/explorerkit-translator/src/parsers/v2/event/anchor/bubblegum.ts index b46e433..a3abe14 100644 --- a/packages/explorerkit-translator/src/parsers/v2/event/anchor/bubblegum.ts +++ b/packages/explorerkit-translator/src/parsers/v2/event/anchor/bubblegum.ts @@ -78,8 +78,11 @@ export const createBubblegumEventParser: (_: IdlItem) => EventParserInterface = return null; } catch (error) { - console.error(error); - return null; + throw new Error(`Error parsing event data - ${eventData}`, { + cause: { + decoderError: error, + }, + }); } }; diff --git a/packages/explorerkit-translator/src/parsers/v2/event/anchor/spl-compression.ts b/packages/explorerkit-translator/src/parsers/v2/event/anchor/spl-compression.ts index 4957140..59cceeb 100644 --- a/packages/explorerkit-translator/src/parsers/v2/event/anchor/spl-compression.ts +++ b/packages/explorerkit-translator/src/parsers/v2/event/anchor/spl-compression.ts @@ -45,8 +45,12 @@ export const createSPLCompEventParser: (_: IdlItem) => EventParserInterface = (_ return null; } catch (error) { - console.error(error); - return null; + throw new Error(`Error parsing event data - ${eventData}`, { + cause: { + decoderError: error, + programId: _.programId, + }, + }); } }; diff --git a/packages/explorerkit-translator/src/parsers/v2/event/anchor/tcomp.ts b/packages/explorerkit-translator/src/parsers/v2/event/anchor/tcomp.ts index 45d1375..61a5bcb 100644 --- a/packages/explorerkit-translator/src/parsers/v2/event/anchor/tcomp.ts +++ b/packages/explorerkit-translator/src/parsers/v2/event/anchor/tcomp.ts @@ -34,8 +34,12 @@ export const createTCompEventParser: (idlItem: IdlItem) => EventParserInterface return null; } catch (error) { - console.error(error); - return null; + throw new Error(`Error parsing event data - ${eventData}`, { + cause: { + decoderError: error, + programId: idlItem.programId, + }, + }); } }; diff --git a/packages/explorerkit-translator/src/parsers/v2/event/shank.ts b/packages/explorerkit-translator/src/parsers/v2/event/shank.ts index 10e2c74..782e0f5 100644 --- a/packages/explorerkit-translator/src/parsers/v2/event/shank.ts +++ b/packages/explorerkit-translator/src/parsers/v2/event/shank.ts @@ -48,8 +48,12 @@ export const createShankEventParser: (idlItem: IdlItem) => EventParserInterface return null; } catch (error) { - console.error(error); - return null; + throw new Error(`Error parsing event data - ${eventData}`, { + cause: { + decoderError: error, + programId: idlItem.programId, + }, + }); } }; diff --git a/packages/explorerkit-translator/src/parsers/v2/event/shank/phoenix.ts b/packages/explorerkit-translator/src/parsers/v2/event/shank/phoenix.ts index 6ad30df..91968f2 100644 --- a/packages/explorerkit-translator/src/parsers/v2/event/shank/phoenix.ts +++ b/packages/explorerkit-translator/src/parsers/v2/event/shank/phoenix.ts @@ -88,8 +88,12 @@ export const createPhoenixEventParser: (idlItem: IdlItem) => EventParserInterfac return null; } catch (error) { - console.error(error); - return null; + throw new Error(`Error parsing event data - ${eventData}`, { + cause: { + decoderError: error, + programId: idlItem.programId, + }, + }); } }; diff --git a/packages/explorerkit-translator/src/parsers/v2/instruction/anchor-v1.ts b/packages/explorerkit-translator/src/parsers/v2/instruction/anchor-v1.ts index 1ae16e7..80c0369 100644 --- a/packages/explorerkit-translator/src/parsers/v2/instruction/anchor-v1.ts +++ b/packages/explorerkit-translator/src/parsers/v2/instruction/anchor-v1.ts @@ -75,8 +75,12 @@ export const createAnchorV1InstructionParser: (idlItem: IdlItem) => InstructionP return null; } catch (error) { - console.error(error); - return null; + throw new Error(`Error parsing instruction data - ${instructionData}`, { + cause: { + decoderError: error, + programId: idlItem.programId, + }, + }); } }; diff --git a/packages/explorerkit-translator/src/parsers/v2/instruction/anchor.ts b/packages/explorerkit-translator/src/parsers/v2/instruction/anchor.ts index 26c4b91..bde957c 100644 --- a/packages/explorerkit-translator/src/parsers/v2/instruction/anchor.ts +++ b/packages/explorerkit-translator/src/parsers/v2/instruction/anchor.ts @@ -71,8 +71,12 @@ export const createAnchorInstructionParser: (idlItem: IdlItem) => InstructionPar return null; } catch (error) { - console.error(error); - return null; + throw new Error(`Error parsing instruction data - ${instructionData}`, { + cause: { + decoderError: error, + programId: idlItem.programId, + }, + }); } }; diff --git a/packages/explorerkit-translator/src/parsers/v2/instruction/ata.ts b/packages/explorerkit-translator/src/parsers/v2/instruction/ata.ts index 7f6c7cc..2700ab6 100644 --- a/packages/explorerkit-translator/src/parsers/v2/instruction/ata.ts +++ b/packages/explorerkit-translator/src/parsers/v2/instruction/ata.ts @@ -72,8 +72,12 @@ export const createShankIxATA: (idlItem: IdlItem) => InstructionParserInterface return null; } catch (error) { - console.error(error); - return null; + throw new Error(`Error parsing instruction data - ${instructionData}`, { + cause: { + decoderError: error, + programId: idlItem.programId, + }, + }); } }; diff --git a/packages/explorerkit-translator/src/parsers/v2/instruction/config.ts b/packages/explorerkit-translator/src/parsers/v2/instruction/config.ts index 0d6bd82..ba64bd4 100644 --- a/packages/explorerkit-translator/src/parsers/v2/instruction/config.ts +++ b/packages/explorerkit-translator/src/parsers/v2/instruction/config.ts @@ -65,8 +65,12 @@ export const createShankIxConfig: (idlItem: IdlItem) => InstructionParserInterfa return null; } catch (error) { - console.error(error); - return null; + throw new Error(`Error parsing instruction data - ${instructionData}`, { + cause: { + decoderError: error, + programId: idlItem.programId, + }, + }); } }; diff --git a/packages/explorerkit-translator/src/parsers/v2/instruction/memo.ts b/packages/explorerkit-translator/src/parsers/v2/instruction/memo.ts index 2533a29..dfe1dd4 100644 --- a/packages/explorerkit-translator/src/parsers/v2/instruction/memo.ts +++ b/packages/explorerkit-translator/src/parsers/v2/instruction/memo.ts @@ -78,8 +78,12 @@ export const createShankIxMemo: (idlItem: IdlItem) => InstructionParserInterface return null; } catch (error) { - console.error(error); - return null; + throw new Error(`Error parsing instruction data - ${instructionData}`, { + cause: { + decoderError: error, + programId: idlItem.programId, + }, + }); } }; diff --git a/packages/explorerkit-translator/src/parsers/v2/instruction/noop.ts b/packages/explorerkit-translator/src/parsers/v2/instruction/noop.ts index 19df811..d862959 100644 --- a/packages/explorerkit-translator/src/parsers/v2/instruction/noop.ts +++ b/packages/explorerkit-translator/src/parsers/v2/instruction/noop.ts @@ -38,8 +38,12 @@ export const createNoopIx: (idlItem: IdlItem) => InstructionParserInterface = (i return null; } catch (error) { - console.error(error); - return null; + throw new Error(`Error parsing instruction data - ${instructionData}`, { + cause: { + decoderError: error, + programId: idlItem.programId, + }, + }); } }; diff --git a/packages/explorerkit-translator/src/parsers/v2/instruction/phoenix.ts b/packages/explorerkit-translator/src/parsers/v2/instruction/phoenix.ts index 4301589..af41cf0 100644 --- a/packages/explorerkit-translator/src/parsers/v2/instruction/phoenix.ts +++ b/packages/explorerkit-translator/src/parsers/v2/instruction/phoenix.ts @@ -67,8 +67,12 @@ export const createShankIxPhoenix: (idlItem: IdlItem) => InstructionParserInterf return null; } catch (error) { - console.error(error); - return null; + throw new Error(`Error parsing instruction data - ${instructionData}`, { + cause: { + decoderError: error, + programId: idlItem.programId, + }, + }); } }; diff --git a/packages/explorerkit-translator/src/parsers/v2/instruction/shank.ts b/packages/explorerkit-translator/src/parsers/v2/instruction/shank.ts index 08d70ef..854da90 100644 --- a/packages/explorerkit-translator/src/parsers/v2/instruction/shank.ts +++ b/packages/explorerkit-translator/src/parsers/v2/instruction/shank.ts @@ -57,8 +57,12 @@ export const createShankInstructionParser: (idlItem: IdlItem) => InstructionPars return null; } catch (error) { - console.error(error); - return null; + throw new Error(`Error parsing instruction data - ${instructionData}`, { + cause: { + decoderError: error, + programId: idlItem.programId, + }, + }); } }; diff --git a/packages/explorerkit-translator/src/parsers/v2/instruction/token-2022-extensions/transfer-fee.ts b/packages/explorerkit-translator/src/parsers/v2/instruction/token-2022-extensions/transfer-fee.ts index 2b1cb05..c9f9777 100644 --- a/packages/explorerkit-translator/src/parsers/v2/instruction/token-2022-extensions/transfer-fee.ts +++ b/packages/explorerkit-translator/src/parsers/v2/instruction/token-2022-extensions/transfer-fee.ts @@ -19,122 +19,131 @@ export const serializeTransferFeeExt = ( extensionIDL: Idl, dataBuffer: Uint8Array, mapTypes?: boolean, - accountKeys?: IdlAccountName[] + accountKeys?: string[] ): ExtensionTypes | null => { - const extensionSerializerLayout = new KinobiTreeGenerator(extensionIDL).constructLayout(); - const extensionIxDiscriminant = Buffer.from(dataBuffer).readUint8(1); - const extensionSerializer = extensionSerializerLayout.get(extensionIxDiscriminant); - - // This is to slice the initial discriminant from the parent token instruction data - const dataToSerialize = dataBuffer.slice(1); - - if (extensionSerializer) { - const decodedShankData = extensionSerializer.serializer?.deserialize(dataToSerialize); - - if (decodedShankData && decodedShankData[0]) { - const filteredIdlInstruction = extensionIDL.instructions?.filter( - (instruction) => instruction.discriminant?.value === extensionIxDiscriminant - ); - - if (mapTypes) { - decodedShankData[0] = mapDataTypeToName( - decodedShankData[0], - filteredIdlInstruction[0]?.args, - filteredIdlInstruction[0]?.discriminant + try { + const extensionSerializerLayout = new KinobiTreeGenerator(extensionIDL).constructLayout(); + const extensionIxDiscriminant = Buffer.from(dataBuffer).readUint8(1); + const extensionSerializer = extensionSerializerLayout.get(extensionIxDiscriminant); + + // This is to slice the initial discriminant from the parent token instruction data + const dataToSerialize = dataBuffer.slice(1); + + if (extensionSerializer) { + const decodedShankData = extensionSerializer.serializer?.deserialize(dataToSerialize); + + if (decodedShankData && decodedShankData[0]) { + const filteredIdlInstruction = extensionIDL.instructions?.filter( + (instruction) => instruction.discriminant?.value === extensionIxDiscriminant ); - } - if (filteredIdlInstruction.length > 0) { - const instructionAccounts = filteredIdlInstruction[0]?.accounts; - let mappedAccountKeys: DataWithMappedType; - switch (extensionIxDiscriminant) { - // Source: https://github.com/solana-labs/solana-program-library/commit/54938423994e7f4acfb7d7eacfef965a4409214b - // Enum 3 is WithdrawWithheldTokensFromAccounts with the following account structure: - // M has to be given to the function to account for the number of items in the double array - /// Accounts expected by this instruction: - /// - /// * Single owner/delegate - /// 0. `[]` The token mint. Must include the `TransferFeeConfig` extension. - /// 1. `[writable]` The fee receiver account. Must include the `TransferFeeAmount` - /// extension and be associated with the provided mint. - /// 2. `[signer]` The mint's `withdraw_withheld_authority`. - /// 3. ..3+N `[writable]` The source accounts to withdraw from. - /// - /// * Multisignature owner/delegate - /// 0. `[]` The token mint. - /// 1. `[writable]` The destination account. - /// 2. `[]` The mint's multisig `withdraw_withheld_authority`. - /// 3. ..3+M `[signer]` M signer accounts. - /// 3+M+1. ..3+M+N `[writable]` The source accounts to withdraw from. - case 3: - if (accountKeys && accountKeys.length > 3 && instructionAccounts) { - const numberOfTokenAccounts = decodedShankData[0].numTokenAccounts.data; - const [tokenMint, destination, authority] = [accountKeys[0], accountKeys[1], accountKeys[2]]; - const sources = accountKeys.splice(-1 * numberOfTokenAccounts); - const names: (IdlAccountName | IdlAccountName[])[] = []; - let signers: IdlAccountName[] = []; - - // So if account keys still has more than 3 keys, this means that there's more than - // 1 signers since token account sources has been spliced - if (accountKeys.length > 3) { - signers = accountKeys.splice(3); - } + if (mapTypes) { + decodedShankData[0] = mapDataTypeToName( + decodedShankData[0], + filteredIdlInstruction[0]?.args, + filteredIdlInstruction[0]?.discriminant + ); + } - // Populate the names array with the account names - instructionAccounts.forEach((idlIxAccount) => { - names.push(extractIdlIxAccountName(idlIxAccount) ?? { name: "Unknown" }); - }); - - // Flatten the names array and create an empty object to store the translated account keys - // This is flatten due to the fact that there's a possibility of nested arrays such as Zeta Program - const flattenNames = names.flat(5); - let toCopy: DataWithMappedType = { - [flattenNames[0]?.name as string]: { data: tokenMint ?? accountKeys[0]!, type: "publicKey" }, - [flattenNames[1]?.name as string]: { data: destination ?? accountKeys[1]!, type: "publicKey" }, - [flattenNames[2]?.name as string]: { data: authority ?? accountKeys[2]!, type: "publicKey" }, - }; - - signers.forEach((signerAccountKey, index) => { - const object: DataWithMappedType = { - [`signer` + (index + 1)]: { data: signerAccountKey, type: "publicKey" }, + if (filteredIdlInstruction.length > 0) { + const instructionAccounts = filteredIdlInstruction[0]?.accounts; + let mappedAccountKeys: DataWithMappedType; + switch (extensionIxDiscriminant) { + // Source: https://github.com/solana-labs/solana-program-library/commit/54938423994e7f4acfb7d7eacfef965a4409214b + // Enum 3 is WithdrawWithheldTokensFromAccounts with the following account structure: + // M has to be given to the function to account for the number of items in the double array + /// Accounts expected by this instruction: + /// + /// * Single owner/delegate + /// 0. `[]` The token mint. Must include the `TransferFeeConfig` extension. + /// 1. `[writable]` The fee receiver account. Must include the `TransferFeeAmount` + /// extension and be associated with the provided mint. + /// 2. `[signer]` The mint's `withdraw_withheld_authority`. + /// 3. ..3+N `[writable]` The source accounts to withdraw from. + /// + /// * Multisignature owner/delegate + /// 0. `[]` The token mint. + /// 1. `[writable]` The destination account. + /// 2. `[]` The mint's multisig `withdraw_withheld_authority`. + /// 3. ..3+M `[signer]` M signer accounts. + /// 3+M+1. ..3+M+N `[writable]` The source accounts to withdraw from. + case 3: + if (accountKeys && accountKeys.length > 3 && instructionAccounts) { + const numberOfTokenAccounts = decodedShankData[0].numTokenAccounts.data; + const [tokenMint, destination, authority] = [accountKeys[0], accountKeys[1], accountKeys[2]]; + const sources = accountKeys.splice(-1 * numberOfTokenAccounts); + const names: (IdlAccountName | IdlAccountName[])[] = []; + let signers: string[] = []; + + // So if account keys still has more than 3 keys, this means that there's more than + // 1 signers since token account sources has been spliced + if (accountKeys.length > 3) { + signers = accountKeys.splice(3); + } + + // Populate the names array with the account names + instructionAccounts.forEach((idlIxAccount) => { + names.push(extractIdlIxAccountName(idlIxAccount) ?? { name: "Unknown" }); + }); + + // Flatten the names array and create an empty object to store the translated account keys + // This is flatten due to the fact that there's a possibility of nested arrays such as Zeta Program + const flattenNames = names.flat(5); + let toCopy: DataWithMappedType = { + [flattenNames[0]?.name as string]: { data: tokenMint ?? accountKeys[0]!, type: "publicKey" }, + [flattenNames[1]?.name as string]: { data: destination ?? accountKeys[1]!, type: "publicKey" }, + [flattenNames[2]?.name as string]: { data: authority ?? accountKeys[2]!, type: "publicKey" }, }; - toCopy = Object.assign(toCopy, object); - }); - sources.forEach((sourceAccountKey, index) => { - const object: DataWithMappedType = { - [`sourceAccount` + (index + 1)]: { data: sourceAccountKey, type: "publicKey" }, - }; + signers.forEach((signerAccountKey, index) => { + const object: DataWithMappedType = { + [`signer` + (index + 1)]: { data: signerAccountKey, type: "publicKey" }, + }; - toCopy = Object.assign(toCopy, object); - }); + toCopy = Object.assign(toCopy, object); + }); + sources.forEach((sourceAccountKey, index) => { + const object: DataWithMappedType = { + [`sourceAccount` + (index + 1)]: { data: sourceAccountKey, type: "publicKey" }, + }; - mappedAccountKeys = toCopy; - } else { - mappedAccountKeys = mapMultisigAccountKeysToName(accountKeys, instructionAccounts); - } - break; + toCopy = Object.assign(toCopy, object); + }); + + mappedAccountKeys = toCopy; + } else { + mappedAccountKeys = mapMultisigAccountKeysToName(accountKeys, instructionAccounts); + } + break; - case 4: - mappedAccountKeys = mapMultisigAccountKeysToName(accountKeys, instructionAccounts, "source"); - break; + case 4: + mappedAccountKeys = mapMultisigAccountKeysToName(accountKeys, instructionAccounts, "source"); + break; - default: - mappedAccountKeys = mapMultisigAccountKeysToName(accountKeys, instructionAccounts); - break; + default: + mappedAccountKeys = mapMultisigAccountKeysToName(accountKeys, instructionAccounts); + break; + } + + return { + extensionInstructionName: extensionSerializer.instructionName, + extensionInstructionData: { ...convertBNToNumberInObject(decodedShankData[0]), ...mappedAccountKeys }, + }; } return { extensionInstructionName: extensionSerializer.instructionName, - extensionInstructionData: { ...convertBNToNumberInObject(decodedShankData[0]), ...mappedAccountKeys }, + extensionInstructionData: convertBNToNumberInObject(decodedShankData[0]), }; } - - return { - extensionInstructionName: extensionSerializer.instructionName, - extensionInstructionData: convertBNToNumberInObject(decodedShankData[0]), - }; } + } catch (error) { + throw new Error(`Error parsing instruction data - ${Buffer.from(dataBuffer).toString("base64")}`, { + cause: { + decoderError: error, + programId: extensionIDL.metadata.address ?? "", + }, + }); } return null; diff --git a/packages/explorerkit-translator/src/parsers/v2/instruction/token-v2.ts b/packages/explorerkit-translator/src/parsers/v2/instruction/token-v2.ts index 2fcefac..72892ed 100644 --- a/packages/explorerkit-translator/src/parsers/v2/instruction/token-v2.ts +++ b/packages/explorerkit-translator/src/parsers/v2/instruction/token-v2.ts @@ -345,8 +345,12 @@ export const createTokenV2Ix: (idlItem: IdlItem) => InstructionParserInterface = return null; } catch (error) { - console.error(error); - return null; + throw new Error(`Error parsing instruction data - ${instructionData}`, { + cause: { + decoderError: error, + programId: idlItem.programId, + }, + }); } };