SHA256
163 lines
5.8 KiB
JavaScript
163 lines
5.8 KiB
JavaScript
#!/usr/bin/env node
|
|
"use strict";
|
|
|
|
const fs = require("fs");
|
|
const path = require("path");
|
|
const BN = require("bn.js");
|
|
const {
|
|
Connection,
|
|
Keypair,
|
|
SystemProgram,
|
|
Transaction,
|
|
sendAndConfirmTransaction,
|
|
} = require("@solana/web3.js");
|
|
const {
|
|
TOKEN_PROGRAM_ID,
|
|
AuthorityType,
|
|
getMintLen,
|
|
createInitializeMintInstruction,
|
|
createSetAuthorityInstruction,
|
|
} = require("@solana/spl-token");
|
|
const { createUmi } = require("@metaplex-foundation/umi-bundle-defaults");
|
|
const { createSignerFromKeypair, signerIdentity, percentAmount, none, some } = require("@metaplex-foundation/umi");
|
|
const { fromWeb3JsKeypair, fromWeb3JsPublicKey } = require("@metaplex-foundation/umi-web3js-adapters");
|
|
const { mplTokenMetadata, createV1, TokenStandard } = require("@metaplex-foundation/mpl-token-metadata");
|
|
const {
|
|
PublicKey,
|
|
assertRequired,
|
|
clusterUrl,
|
|
ensureArweaveUri,
|
|
ensureDir,
|
|
loadKeypair,
|
|
nowStamp,
|
|
parseEnvConfig,
|
|
resolveConfigPath,
|
|
} = require("./js_common");
|
|
|
|
function lamportsToSol(lamports) {
|
|
return Number(lamports) / 1_000_000_000;
|
|
}
|
|
|
|
async function attachGovernanceMetadata(cfg, cluster, issuer, mintPubkey, mintKeypair) {
|
|
ensureArweaveUri("DAO_GOV_TOKEN_METADATA_URI", cfg.DAO_GOV_TOKEN_METADATA_URI);
|
|
ensureArweaveUri("DAO_GOV_TOKEN_IMAGE_URL", cfg.DAO_GOV_TOKEN_IMAGE_URL);
|
|
|
|
const umi = createUmi(clusterUrl(cluster));
|
|
const issuerSigner = createSignerFromKeypair(umi, fromWeb3JsKeypair(issuer));
|
|
const mintSigner = createSignerFromKeypair(umi, fromWeb3JsKeypair(mintKeypair));
|
|
umi.use(signerIdentity(issuerSigner));
|
|
umi.use(mplTokenMetadata());
|
|
|
|
const builder = createV1(umi, {
|
|
mint: mintSigner,
|
|
authority: issuerSigner,
|
|
payer: issuerSigner,
|
|
updateAuthority: issuerSigner,
|
|
name: cfg.DAO_GOV_NFT_NAME,
|
|
symbol: cfg.DAO_GOV_NFT_SYMBOL,
|
|
uri: cfg.DAO_GOV_TOKEN_METADATA_URI,
|
|
sellerFeeBasisPoints: percentAmount(0),
|
|
tokenStandard: TokenStandard.Fungible,
|
|
decimals: some(0),
|
|
creators: none(),
|
|
collection: none(),
|
|
uses: none(),
|
|
collectionDetails: none(),
|
|
ruleSet: none(),
|
|
printSupply: none(),
|
|
primarySaleHappened: false,
|
|
isMutable: true,
|
|
isCollection: false,
|
|
splTokenProgram: fromWeb3JsPublicKey(TOKEN_PROGRAM_ID),
|
|
});
|
|
|
|
const result = await builder.sendAndConfirm(umi);
|
|
return Buffer.from(result.signature).toString("base64");
|
|
}
|
|
|
|
async function main() {
|
|
const configPath = resolveConfigPath(process.argv[2], "dao.config.env");
|
|
if (!fs.existsSync(configPath)) throw new Error(`Конфиг не найден: ${configPath}`);
|
|
|
|
const cfg = parseEnvConfig(configPath);
|
|
[
|
|
"DAO_CLUSTER",
|
|
"DAO_GOV_NFT_NAME",
|
|
"DAO_GOV_NFT_SYMBOL",
|
|
"DAO_GOV_TOKEN_DESCRIPTION",
|
|
"DAO_ISSUER_KEYPAIR",
|
|
"SPL_GOVERNANCE_PROGRAM_ID",
|
|
"DAO_GOV_TOKEN_METADATA_URI",
|
|
"DAO_GOV_TOKEN_IMAGE_URL",
|
|
].forEach((k) => assertRequired(cfg, k));
|
|
|
|
const cluster = cfg.DAO_CLUSTER;
|
|
const connection = new Connection(clusterUrl(cluster), "confirmed");
|
|
const issuer = loadKeypair(path.resolve(cfg.DAO_ISSUER_KEYPAIR));
|
|
const mintKeypair = cfg.DAO_GOV_MINT_KEYPAIR
|
|
? loadKeypair(path.resolve(cfg.DAO_GOV_MINT_KEYPAIR))
|
|
: Keypair.generate();
|
|
const governanceProgramId = new PublicKey(cfg.SPL_GOVERNANCE_PROGRAM_ID);
|
|
|
|
const startBalance = await connection.getBalance(issuer.publicKey, "confirmed");
|
|
console.log("============================================================");
|
|
console.log("CREATE SHiNE GOVERNANCE MINT");
|
|
console.log("------------------------------------------------------------");
|
|
console.log("Сеть: ", cluster);
|
|
console.log("Mint: ", mintKeypair.publicKey.toBase58());
|
|
console.log("Issuer: ", issuer.publicKey.toBase58());
|
|
console.log("Governance program:", governanceProgramId.toBase58());
|
|
console.log("Баланс до: ", `${lamportsToSol(startBalance)} SOL`);
|
|
console.log("Name: ", cfg.DAO_GOV_NFT_NAME);
|
|
console.log("Symbol: ", cfg.DAO_GOV_NFT_SYMBOL);
|
|
console.log("Metadata URI: ", cfg.DAO_GOV_TOKEN_METADATA_URI);
|
|
console.log("Image URL: ", cfg.DAO_GOV_TOKEN_IMAGE_URL);
|
|
console.log("============================================================");
|
|
|
|
const mintLen = getMintLen([]);
|
|
const mintRent = await connection.getMinimumBalanceForRentExemption(mintLen);
|
|
const txMint = new Transaction().add(
|
|
SystemProgram.createAccount({
|
|
fromPubkey: issuer.publicKey,
|
|
newAccountPubkey: mintKeypair.publicKey,
|
|
space: mintLen,
|
|
lamports: mintRent,
|
|
programId: TOKEN_PROGRAM_ID,
|
|
}),
|
|
createInitializeMintInstruction(mintKeypair.publicKey, 0, issuer.publicKey, issuer.publicKey, TOKEN_PROGRAM_ID)
|
|
);
|
|
const sigMint = await sendAndConfirmTransaction(connection, txMint, [issuer, mintKeypair], {
|
|
commitment: "confirmed",
|
|
});
|
|
|
|
const sigMetadata = await attachGovernanceMetadata(cfg, cluster, issuer, mintKeypair.publicKey, mintKeypair);
|
|
|
|
const report = {
|
|
createdAt: new Date().toISOString(),
|
|
cluster,
|
|
mint: mintKeypair.publicKey.toBase58(),
|
|
issuer: issuer.publicKey.toBase58(),
|
|
mintAuthority: issuer.publicKey.toBase58(),
|
|
freezeAuthority: issuer.publicKey.toBase58(),
|
|
metadataUpdateAuthority: issuer.publicKey.toBase58(),
|
|
governanceProgramId: governanceProgramId.toBase58(),
|
|
metadataUri: cfg.DAO_GOV_TOKEN_METADATA_URI,
|
|
imageUrl: cfg.DAO_GOV_TOKEN_IMAGE_URL,
|
|
txMint: sigMint,
|
|
txMetadata: sigMetadata,
|
|
};
|
|
const runsDir = path.resolve(__dirname, "..", "local", "runs");
|
|
ensureDir(runsDir);
|
|
const reportPath = path.join(runsDir, `${nowStamp()}_governance_mint.json`);
|
|
fs.writeFileSync(reportPath, JSON.stringify(report, null, 2));
|
|
|
|
console.log("Готово. Governance mint создан.");
|
|
console.log("mint:", mintKeypair.publicKey.toBase58());
|
|
console.log("report:", reportPath);
|
|
}
|
|
|
|
main().catch((e) => {
|
|
console.error("CreateMint error:", e?.message || e);
|
|
process.exit(1);
|
|
});
|