SHiNE-server/shine-solana/shine/scripts/dao/revoke_member_token_full_exec.js

112 lines
4.0 KiB
JavaScript
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env node
"use strict";
const fs = require("fs");
const path = require("path");
const readline = require("readline");
const BN = require("bn.js");
const { Connection, Keypair, PublicKey, Transaction, sendAndConfirmTransaction, clusterApiUrl } = require("@solana/web3.js");
const { PROGRAM_VERSION_V3, withRevokeGoverningTokens } = require("@solana/spl-governance");
function parseEnvConfig(configPath) {
const raw = fs.readFileSync(configPath, "utf8");
const out = {};
for (const line of raw.split("\n")) {
const trimmed = line.trim();
if (!trimmed || trimmed.startsWith("#")) continue;
const eq = trimmed.indexOf("=");
if (eq === -1) continue;
const key = trimmed.slice(0, eq).trim();
let val = trimmed.slice(eq + 1).trim();
if ((val.startsWith('"') && val.endsWith('"')) || (val.startsWith("'") && val.endsWith("'"))) {
val = val.slice(1, -1);
}
val = val.replace(/\$HOME/g, process.env.HOME || "");
out[key] = val;
}
return out;
}
function loadKeypair(filePath) {
const arr = JSON.parse(fs.readFileSync(filePath, "utf8"));
return Keypair.fromSecretKey(Uint8Array.from(arr));
}
async function askYes() {
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
const answer = await new Promise((resolve) =>
rl.question("Введите YES для отзыва (burn/revoke) governance токенов: ", resolve)
);
rl.close();
return answer.trim() === "YES";
}
async function main() {
const configPath = process.argv[2]
? path.resolve(process.argv[2])
: path.resolve(__dirname, "dao.config.env");
const realmStr = process.argv[3];
const mintStr = process.argv[4];
const targetOwnerStr = process.argv[5];
const amountStr = process.argv[6] || "1";
if (!realmStr || !mintStr || !targetOwnerStr) {
throw new Error(
"Использование: node scripts/dao/revoke_member_token_full_exec.js <config.env> <realm> <mint> <target_owner_pubkey> [amount]"
);
}
const cfg = parseEnvConfig(configPath);
const cluster = cfg.DAO_CLUSTER || "devnet";
const governanceProgramId = new PublicKey(cfg.SPL_GOVERNANCE_PROGRAM_ID);
const revokeKpPath = cfg.DAO_REVOKE_AUTHORITY_KEYPAIR || cfg.DAO_ISSUER_KEYPAIR;
if (!revokeKpPath) throw new Error("В конфиге нет DAO_REVOKE_AUTHORITY_KEYPAIR и DAO_ISSUER_KEYPAIR");
const revokeAuthority = loadKeypair(path.resolve(revokeKpPath));
const realm = new PublicKey(realmStr);
const mint = new PublicKey(mintStr);
const targetOwner = new PublicKey(targetOwnerStr);
const amount = new BN(amountStr);
if (amount.lten(0)) throw new Error("amount должен быть > 0");
console.log("============================================================");
console.log("REVOKE/BURN GOVERNANCE TOKENS");
console.log("------------------------------------------------------------");
console.log("Сеть: ", cluster);
console.log("Governance program: ", governanceProgramId.toBase58());
console.log("Realm: ", realm.toBase58());
console.log("Mint: ", mint.toBase58());
console.log("Target owner: ", targetOwner.toBase58());
console.log("Amount: ", amount.toString());
console.log("Revoke authority: ", revokeAuthority.publicKey.toBase58());
console.log("============================================================");
const ok = await askYes();
if (!ok) {
console.log("Отменено пользователем.");
return;
}
const connection = new Connection(clusterApiUrl(cluster), "confirmed");
const ix = [];
await withRevokeGoverningTokens(
ix,
governanceProgramId,
PROGRAM_VERSION_V3,
realm,
targetOwner,
mint,
revokeAuthority.publicKey,
amount
);
const sig = await sendAndConfirmTransaction(connection, new Transaction().add(...ix), [revokeAuthority], {
commitment: "confirmed",
});
console.log("Готово. Tx:", sig);
}
main().catch((e) => {
console.error("Ошибка revoke:", e?.message || e);
process.exit(1);
});