UNPKG

mintme-sdk

Version:

A simple and powerful SDK for creating and managing tokens on the Solana blockchain. MintMe SDK simplifies the process of minting SPL tokens with metadata, managing token authorities, and interacting with the Solana token ecosystem.

319 lines (291 loc) 10.8 kB
#!/usr/bin/env node /** * createTokenTerminal.js * * Script to create tokens on Solana from the terminal using the mintme library. * * Usage: * node createTokenTerminal.js --name "MINTME" --symbol "MTKN" [options] */ const { Connection, Keypair } = require("@solana/web3.js"); const { createToken, revokeFreezeAuthority } = require("mintme-sdk"); const fs = require("fs"); const path = require("path"); const readline = require("readline"); // Function to parse command line arguments function parseArgs() { const args = process.argv.slice(2); const params = {}; for (let i = 0; i < args.length; i++) { if (args[i].startsWith("--")) { const key = args[i].slice(2); const value = args[i + 1] && !args[i + 1].startsWith("--") ? args[i + 1] : true; params[key] = value; if (value !== true) i++; } } return params; } // Function to display help function showHelp() { console.log(` createTokenTerminal.js - Create tokens on Solana using mintme Usage: node createTokenTerminal.js --name "Token Name" --symbol "SYMB" [options] Options: --name STRING Token name (required) --symbol STRING Token symbol (required) --unique-key STRING Unique Key --decimals NUMBER Number of decimals (default: 9) --supply NUMBER Initial supply (default: 1000000000) --uri STRING Metadata URI (default: "https://ipfs.mintme.dev/metadata.json") --revoke-mint Revoke mint authority (default: false) --revoke-freeze Revoke freeze authority after creating the token (default: false) --wallet STRING Path to wallet.json file (default: "./wallet.json") --cluster STRING Solana cluster: devnet, testnet, mainnet (default: devnet) --endpoint STRING Custom Solana RPC endpoint (takes priority over --cluster) --help Show this help Examples: node tests/createTokenTerminal.js --name "MINTME" --symbol "MTM" --unique-key "VERSION_1" node tests/createTokenTerminal.js --name "MINTME" --symbol "MTM" --decimals 6 --supply 1000000 --unique-key "VERSION_1" node tests/createTokenTerminal.js --name "MINTME" --symbol "MTM" --revoke-mint --wallet "./my-wallet.json" --unique-key "VERSION_1" node tests/createTokenTerminal.js --name "MINTME" --symbol "MTM" --cluster mainnet --unique-key "VERSION_1" node tests/createTokenTerminal.js --name "MINTME" --symbol "MTM" --revoke-freeze --unique-key "VERSION_1" node tests/create-token-terminal.js --name "MINTME" --symbol "MTM" --decimals 6 --supply 1000000 --uri "https://mintme.dev/metadata.json" --revoke-mint --revoke-freeze --unique-key "VERSION_1" node tests/create-token-terminal.js --name "MINTME" --symbol "MTM" --decimals 6 --supply 1000000 --uri "https://mintme.dev/metadata.json" --revoke-mint --revoke-freeze --endpoint "https://api.devnet.solana.com" --unique-key "VERSION_1" `); } // Main function async function main() { try { // Parse arguments const params = parseArgs(); // Show help if requested or if required parameters are missing if ( params.help || !params.name || !params.symbol || !params["unique-key"] ) { showHelp(); if (!params.help) { console.error( "\nError: Parameters --name, --symbol, and --unique-key are required" ); } process.exit(params.help ? 0 : 1); } // Configure parameters with default values const tokenName = params.name; const tokenSymbol = params.symbol; const uniqueKey = params["unique-key"]; const decimals = Number.parseInt(params.decimals || "9", 10); const initialSupply = Number.parseInt(params.supply || "1000000000", 10); const uri = params.uri || "https://ipfs.mintme.dev/metadata.json"; const revokeMint = params["revoke-mint"] === true; const revokeFreezeAfterCreation = params["revoke-freeze"] === true; const walletPath = params.wallet || "./wallet.json"; const cluster = params.cluster || "devnet"; // Configure endpoint (custom endpoint takes priority over cluster) let endpoint; if (params.endpoint) { endpoint = params.endpoint; } else { switch (cluster) { case "mainnet": endpoint = "https://api.mainnet-beta.solana.com"; break; case "testnet": endpoint = "https://api.testnet.solana.com"; break; case "devnet": default: endpoint = "https://api.devnet.solana.com"; break; } } console.log("=== Token Configuration ==="); console.log(`Name: ${tokenName}`); console.log(`Symbol: ${tokenSymbol}`); console.log(`Unique Key: ${uniqueKey}`); console.log(`Decimals: ${decimals}`); console.log(`Initial Supply: ${initialSupply}`); console.log(`URI: ${uri}`); console.log(`Revoke mint: ${revokeMint}`); console.log(`Revoke freeze after creation: ${revokeFreezeAfterCreation}`); console.log(`Wallet: ${walletPath}`); console.log(`Cluster: ${cluster}`); console.log(`Endpoint: ${endpoint}`); console.log("============================="); // Verify that the wallet file exists const resolvedWalletPath = path.resolve(walletPath); if (!fs.existsSync(resolvedWalletPath)) { console.error(`Error: Wallet file not found at ${resolvedWalletPath}`); console.log( "You can generate a wallet by running: node generate-wallet.js" ); process.exit(1); } // Load wallet console.log(`Loading wallet from ${resolvedWalletPath}...`); const walletData = JSON.parse(fs.readFileSync(resolvedWalletPath, "utf-8")); const payer = Keypair.fromSecretKey(Buffer.from(walletData)); // Create Solana connection console.log(`Connecting to Solana (${endpoint})...`); const connection = new Connection(endpoint, "confirmed"); // Check balance const balance = await connection.getBalance(payer.publicKey); console.log(`Address: ${payer.publicKey.toString()}`); console.log(`Balance: ${balance / 1000000000} SOL`); if (balance < 10000000) { console.error( "Error: Insufficient balance. You need at least 0.01 SOL to create a token." ); console.log( `You can get SOL on devnet with: solana airdrop 2 ${payer.publicKey.toString()} --url devnet` ); process.exit(1); } // Create token console.log("\nCreating token..."); const result = await createToken({ connection, payer, name: tokenName, symbol: tokenSymbol, uniqueKey: uniqueKey, decimals, initialSupply, uri, revokeMint, }); if (result.success) { console.log("\n✅ Token created successfully!"); console.log("=== Token Details ==="); console.log(`Mint: ${result.mint}`); console.log(`Token account: ${result.tokenAccount}`); console.log(`Metadata: ${result.metadata}`); console.log(`Transaction: ${result.txSignature}`); console.log( `Explorer URL: https://explorer.solana.com/tx/${result.txSignature}?cluster=${cluster}` ); // Save token information to a file const tokenInfo = { name: tokenName, symbol: tokenSymbol, mint: result.mint, tokenAccount: result.tokenAccount, metadata: result.metadata, txSignature: result.txSignature, createdAt: new Date().toISOString(), }; // Revoke freeze authority if requested if (revokeFreezeAfterCreation) { console.log("\nRevoking freeze authority..."); try { const revokeResult = await revokeFreezeAuthority({ connection, payer, name: tokenName, symbol: tokenSymbol, uniqueKey: uniqueKey, }); if (revokeResult.success) { console.log("\n✅ Freeze authority revoked successfully!"); console.log(`Transaction: ${revokeResult.txSignature}`); console.log( `Explorer URL: https://explorer.solana.com/tx/${revokeResult.txSignature}?cluster=${cluster}` ); } else { console.error( "\n❌ Error revoking freeze authority:", revokeResult.error ); if (revokeResult.details) { console.error("Details:", revokeResult.details); } } } catch (error) { console.error("\n❌ Error revoking freeze authority:", error); } } else if (!revokeFreezeAfterCreation) { // Ask if they want to revoke freeze authority (only if not automatically revoked) await askToRevokeFreezeAuthority( connection, payer, tokenName, tokenSymbol, uniqueKey, cluster ); } } else { console.error("\n❌ Error creating token:", result.error); if (result.details) { console.error("Details:", result.details); } process.exit(1); } } catch (error) { console.error("Unexpected error:", error); process.exit(1); } } function askToRevokeFreezeAuthority( connection, payer, tokenName, tokenSymbol, uniqueKey, cluster ) { return new Promise((resolve) => { const rl = readline.createInterface({ input: process.stdin, output: process.stdout, }); rl.question( "Do you want to revoke the freeze authority? (y/n): ", async (answer) => { rl.close(); if (answer.toLowerCase() === "y") { console.log("\nRevoking freeze authority..."); try { const result = await revokeFreezeAuthority({ connection, payer, name: tokenName, symbol: tokenSymbol, uniqueKey: uniqueKey, }); if (result.success) { console.log("\n✅ Freeze authority revoked successfully!"); console.log(`Transaction: ${result.txSignature}`); console.log( `Explorer URL: https://explorer.solana.com/tx/${result.txSignature}?cluster=${cluster}` ); } else { console.error( "\n❌ Error revoking freeze authority:", result.error ); if (result.details) { console.error("Details:", result.details); } } } catch (error) { console.error("\n❌ Error revoking freeze authority:", error); } } else { console.log( "\nFreeze authority was not revoked. You can revoke it later if you wish." ); } resolve(); } ); }); } // Execute the main function main();