UNPKG

solana-token-extension-boost

Version:

SDK for Solana Token Extensions with wallet adapter support

171 lines (170 loc) 5.86 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ExtensionTypeString = exports.ExtensionTypeByte = exports.EXTENSION_TYPES = void 0; exports.getExtensionName = getExtensionName; exports.isToken2022 = isToken2022; exports.getTokenInfo = getTokenInfo; exports.getOptimalInitializationOrder = getOptimalInitializationOrder; const spl_token_1 = require("@solana/spl-token"); exports.EXTENSION_TYPES = { TransferFeeConfig: 0, TransferFeeAmount: 1, MintCloseAuthority: 2, ConfidentialTransferMint: 3, ConfidentialTransferAccount: 4, DefaultAccountState: 5, ImmutableOwner: 6, MemoTransfer: 7, NonTransferable: 8, InterestBearingConfig: 9, CpiGuard: 10, PermanentDelegate: 11, NonTransferableAccount: 12, TransferHook: 13, MetadataPointer: 14, TokenMetadata: 15 }; exports.ExtensionTypeByte = { TransferFeeConfig: 0, TransferFeeAmount: 1, MintCloseAuthority: 2, ConfidentialTransferMint: 3, ConfidentialTransferAccount: 4, DefaultAccountState: 5, ImmutableOwner: 6, MemoTransfer: 7, NonTransferable: 8, InterestBearingConfig: 9, CpiGuard: 10, PermanentDelegate: 11, NonTransferableAccount: 12, TransferHook: 13, MetadataPointer: 14, TokenMetadata: 15, GroupPointer: 20, MemberPointer: 21, }; exports.ExtensionTypeString = { 0: "TransferFee (Config)", 1: "TransferFee (Amount)", 2: "MintCloseAuthority", 3: "ConfidentialTransfer (Mint)", 4: "ConfidentialTransfer (Account)", 5: "DefaultAccountState", 6: "ImmutableOwner", 7: "MemoTransfer", 8: "NonTransferable", 9: "InterestBearing", 10: "CpiGuard", 11: "PermanentDelegate", 12: "NonTransferableAccount", 13: "TransferHook", 14: "MetadataPointer", 15: "TokenMetadata", 20: "GroupPointer", 21: "MemberPointer", }; function getExtensionName(type) { const names = { 0: "TransferFee (Config)", 1: "TransferFee (Amount)", 2: "MintCloseAuthority", 3: "ConfidentialTransfer (Mint)", 4: "ConfidentialTransfer (Account)", 5: "DefaultAccountState", 6: "ImmutableOwner", 7: "MemoTransfer", 8: "NonTransferable", 9: "InterestBearing", 10: "CpiGuard", 11: "PermanentDelegate", 12: "NonTransferableAccount", 13: "TransferHook", 14: "MetadataPointer", 15: "TokenMetadata", }; return names[type] || `Unknown Extension (${type})`; } async function isToken2022(connection, mint) { try { const accountInfo = await connection.getAccountInfo(mint); if (!accountInfo) { return false; } return accountInfo.owner.equals(spl_token_1.TOKEN_2022_PROGRAM_ID); } catch (error) { return false; } } async function getTokenInfo(connection, mint) { const isProgramToken2022 = await isToken2022(connection, mint); if (!isProgramToken2022) { return { isProgramToken2022, extensions: [] }; } try { const mintInfo = await (0, spl_token_1.getMint)(connection, mint, "confirmed", spl_token_1.TOKEN_2022_PROGRAM_ID); let extensions = []; if (mintInfo.tlvData) { // Check extensions manually by reading data from tlvData // This is a simplified way to avoid type errors Object.entries(exports.EXTENSION_TYPES).forEach(([name, id]) => { extensions.push({ type: id, name: getExtensionName(id), // We simply check for the presence of extension by tlvData size // In reality, more complex logic is needed to check each extension precisely present: mintInfo.tlvData.length > 0 }); }); } return { isProgramToken2022, extensions }; } catch (error) { return { isProgramToken2022, extensions: [] }; } } /** * Find the optimal initialization order for extensions * Some extensions must be initialized before the mint, others must be after. * * @param extensionTypes - Array of extension types to sort * @returns Sorted array in optimal order */ function getOptimalInitializationOrder(extensionTypes) { // Some extensions must be initialized before the mint const beforeMintInit = [ spl_token_1.ExtensionType.MintCloseAuthority, spl_token_1.ExtensionType.TransferFeeConfig, spl_token_1.ExtensionType.ConfidentialTransferMint, spl_token_1.ExtensionType.DefaultAccountState, spl_token_1.ExtensionType.MetadataPointer, // Important: MetadataPointer must be initialized before mint spl_token_1.ExtensionType.TokenMetadata, // If using TokenMetadata directly instead of MetadataPointer spl_token_1.ExtensionType.NonTransferable ]; // Some extensions must be initialized after the mint const afterMintInit = [ spl_token_1.ExtensionType.TransferHook, spl_token_1.ExtensionType.InterestBearingConfig, spl_token_1.ExtensionType.CpiGuard, spl_token_1.ExtensionType.PermanentDelegate, spl_token_1.ExtensionType.NonTransferableAccount ]; // Sort extensions in optimal order const beforeMint = []; const afterMint = []; for (const extensionType of extensionTypes) { if (beforeMintInit.includes(extensionType)) { beforeMint.push(extensionType); } else if (afterMintInit.includes(extensionType)) { afterMint.push(extensionType); } else { // Default: add before mint initialization beforeMint.push(extensionType); } } // Return sorted array with before-mint extensions first return [...beforeMint, ...afterMint]; }