UNPKG

@gorbchain-xyz/chaindecode

Version:

GorbchainSDK V1.3+ - Complete Solana development toolkit with advanced cryptography, messaging, and collaboration features. Build secure applications with blockchain, DeFi, and end-to-end encryption.

525 lines (524 loc) 19.5 kB
// SPL Token Instruction Types (discriminators) export var SPLTokenInstruction; (function (SPLTokenInstruction) { SPLTokenInstruction[SPLTokenInstruction["InitializeMint"] = 0] = "InitializeMint"; SPLTokenInstruction[SPLTokenInstruction["InitializeAccount"] = 1] = "InitializeAccount"; SPLTokenInstruction[SPLTokenInstruction["InitializeMultisig"] = 2] = "InitializeMultisig"; SPLTokenInstruction[SPLTokenInstruction["Transfer"] = 3] = "Transfer"; SPLTokenInstruction[SPLTokenInstruction["Approve"] = 4] = "Approve"; SPLTokenInstruction[SPLTokenInstruction["Revoke"] = 5] = "Revoke"; SPLTokenInstruction[SPLTokenInstruction["SetAuthority"] = 6] = "SetAuthority"; SPLTokenInstruction[SPLTokenInstruction["MintTo"] = 7] = "MintTo"; SPLTokenInstruction[SPLTokenInstruction["Burn"] = 8] = "Burn"; SPLTokenInstruction[SPLTokenInstruction["CloseAccount"] = 9] = "CloseAccount"; SPLTokenInstruction[SPLTokenInstruction["FreezeAccount"] = 10] = "FreezeAccount"; SPLTokenInstruction[SPLTokenInstruction["ThawAccount"] = 11] = "ThawAccount"; SPLTokenInstruction[SPLTokenInstruction["TransferChecked"] = 12] = "TransferChecked"; SPLTokenInstruction[SPLTokenInstruction["ApproveChecked"] = 13] = "ApproveChecked"; SPLTokenInstruction[SPLTokenInstruction["MintToChecked"] = 14] = "MintToChecked"; SPLTokenInstruction[SPLTokenInstruction["BurnChecked"] = 15] = "BurnChecked"; SPLTokenInstruction[SPLTokenInstruction["InitializeAccount2"] = 16] = "InitializeAccount2"; SPLTokenInstruction[SPLTokenInstruction["SyncNative"] = 17] = "SyncNative"; SPLTokenInstruction[SPLTokenInstruction["InitializeAccount3"] = 18] = "InitializeAccount3"; SPLTokenInstruction[SPLTokenInstruction["InitializeMultisig2"] = 19] = "InitializeMultisig2"; SPLTokenInstruction[SPLTokenInstruction["InitializeMint2"] = 20] = "InitializeMint2"; })(SPLTokenInstruction || (SPLTokenInstruction = {})); // Authority Types export var AuthorityType; (function (AuthorityType) { AuthorityType[AuthorityType["MintTokens"] = 0] = "MintTokens"; AuthorityType[AuthorityType["FreezeAccount"] = 1] = "FreezeAccount"; AuthorityType[AuthorityType["AccountOwner"] = 2] = "AccountOwner"; AuthorityType[AuthorityType["CloseAccount"] = 3] = "CloseAccount"; })(AuthorityType || (AuthorityType = {})); /** * Main SPL Token decoder function */ export function decodeSPLTokenInstruction(instruction) { const data = instruction.data; if (!data || data.length === 0) { throw new Error('Invalid SPL Token instruction: no data'); } const instructionType = data[0]; const programId = instruction.programId; switch (instructionType) { case SPLTokenInstruction.Transfer: return decodeTransfer(instruction, programId); case SPLTokenInstruction.MintTo: return decodeMintTo(instruction, programId); case SPLTokenInstruction.Burn: return decodeBurn(instruction, programId); case SPLTokenInstruction.InitializeMint: return decodeInitializeMint(instruction, programId); case SPLTokenInstruction.InitializeAccount: return decodeInitializeAccount(instruction, programId); case SPLTokenInstruction.SetAuthority: return decodeSetAuthority(instruction, programId); case SPLTokenInstruction.Approve: return decodeApprove(instruction, programId); case SPLTokenInstruction.Revoke: return decodeRevoke(instruction, programId); case SPLTokenInstruction.CloseAccount: return decodeCloseAccount(instruction, programId); case SPLTokenInstruction.FreezeAccount: return decodeFreezeAccount(instruction, programId); case SPLTokenInstruction.ThawAccount: return decodeThawAccount(instruction, programId); case SPLTokenInstruction.TransferChecked: return decodeTransferChecked(instruction, programId); case SPLTokenInstruction.ApproveChecked: return decodeApproveChecked(instruction, programId); case SPLTokenInstruction.MintToChecked: return decodeMintToChecked(instruction, programId); case SPLTokenInstruction.BurnChecked: return decodeBurnChecked(instruction, programId); case SPLTokenInstruction.SyncNative: return decodeSyncNative(instruction, programId); default: return { type: 'spl-token-unknown', programId, data: { instructionType, error: `Unknown SPL Token instruction type: ${instructionType}` }, accounts: instruction.accounts, raw: instruction }; } } /** * Enhanced SPL Token instruction decoder with amount extraction */ export function decodeSPLTokenInstructionWithDetails(data) { if (data.length === 0) { return { type: 'spl-token-unknown', instruction: 'Unknown SPL Token instruction', accounts: [] }; } const instructionType = data[0]; switch (instructionType) { case 3: // Transfer if (data.length >= 9) { const amount = new DataView(data.buffer, data.byteOffset + 1, 8).getBigUint64(0, true); return { type: 'spl-token-transfer', instruction: 'Transfer tokens', amount, accounts: [] }; } break; case 7: // MintTo if (data.length >= 9) { const amount = new DataView(data.buffer, data.byteOffset + 1, 8).getBigUint64(0, true); return { type: 'spl-token-mint-to', instruction: 'Mint tokens', amount, accounts: [] }; } break; case 8: // Burn if (data.length >= 9) { const amount = new DataView(data.buffer, data.byteOffset + 1, 8).getBigUint64(0, true); return { type: 'spl-token-burn', instruction: 'Burn tokens', amount, accounts: [] }; } break; case 4: // Approve if (data.length >= 9) { const amount = new DataView(data.buffer, data.byteOffset + 1, 8).getBigUint64(0, true); return { type: 'spl-token-approve', instruction: 'Approve token spending', amount, accounts: [] }; } break; case 5: // Revoke return { type: 'spl-token-revoke', instruction: 'Revoke token approval', accounts: [] }; case 9: // CloseAccount return { type: 'spl-token-close-account', instruction: 'Close token account', accounts: [] }; case 10: // FreezeAccount return { type: 'spl-token-freeze-account', instruction: 'Freeze token account', accounts: [] }; case 11: // ThawAccount return { type: 'spl-token-thaw-account', instruction: 'Thaw token account', accounts: [] }; case 0: // InitializeMint if (data.length >= 51) { const decimals = data[1]; return { type: 'spl-token-initialize-mint', instruction: `Initialize mint with ${decimals} decimals`, decimals, accounts: [] }; } break; case 1: // InitializeAccount return { type: 'spl-token-initialize-account', instruction: 'Initialize token account', accounts: [] }; default: return { type: 'spl-token-unknown', instruction: `Unknown SPL Token instruction (type: ${instructionType})`, accounts: [] }; } return { type: 'spl-token-unknown', instruction: 'Unknown SPL Token instruction', accounts: [] }; } /** * Decode base58 instruction data to Uint8Array */ export function decodeInstructionData(base58Data) { try { // Simple base58 decode - in production use proper base58 library const bytes = new Uint8Array(Buffer.from(base58Data, 'base64')); return bytes; } catch (error) { // Failed to decode instruction data - return empty array return new Uint8Array(0); } } /** * Decode Transfer instruction (3) * Layout: [u8 instruction, u64 amount] */ function decodeTransfer(instruction, programId) { var _a, _b, _c; const data = instruction.data; if (data.length !== 9) { throw new Error('Invalid Transfer instruction data length'); } const amount = readU64LE(data, 1); const accounts = instruction.accounts; return { type: 'spl-token-transfer', programId, data: { amount: amount.toString(), source: (_a = accounts[0]) !== null && _a !== void 0 ? _a : null, destination: (_b = accounts[1]) !== null && _b !== void 0 ? _b : null, authority: (_c = accounts[2]) !== null && _c !== void 0 ? _c : null, signers: accounts.slice(3) }, accounts, raw: instruction }; } /** * Decode MintTo instruction (7) * Layout: [u8 instruction, u64 amount] */ function decodeMintTo(instruction, programId) { var _a, _b, _c; const data = instruction.data; if (data.length !== 9) { throw new Error('Invalid MintTo instruction data length'); } const amount = readU64LE(data, 1); const accounts = instruction.accounts; return { type: 'spl-token-mint-to', programId, data: { amount: amount.toString(), mint: (_a = accounts[0]) !== null && _a !== void 0 ? _a : null, account: (_b = accounts[1]) !== null && _b !== void 0 ? _b : null, authority: (_c = accounts[2]) !== null && _c !== void 0 ? _c : null, signers: accounts.slice(3) }, accounts, raw: instruction }; } /** * Decode Burn instruction (8) * Layout: [u8 instruction, u64 amount] */ function decodeBurn(instruction, programId) { var _a, _b, _c, _d; const data = instruction.data; if (data.length !== 9) { throw new Error('Invalid Burn instruction data length'); } const amount = readU64LE(data, 1); const accounts = (_a = instruction.accounts) !== null && _a !== void 0 ? _a : []; return { type: 'spl-token-burn', programId, data: { amount: amount.toString(), account: (_b = accounts[0]) !== null && _b !== void 0 ? _b : null, mint: (_c = accounts[1]) !== null && _c !== void 0 ? _c : null, authority: (_d = accounts[2]) !== null && _d !== void 0 ? _d : null, signers: accounts.slice(3) }, accounts, raw: instruction }; } /** * Decode InitializeMint instruction (0) * Layout: [u8 instruction, u8 decimals, [u8; 32] mint_authority, Option<[u8; 32]> freeze_authority] */ function decodeInitializeMint(instruction, programId) { var _a; const data = instruction.data; if (data.length !== 67) { throw new Error('Invalid InitializeMint instruction data length'); } const decimals = data[1]; const mintAuthority = data.slice(2, 34); const freezeAuthorityOption = data[34]; const freezeAuthority = freezeAuthorityOption ? data.slice(35, 67) : null; return { type: 'spl-token-initialize-mint', programId, data: { decimals, mintAuthority: bufferToBase58(mintAuthority), freezeAuthority: freezeAuthority ? bufferToBase58(freezeAuthority) : null }, accounts: (_a = instruction.accounts) !== null && _a !== void 0 ? _a : [], raw: instruction }; } /** * Decode InitializeAccount instruction (1) */ function decodeInitializeAccount(instruction, programId) { var _a, _b, _c, _d, _e, _f, _g, _h, _j; const accounts = (_a = instruction.accounts) !== null && _a !== void 0 ? _a : []; return { type: 'spl-token-initialize-account', programId, data: { account: (_c = (_b = accounts[0]) === null || _b === void 0 ? void 0 : _b.address) !== null && _c !== void 0 ? _c : accounts[0], mint: (_e = (_d = accounts[1]) === null || _d === void 0 ? void 0 : _d.address) !== null && _e !== void 0 ? _e : accounts[1], owner: (_g = (_f = accounts[2]) === null || _f === void 0 ? void 0 : _f.address) !== null && _g !== void 0 ? _g : accounts[2], rentSysvar: (_j = (_h = accounts[3]) === null || _h === void 0 ? void 0 : _h.address) !== null && _j !== void 0 ? _j : accounts[3] }, accounts, raw: instruction }; } /** * Decode SetAuthority instruction (6) * Layout: [u8 instruction, u8 authority_type, Option<[u8; 32]> new_authority] */ function decodeSetAuthority(instruction, programId) { var _a; const data = instruction.data; if (data.length !== 35) { throw new Error('Invalid SetAuthority instruction data length'); } const authorityType = data[1]; const newAuthorityOption = data[2]; const newAuthority = newAuthorityOption ? data.slice(3, 35) : null; return { type: 'spl-token-set-authority', programId, data: { authorityType: getAuthorityTypeName(authorityType), newAuthority: newAuthority ? bufferToBase58(newAuthority) : null }, accounts: (_a = instruction.accounts) !== null && _a !== void 0 ? _a : [], raw: instruction }; } /** * Decode other instructions with simple layouts */ function decodeApprove(instruction, programId) { var _a, _b, _c; const data = instruction.data; const amount = readU64LE(data, 1); const accounts = instruction.accounts; return { type: 'spl-token-approve', programId, data: { amount: amount.toString(), source: (_a = accounts[0]) !== null && _a !== void 0 ? _a : null, // Token account delegate: (_b = accounts[1]) !== null && _b !== void 0 ? _b : null, // Delegate account authority: (_c = accounts[2]) !== null && _c !== void 0 ? _c : null, // Authority (owner) signers: accounts.slice(3) }, accounts, raw: instruction }; } function decodeRevoke(instruction, programId) { var _a; return { type: 'spl-token-revoke', programId, data: {}, accounts: (_a = instruction.accounts) !== null && _a !== void 0 ? _a : [], raw: instruction }; } function decodeCloseAccount(instruction, programId) { var _a; return { type: 'spl-token-close-account', programId, data: {}, accounts: (_a = instruction.accounts) !== null && _a !== void 0 ? _a : [], raw: instruction }; } function decodeFreezeAccount(instruction, programId) { var _a; return { type: 'spl-token-freeze-account', programId, data: {}, accounts: (_a = instruction.accounts) !== null && _a !== void 0 ? _a : [], raw: instruction }; } function decodeThawAccount(instruction, programId) { var _a; return { type: 'spl-token-thaw-account', programId, data: {}, accounts: (_a = instruction.accounts) !== null && _a !== void 0 ? _a : [], raw: instruction }; } function decodeTransferChecked(instruction, programId) { var _a; const data = instruction.data; const amount = readU64LE(data, 1); const decimals = data[9]; return { type: 'spl-token-transfer-checked', programId, data: { amount: amount.toString(), decimals }, accounts: (_a = instruction.accounts) !== null && _a !== void 0 ? _a : [], raw: instruction }; } function decodeApproveChecked(instruction, programId) { var _a; const data = instruction.data; const amount = readU64LE(data, 1); const decimals = data[9]; return { type: 'spl-token-approve-checked', programId, data: { amount: amount.toString(), decimals }, accounts: (_a = instruction.accounts) !== null && _a !== void 0 ? _a : [], raw: instruction }; } function decodeMintToChecked(instruction, programId) { var _a; const data = instruction.data; const amount = readU64LE(data, 1); const decimals = data[9]; return { type: 'spl-token-mint-to-checked', programId, data: { amount: amount.toString(), decimals }, accounts: (_a = instruction.accounts) !== null && _a !== void 0 ? _a : [], raw: instruction }; } function decodeBurnChecked(instruction, programId) { var _a; const data = instruction.data; const amount = readU64LE(data, 1); const decimals = data[9]; return { type: 'spl-token-burn-checked', programId, data: { amount: amount.toString(), decimals }, accounts: (_a = instruction.accounts) !== null && _a !== void 0 ? _a : [], raw: instruction }; } function decodeSyncNative(instruction, programId) { var _a; return { type: 'spl-token-sync-native', programId, data: {}, accounts: (_a = instruction.accounts) !== null && _a !== void 0 ? _a : [], raw: instruction }; } // Utility functions function readU64LE(buffer, offset) { // Read 64-bit little-endian integer as string to avoid BigInt requirement let result = 0; let multiplier = 1; // Read the lower 32 bits for (let i = 0; i < 4; i++) { result += buffer[offset + i] * multiplier; multiplier *= 256; } // For simplicity, ignore the upper 32 bits if they would cause overflow // In production, you'd want proper 64-bit integer handling let upper = 0; multiplier = 1; for (let i = 4; i < 8; i++) { upper += buffer[offset + i] * multiplier; multiplier *= 256; } // Combine lower and upper parts, handling overflow by returning as string const total = result + (upper * Math.pow(2, 32)); return total.toString(); } function bufferToBase58(buffer) { // Simplified base58 encoding - in production, use a proper base58 library // For now, return hex representation return Array.from(buffer).map((b) => { const hex = b.toString(16); return hex.length === 1 ? `0${hex}` : hex; }).join(''); } function getAuthorityTypeName(type) { switch (type) { case AuthorityType.MintTokens: return 'MintTokens'; case AuthorityType.FreezeAccount: return 'FreezeAccount'; case AuthorityType.AccountOwner: return 'AccountOwner'; case AuthorityType.CloseAccount: return 'CloseAccount'; default: return `Unknown(${type})`; } }