solana-token-extension-boost
Version:
SDK for Solana Token Extensions with wallet adapter support
243 lines (242 loc) • 10.8 kB
JavaScript
"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;