#!/usr/bin/env node "use strict"; const fs = require("fs"); const path = require("path"); const { Connection, Keypair, SystemProgram, Transaction, sendAndConfirmTransaction, } = require("@solana/web3.js"); const { TOKEN_2022_PROGRAM_ID, ExtensionType, getMintLen, createInitializeMintInstruction, createInitializeNonTransferableMintInstruction, createInitializePermanentDelegateInstruction, } = require("@solana/spl-token"); const { parseEnvConfig, assertRequired, resolveConfigPath, loadKeypair, saveKeypair, parseCluster, nowStamp, } = require("./_common"); async function main() { const configPath = resolveConfigPath(process.argv[2]); const cfg = parseEnvConfig(configPath); assertRequired(cfg, "GT_CLUSTER"); assertRequired(cfg, "GT_OPERATOR_KEYPAIR_PATH"); assertRequired(cfg, "GT_RUNS_DIR"); const operator = loadKeypair(path.resolve(cfg.GT_OPERATOR_KEYPAIR_PATH)); const connection = new Connection(parseCluster(cfg.GT_CLUSTER), "confirmed"); let mint; if (cfg.GT_MINT_KEYPAIR_PATH) { mint = loadKeypair(path.resolve(cfg.GT_MINT_KEYPAIR_PATH)); } else { mint = Keypair.generate(); } const extensions = [ExtensionType.NonTransferable, ExtensionType.PermanentDelegate]; const mintLen = getMintLen(extensions); const rent = await connection.getMinimumBalanceForRentExemption(mintLen, "confirmed"); const tx = new Transaction().add( SystemProgram.createAccount({ fromPubkey: operator.publicKey, newAccountPubkey: mint.publicKey, space: mintLen, lamports: rent, programId: TOKEN_2022_PROGRAM_ID, }), createInitializeNonTransferableMintInstruction(mint.publicKey, TOKEN_2022_PROGRAM_ID), createInitializePermanentDelegateInstruction( mint.publicKey, operator.publicKey, TOKEN_2022_PROGRAM_ID ), createInitializeMintInstruction( mint.publicKey, 0, operator.publicKey, operator.publicKey, TOKEN_2022_PROGRAM_ID ) ); const sig = await sendAndConfirmTransaction(connection, tx, [operator, mint], { commitment: "confirmed", }); const runsDir = path.resolve(cfg.GT_RUNS_DIR); fs.mkdirSync(runsDir, { recursive: true }); const outMintPath = cfg.GT_MINT_KEYPAIR_PATH && cfg.GT_MINT_KEYPAIR_PATH.trim() ? path.resolve(cfg.GT_MINT_KEYPAIR_PATH) : path.join(runsDir, `${nowStamp()}_mint-keypair.json`); saveKeypair(outMintPath, mint); const report = { createdAt: new Date().toISOString(), cluster: cfg.GT_CLUSTER, operator: operator.publicKey.toBase58(), mint: mint.publicKey.toBase58(), tokenProgram: TOKEN_2022_PROGRAM_ID.toBase58(), nonTransferable: true, permanentDelegate: operator.publicKey.toBase58(), mintAuthority: operator.publicKey.toBase58(), freezeAuthority: operator.publicKey.toBase58(), mintKeypairPath: outMintPath, txCreateMint: sig, }; const reportPath = path.join(runsDir, `${nowStamp()}_create_token.json`); fs.writeFileSync(reportPath, JSON.stringify(report, null, 2)); console.log("Governance token создан."); console.log("Mint:", mint.publicKey.toBase58()); console.log("Mint keypair:", outMintPath); console.log("Tx:", sig); console.log("Report:", reportPath); } main().catch((e) => { console.error("Ошибка создания governance token:", e?.message || e); process.exit(1); });