UNPKG

solana-token-extension-boost

Version:

SDK for Solana Token Extensions with wallet adapter support

243 lines (242 loc) 10.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.CpiGuardExtension = void 0; exports.createInitializeCpiGuardInstruction = createInitializeCpiGuardInstruction; const web3_js_1 = require("@solana/web3.js"); const spl_token_1 = require("@solana/spl-token"); /** * Create instruction to initialize CPI Guard for mint * @param mint - Mint address * @param authority - (Optional) Authority address that can enable/disable CPI Guard * @param programId - Token Extension Program ID * @returns Instruction to initialize CPI Guard */ function createInitializeCpiGuardInstruction(mint, authority = null, programId = spl_token_1.TOKEN_2022_PROGRAM_ID) { const keys = [ { pubkey: mint, isSigner: false, isWritable: true }, ]; if (authority) { keys.push({ pubkey: authority, isSigner: false, isWritable: false }); } return new web3_js_1.TransactionInstruction({ programId, keys, data: Buffer.from([ spl_token_1.ExtensionType.CpiGuard & 0xff, (spl_token_1.ExtensionType.CpiGuard >> 8) & 0xff, (spl_token_1.ExtensionType.CpiGuard >> 16) & 0xff, (spl_token_1.ExtensionType.CpiGuard >> 24) & 0xff, authority ? 1 : 0 // 1 if authority is provided, 0 otherwise ]), }); } /** * Class for protection against CPI attacks */ class CpiGuardExtension { /** * Create a new CpiGuardExtension instance * @param connection - Connection to Solana cluster * @param mint - Mint address */ constructor(connection, mint) { this.connection = connection; this.mint = mint; } /** * Create instruction to initialize CPI Guard for mint * @param mint - Mint address * @param authority - (Optional) Authority address that can enable/disable CPI Guard * @param programId - Token Extension Program ID * @returns Instruction to initialize CPI Guard */ static createInitializeCpiGuardInstruction(mint, authority = null, programId = spl_token_1.TOKEN_2022_PROGRAM_ID) { return createInitializeCpiGuardInstruction(mint, authority, programId); } /** * Create instruction to enable CPI Guard for a mint * @param mint - Mint address * @param authority - Authority address that can enable/disable CPI Guard * @param programId - Token Extension Program ID * @returns Instruction to enable CPI Guard */ static createEnableCpiGuardInstruction(mint, authority, programId = spl_token_1.TOKEN_2022_PROGRAM_ID) { return new web3_js_1.TransactionInstruction({ programId, keys: [ { pubkey: mint, isSigner: false, isWritable: true }, { pubkey: authority, isSigner: true, isWritable: false } ], data: Buffer.from([ spl_token_1.ExtensionType.CpiGuard & 0xff, (spl_token_1.ExtensionType.CpiGuard >> 8) & 0xff, (spl_token_1.ExtensionType.CpiGuard >> 16) & 0xff, (spl_token_1.ExtensionType.CpiGuard >> 24) & 0xff, 1 // Enable CPI Guard ]), }); } /** * Create instruction to disable CPI Guard for a mint * @param mint - Mint address * @param authority - Authority address that can enable/disable CPI Guard * @param programId - Token Extension Program ID * @returns Instruction to disable CPI Guard */ static createDisableCpiGuardInstruction(mint, authority, programId = spl_token_1.TOKEN_2022_PROGRAM_ID) { return new web3_js_1.TransactionInstruction({ programId, keys: [ { pubkey: mint, isSigner: false, isWritable: true }, { pubkey: authority, isSigner: true, isWritable: false } ], data: Buffer.from([ spl_token_1.ExtensionType.CpiGuard & 0xff, (spl_token_1.ExtensionType.CpiGuard >> 8) & 0xff, (spl_token_1.ExtensionType.CpiGuard >> 16) & 0xff, (spl_token_1.ExtensionType.CpiGuard >> 24) & 0xff, 0 // Disable CPI Guard ]), }); } /** * Check if CPI Guard is enabled for a mint * @param connection - Connection to Solana cluster * @param mint - Mint address * @param programId - Token Extension Program ID * @returns Promise resolving to boolean indicating if CPI Guard is enabled */ static async isCpiGuardEnabled(connection, mint, programId = spl_token_1.TOKEN_2022_PROGRAM_ID) { try { const mintInfo = await (0, spl_token_1.getMint)(connection, mint, 'confirmed', programId); // Check the TLV data for CPI Guard extension if (mintInfo.tlvData) { let offset = 0; while (offset < mintInfo.tlvData.length) { if (offset + 8 > mintInfo.tlvData.length) break; const type = mintInfo.tlvData.readUInt32LE(offset); const length = mintInfo.tlvData.readUInt32LE(offset + 4); if (type === spl_token_1.ExtensionType.CpiGuard) { // CPI Guard found, check if it's enabled if (offset + 8 + length > mintInfo.tlvData.length) break; return mintInfo.tlvData.readUInt8(offset + 8) === 1; } offset += 8 + length; } } return false; // CPI Guard not found or not enabled } catch (error) { console.error('Error checking CPI Guard status:', error); return false; } } /** * Get CPI Guard authority for a mint * @param connection - Connection to Solana cluster * @param mint - Mint address * @param programId - Token Extension Program ID * @returns Promise resolving to the authority public key or null if no authority */ static async getCpiGuardAuthority(connection, mint, programId = spl_token_1.TOKEN_2022_PROGRAM_ID) { try { const mintInfo = await (0, spl_token_1.getMint)(connection, mint, 'confirmed', programId); // Check the TLV data for CPI Guard extension if (mintInfo.tlvData) { let offset = 0; while (offset < mintInfo.tlvData.length) { if (offset + 8 > mintInfo.tlvData.length) break; const type = mintInfo.tlvData.readUInt32LE(offset); const length = mintInfo.tlvData.readUInt32LE(offset + 4); if (type === spl_token_1.ExtensionType.CpiGuard) { // CPI Guard found, check if it has an authority if (offset + 8 + length > mintInfo.tlvData.length) break; if (length >= 33) { // Authority is present const authorityBytes = mintInfo.tlvData.slice(offset + 9, offset + 9 + 32); return new web3_js_1.PublicKey(authorityBytes); } return null; // No authority } offset += 8 + length; } } return null; // CPI Guard not found } catch (error) { console.error('Error getting CPI Guard authority:', error); return null; } } /** * Create instructions to create a new token with CPI Guard * @param connection - Connection to Solana cluster * @param payer - Public key of the fee payer * @param mintAuthority - Mint authority * @param decimals - Number of decimals * @param cpiGuardAuthority - (Optional) Authority that can enable/disable CPI Guard * @returns Instructions, signers, and mint address */ static async createTokenWithCpiGuardInstructions(connection, payer, mintAuthority, decimals, cpiGuardAuthority) { // Generate a new keypair for the mint const mintKeypair = web3_js_1.Keypair.generate(); const mint = mintKeypair.publicKey; // Calculate the space needed for the mint with CPI Guard extension const mintLen = (0, spl_token_1.getMintLen)([spl_token_1.ExtensionType.CpiGuard]); const lamports = await connection.getMinimumBalanceForRentExemption(mintLen); // Create instructions array const instructions = []; // Add instruction to create account instructions.push(web3_js_1.SystemProgram.createAccount({ fromPubkey: payer, newAccountPubkey: mint, space: mintLen, lamports, programId: spl_token_1.TOKEN_2022_PROGRAM_ID, })); // Add instruction to initialize CPI Guard instructions.push(createInitializeCpiGuardInstruction(mint, cpiGuardAuthority || null, spl_token_1.TOKEN_2022_PROGRAM_ID)); // Add instruction to initialize mint instructions.push((0, spl_token_1.createInitializeMintInstruction)(mint, decimals, mintAuthority, null, // freeze authority spl_token_1.TOKEN_2022_PROGRAM_ID)); return { instructions, signers: [mintKeypair], mint, }; } /** * Check if this mint has CPI Guard enabled * @returns Promise resolving to boolean indicating if CPI Guard is enabled */ async isCpiGuardEnabled() { return CpiGuardExtension.isCpiGuardEnabled(this.connection, this.mint, spl_token_1.TOKEN_2022_PROGRAM_ID); } /** * Get the CPI Guard authority for this mint * @returns Promise resolving to the authority public key or null if no authority */ async getCpiGuardAuthority() { return CpiGuardExtension.getCpiGuardAuthority(this.connection, this.mint, spl_token_1.TOKEN_2022_PROGRAM_ID); } /** * Create instruction to enable CPI Guard for this mint * @param authority - Authority address that can enable/disable CPI Guard * @returns Instruction to enable CPI Guard */ createEnableCpiGuardInstruction(authority) { return CpiGuardExtension.createEnableCpiGuardInstruction(this.mint, authority, spl_token_1.TOKEN_2022_PROGRAM_ID); } /** * Create instruction to disable CPI Guard for this mint * @param authority - Authority address that can enable/disable CPI Guard * @returns Instruction to disable CPI Guard */ createDisableCpiGuardInstruction(authority) { return CpiGuardExtension.createDisableCpiGuardInstruction(this.mint, authority, spl_token_1.TOKEN_2022_PROGRAM_ID); } } exports.CpiGuardExtension = CpiGuardExtension;