diff --git a/command/analyze.js b/command/analyze.js index 4f40261..b094560 100644 --- a/command/analyze.js +++ b/command/analyze.js @@ -1,6 +1,5 @@ const { Command, Argument } = require("commander"); -const { getBlsRegisterClient, getPath, readKeypair } = require("./utils"); -const anchor = require("@coral-xyz/anchor"); +const { getBlsRegisterClient } = require("./utils"); const chalk = require("chalk"); const { Keypair } = require("@solana/web3.js"); const fs = require("node:fs"); @@ -58,7 +57,7 @@ analyzeCommand.addArgument(file).action(async (file, options) => { } while (rs != null && rs.length > 0); process.exit(0); } catch (e) { - console.log(chalk.red("analyze execute fail: " + e)); + console.log(chalk.red("analyze execute failed: " + e)); process.exit(1); } }); diff --git a/command/bless_token.js b/command/bless_token.js index 87386ac..c54d28f 100644 --- a/command/bless_token.js +++ b/command/bless_token.js @@ -94,7 +94,7 @@ blesstokenCommand console.log(chalk.green("bless token initial success.")); process.exit(0); } catch (e) { - console.log(chalk.red("bless token initial fail: " + e)); + console.log(chalk.red("bless token initial failed: " + e)); process.exit(1); } }); diff --git a/command/bles_meta_accept_admin.js b/command/meta/bles_meta_accept_admin.js similarity index 93% rename from command/bles_meta_accept_admin.js rename to command/meta/bles_meta_accept_admin.js index 8af46d9..58c95c0 100644 --- a/command/bles_meta_accept_admin.js +++ b/command/meta/bles_meta_accept_admin.js @@ -1,12 +1,12 @@ const { Command, Argument } = require("commander"); const chalk = require("chalk"); -const { WALLET_PATH } = require("../lib/constants"); +const { WALLET_PATH } = require("../../lib/constants"); const { getBlsContractClient, getPath, readKeypair, bs58Message, -} = require("./utils"); +} = require("../utils"); const { PublicKey } = require("@solana/web3.js"); const blessMetaAcceptAdminCommand = new Command("accept-admin") @@ -25,7 +25,7 @@ const blessMetaAcceptAdminCommand = new Command("accept-admin") ) .option( "--squads ", - "squads: if squads true, use squads to signature, default is false.", + "squads: if true, use Squads to sign the transaction; default: false.", ) .option( "--admin ", @@ -103,7 +103,7 @@ blessMetaAcceptAdminCommand console.log(chalk.green("bless meta accept admin success.")); process.exit(0); } catch (e) { - console.log(chalk.red("bless meta accept admin fail: " + e)); + console.log(chalk.red("bless meta accept admin failed: " + e)); process.exit(1); } }); diff --git a/command/bles_meta_create.js b/command/meta/bles_meta_create.js similarity index 93% rename from command/bles_meta_create.js rename to command/meta/bles_meta_create.js index 742d17d..524f6aa 100644 --- a/command/bles_meta_create.js +++ b/command/meta/bles_meta_create.js @@ -1,14 +1,14 @@ const { Command, Argument } = require("commander"); const chalk = require("chalk"); const anchor = require("@coral-xyz/anchor"); -const { WALLET_PATH } = require("../lib/constants"); +const { WALLET_PATH } = require("../../lib/constants"); const { getBlsContractClient, getPath, readKeypair, getMetadata, bs58Message, -} = require("./utils"); +} = require("../utils"); const { PublicKey } = require("@solana/web3.js"); const blessMetaCreateCommand = new Command("create") @@ -28,11 +28,11 @@ const blessMetaCreateCommand = new Command("create") .option("--multisig ", "multisig: the multisig of the bless meta") .option( "--squads ", - "squads: if squads true, use squads to signature, default is false.", + "squads: if true, use Squads to sign the transaction; default: false.", ) .option( "--admin ", - "admin: the admin of the bless meta, the admin will as payer in squads mode ", + "admin: the admin of the bless meta, the admin will as payer in Squads mode ", ) .description( "create-meta: create meta account of the bless meta, the value is base58", @@ -128,7 +128,9 @@ blessMetaCreateCommand console.log(chalk.green("bless token metadata create account success.")); process.exit(0); } catch (e) { - console.log(chalk.red("bless token metadata create account fail: " + e)); + console.log( + chalk.red("bless token metadata create account failed: " + e), + ); process.exit(1); } }); diff --git a/command/bles_meta_init.js b/command/meta/bles_meta_init.js similarity index 94% rename from command/bles_meta_init.js rename to command/meta/bles_meta_init.js index 060123a..554be1e 100644 --- a/command/bles_meta_init.js +++ b/command/meta/bles_meta_init.js @@ -1,8 +1,8 @@ const { Command, Argument } = require("commander"); const chalk = require("chalk"); -const { WALLET_PATH } = require("../lib/constants"); +const { WALLET_PATH } = require("../../lib/constants"); const { PublicKey } = require("@solana/web3.js"); -const { getBlsContractClient, getPath, readKeypair } = require("./utils"); +const { getBlsContractClient, getPath, readKeypair } = require("../utils"); const blessMetaInitCommand = new Command("init") .option( @@ -39,7 +39,7 @@ blessMetaInitCommand.addArgument(mint).action(async (mint, options) => { console.log(chalk.green("bless token metadata account initial success.")); process.exit(0); } catch (e) { - console.log(chalk.red("bless token metadata account initial fail: " + e)); + console.log(chalk.red("bless token metadata account initial failed: " + e)); process.exit(1); } }); diff --git a/command/bles_meta_set_pending_admin.js b/command/meta/bles_meta_set_pending_admin.js similarity index 95% rename from command/bles_meta_set_pending_admin.js rename to command/meta/bles_meta_set_pending_admin.js index 0e6ce80..8c1134a 100644 --- a/command/bles_meta_set_pending_admin.js +++ b/command/meta/bles_meta_set_pending_admin.js @@ -1,12 +1,12 @@ const { Command, Argument } = require("commander"); const chalk = require("chalk"); -const { WALLET_PATH } = require("../lib/constants"); +const { WALLET_PATH } = require("../../lib/constants"); const { getBlsContractClient, getPath, readKeypair, bs58Message, -} = require("./utils"); +} = require("../utils"); const { PublicKey } = require("@solana/web3.js"); const blessMetaSetPendingAdminCommand = new Command("pending-admin") @@ -29,7 +29,7 @@ const blessMetaSetPendingAdminCommand = new Command("pending-admin") ) .option( "--squads ", - "squads: if squads true, use squads to signature, default is false.", + "squads: if true, use Squads to sign the transaction; default: false.", ) .description( "pending-admin: set the pending admin of the bless meta, the value is base58", @@ -115,7 +115,7 @@ blessMetaSetPendingAdminCommand console.log(chalk.green("bless meta set pending admin success.")); process.exit(0); } catch (e) { - console.log(chalk.red("bless meta set the pending admin fail: " + e)); + console.log(chalk.red("bless meta set the pending admin failed: " + e)); process.exit(1); } }); diff --git a/command/bles_meta_update.js b/command/meta/bles_meta_update.js similarity index 93% rename from command/bles_meta_update.js rename to command/meta/bles_meta_update.js index 5d65610..7940895 100644 --- a/command/bles_meta_update.js +++ b/command/meta/bles_meta_update.js @@ -1,13 +1,13 @@ const { Command, Argument } = require("commander"); const chalk = require("chalk"); -const { WALLET_PATH } = require("../lib/constants"); +const { WALLET_PATH } = require("../../lib/constants"); const { getBlsContractClient, getPath, readKeypair, getMetadata, bs58Message, -} = require("./utils"); +} = require("../utils"); const { PublicKey } = require("@solana/web3.js"); const blessMetaUpdateCommand = new Command("update") @@ -27,11 +27,11 @@ const blessMetaUpdateCommand = new Command("update") .option("--multisig ", "multisig: the multisig of the bless meta") .option( "--squads ", - "squads: if squads true, use squads to signature, default is false.", + "squads: if true, use Squads to sign the transaction; default: false.", ) .option( "--admin ", - "admin: the admin of the bless meta, the admin will as payer in squads mode ", + "admin: the admin of the bless meta, the admin will as payer in Squads mode ", ) .description( "create-meta: create meta account of the bless meta, the value is base58", @@ -116,7 +116,9 @@ blessMetaUpdateCommand console.log(chalk.green("bless token metadata account update success.")); process.exit(0); } catch (e) { - console.log(chalk.red("bless token metadata account update fail: " + e)); + console.log( + chalk.red("bless token metadata account update failed: " + e), + ); process.exit(1); } }); diff --git a/command/meta/index.js b/command/meta/index.js new file mode 100644 index 0000000..2ab05e2 --- /dev/null +++ b/command/meta/index.js @@ -0,0 +1,16 @@ +const blessMetaInitCommand = require("./bles_meta_init.js") +const tokenMetaSetAdminCommand = require("./bles_meta_set_pending_admin.js") +const blessMetaUpdateCommand = require("./bles_meta_update.js") +const blessMetaCreateCommand = require("./bles_meta_create.js") +const tokenMetaAcceptAdminCommand = require("./bles_meta_accept_admin.js") + +const commands = { + blessMetaInitCommand, + blessMetaCreateCommand, + blessMetaUpdateCommand, + tokenMetaSetAdminCommand, + tokenMetaAcceptAdminCommand, +}; + +module.exports = commands; +module.exports.default = commands; diff --git a/command/program/index.js b/command/program/index.js new file mode 100644 index 0000000..c701cf9 --- /dev/null +++ b/command/program/index.js @@ -0,0 +1,3 @@ +const programCommand = require("./program.js"); + +module.exports = programCommand; \ No newline at end of file diff --git a/command/loader.js b/command/program/loader.js similarity index 100% rename from command/loader.js rename to command/program/loader.js diff --git a/command/prg_deploy_buffer.js b/command/program/prg_deploy_buffer.js similarity index 93% rename from command/prg_deploy_buffer.js rename to command/program/prg_deploy_buffer.js index 226b437..877a171 100644 --- a/command/prg_deploy_buffer.js +++ b/command/program/prg_deploy_buffer.js @@ -1,6 +1,6 @@ const { Command, Argument } = require("commander"); -const { getPath, readKeypair, getConnection } = require("./utils"); -const { WALLET_PATH } = require("../lib/constants"); +const { getPath, readKeypair, getConnection } = require("../utils"); +const { WALLET_PATH } = require("../../lib/constants"); const Loader = require("./loader"); const chalk = require("chalk"); const nacl = require("tweetnacl"); @@ -79,7 +79,7 @@ deployBufferCommand const tx = await connection.sendRawTransaction(deployTx.serialize()); console.log(chalk.green("program deploy success: " + tx)); } catch (e) { - console.log(chalk.red("program deploy fail: " + e)); + console.log(chalk.red("program deploy failed: " + e)); } }); diff --git a/command/prg_upgrade.js b/command/program/prg_upgrade.js similarity index 92% rename from command/prg_upgrade.js rename to command/program/prg_upgrade.js index 93c1a0c..1384aca 100644 --- a/command/prg_upgrade.js +++ b/command/program/prg_upgrade.js @@ -1,6 +1,6 @@ const { Command, Argument } = require("commander"); -const { getPath, readKeypair, getConnection } = require("./utils"); -const { WALLET_PATH } = require("../lib/constants"); +const { getPath, readKeypair, getConnection } = require("../utils"); +const { WALLET_PATH } = require("../../lib/constants"); const Loader = require("./loader"); const chalk = require("chalk"); const nacl = require("tweetnacl"); @@ -64,7 +64,7 @@ upgradeCommand const tx = await connection.sendRawTransaction(transaction.serialize()); console.log(chalk.green("program upgrade success: " + tx)); } catch (e) { - console.log(chalk.red("program upgrade fail: " + e)); + console.log(chalk.red("program upgrade failed: " + e)); } }); diff --git a/command/program.js b/command/program/program.js similarity index 100% rename from command/program.js rename to command/program/program.js diff --git a/command/register/index.js b/command/register/index.js new file mode 100644 index 0000000..d9c014a --- /dev/null +++ b/command/register/index.js @@ -0,0 +1,3 @@ +const registerCommand = require("./register.js") + +module.exports = registerCommand; \ No newline at end of file diff --git a/command/reg_accept_admin.js b/command/register/reg_accept_admin.js similarity index 85% rename from command/reg_accept_admin.js rename to command/register/reg_accept_admin.js index a427543..00cb63f 100644 --- a/command/reg_accept_admin.js +++ b/command/register/reg_accept_admin.js @@ -1,9 +1,8 @@ const { Command, Argument } = require("commander"); const anchor = require("@coral-xyz/anchor"); const chalk = require("chalk"); -const { WALLET_PATH } = require("../lib/constants"); -const { getBlsRegisterClient, getPath, readKeypair } = require("./utils"); -const { PublicKey } = require("@solana/web3.js"); +const { WALLET_PATH } = require("../../lib/constants"); +const { getBlsRegisterClient, getPath, readKeypair } = require("../utils"); const registerAcceptAdminCommand = new Command("accept-admin") .option( @@ -26,7 +25,7 @@ registerAcceptAdminCommand.action(async (options) => { console.log(chalk.green("registration accept admin success.")); process.exit(0); } catch (e) { - console.log(chalk.red("accept admin of registration fail: " + e)); + console.log(chalk.red("accept admin of registration failed: " + e)); process.exit(1); } }); diff --git a/command/reg_init.js b/command/register/reg_init.js similarity index 91% rename from command/reg_init.js rename to command/register/reg_init.js index dec19b6..cb4531d 100644 --- a/command/reg_init.js +++ b/command/register/reg_init.js @@ -1,6 +1,6 @@ const { Command, Argument } = require("commander"); -const { getBlsRegisterClient, getPath, readKeypair } = require("./utils"); -const { WALLET_PATH } = require("../lib/constants"); +const { getBlsRegisterClient, getPath, readKeypair } = require("../utils"); +const { WALLET_PATH } = require("../../lib/constants"); const anchor = require("@coral-xyz/anchor"); const chalk = require("chalk"); const regInitCommand = new Command("init") @@ -35,7 +35,7 @@ regInitCommand.addArgument(deadline).action(async (deadline, options) => { console.log(chalk.green("registration initial success.")); process.exit(0); } catch (e) { - console.log(chalk.red("registration initial fail: " + e)); + console.log(chalk.red("registration initial failed: " + e)); process.exit(1); } }); diff --git a/command/reg_pause.js b/command/register/reg_pause.js similarity index 92% rename from command/reg_pause.js rename to command/register/reg_pause.js index cfd4425..bc3f111 100644 --- a/command/reg_pause.js +++ b/command/register/reg_pause.js @@ -1,8 +1,7 @@ const { Command, Argument } = require("commander"); -const anchor = require("@coral-xyz/anchor"); const chalk = require("chalk"); -const { WALLET_PATH } = require("../lib/constants"); -const { getBlsRegisterClient, getPath, readKeypair } = require("./utils"); +const { WALLET_PATH } = require("../../lib/constants"); +const { getBlsRegisterClient, getPath, readKeypair } = require("../utils"); const registerSetPauseCommand = new Command("pause") .option( @@ -36,7 +35,7 @@ registerSetPauseCommand.addArgument(pause).action(async (pause, options) => { } process.exit(0); } catch (e) { - console.log(chalk.red("set the pause status of registration fail: " + e)); + console.log(chalk.red("set the pause status of registration failed: " + e)); process.exit(1); } }); diff --git a/command/reg_register.js b/command/register/reg_register.js similarity index 94% rename from command/reg_register.js rename to command/register/reg_register.js index d16c719..5077f11 100644 --- a/command/reg_register.js +++ b/command/register/reg_register.js @@ -2,8 +2,8 @@ const { Command, Argument } = require("commander"); const anchor = require("@coral-xyz/anchor"); const chalk = require("chalk"); const ed = require("@noble/ed25519"); -const { getBlsRegisterClient, getPath, readKeypair } = require("./utils"); -const { WALLET_PATH } = require("../lib/constants"); +const { getBlsRegisterClient, getPath, readKeypair } = require("../utils"); +const { WALLET_PATH } = require("../../lib/constants"); const { PublicKey } = require("@solana/web3.js"); const registerDoCommand = new Command("register") @@ -71,7 +71,7 @@ registerDoCommand.addArgument(nodeid).action(async (nodeid, options) => { console.log(chalk.green("register success ")); process.exit(0); } catch (e) { - console.log(chalk.red("register bless node id fail: " + e)); + console.log(chalk.red("register bless node id failed: " + e)); process.exit(1); } }); diff --git a/command/reg_set_backend_signer.js b/command/register/reg_set_backend_signer.js similarity index 89% rename from command/reg_set_backend_signer.js rename to command/register/reg_set_backend_signer.js index d4e6733..f3fc1f2 100644 --- a/command/reg_set_backend_signer.js +++ b/command/register/reg_set_backend_signer.js @@ -1,8 +1,7 @@ const { Command, Argument } = require("commander"); -const anchor = require("@coral-xyz/anchor"); const chalk = require("chalk"); -const { getBlsRegisterClient, getPath, readKeypair } = require("./utils"); -const { WALLET_PATH } = require("../lib/constants"); +const { getBlsRegisterClient, getPath, readKeypair } = require("../utils"); +const { WALLET_PATH } = require("../../lib/constants"); const registerBackendSignerCommand = new Command("bsigner") .option( @@ -39,7 +38,7 @@ registerBackendSignerCommand process.exit(0); } catch (e) { console.log( - chalk.red("set the backend signer of registration fail: " + e), + chalk.red("set the backend signer of registration failed: " + e), ); process.exit(1); } diff --git a/command/reg_set_deadline.js b/command/register/reg_set_deadline.js similarity index 96% rename from command/reg_set_deadline.js rename to command/register/reg_set_deadline.js index c97c129..c61a74d 100644 --- a/command/reg_set_deadline.js +++ b/command/register/reg_set_deadline.js @@ -1,8 +1,8 @@ const { Command, Argument } = require("commander"); const anchor = require("@coral-xyz/anchor"); const chalk = require("chalk"); -const { getBlsRegisterClient, getPath, readKeypair } = require("./utils"); -const { WALLET_PATH } = require("../lib/constants"); +const { getBlsRegisterClient, getPath, readKeypair } = require("../utils"); +const { WALLET_PATH } = require("../../lib/constants"); const registerSetDeadlineCommand = new Command("deadline") .option( @@ -52,7 +52,7 @@ registerSetDeadlineCommand } process.exit(0); } catch (e) { - console.log(chalk.red("set the deadline of registration fail: " + e)); + console.log(chalk.red("set the deadline of registration failed: " + e)); process.exit(1); } }); diff --git a/command/reg_set_pending_admin.js b/command/register/reg_set_pending_admin.js similarity index 86% rename from command/reg_set_pending_admin.js rename to command/register/reg_set_pending_admin.js index a1aa985..d9383c6 100644 --- a/command/reg_set_pending_admin.js +++ b/command/register/reg_set_pending_admin.js @@ -1,8 +1,8 @@ const { Command, Argument } = require("commander"); const anchor = require("@coral-xyz/anchor"); const chalk = require("chalk"); -const { WALLET_PATH } = require("../lib/constants"); -const { getBlsRegisterClient, getPath, readKeypair } = require("./utils"); +const { WALLET_PATH } = require("../../lib/constants"); +const { getBlsRegisterClient, getPath, readKeypair } = require("../utils"); const { PublicKey } = require("@solana/web3.js"); const registerSetPendingAdminCommand = new Command("pending-admin") @@ -36,16 +36,16 @@ registerSetPendingAdminCommand await client.nodeRegistrationClient.setRegistrationPendingAdminAccount( pendingAdmin, ); - console.log(chalk.green("registration set pending admin success.")); + console.log(chalk.green("Registration set pending admin success.")); } else { const r = await client.nodeRegistrationClient.getNodeRegistration(); console.log( - chalk.green("registration pending admin is " + r.pendingAdminAccount), + chalk.green("Registration pending admin is " + r.pendingAdminAccount), ); } process.exit(0); } catch (e) { - console.log(chalk.red("set the pending admin fail: " + e)); + console.log(chalk.red("Set the pending admin failed: " + e)); process.exit(1); } }); diff --git a/command/register.js b/command/register/register.js similarity index 100% rename from command/register.js rename to command/register/register.js diff --git a/command/stake/accept_admin.js b/command/stake/accept_admin.js new file mode 100644 index 0000000..3d57f89 --- /dev/null +++ b/command/stake/accept_admin.js @@ -0,0 +1,114 @@ +const { Command, Argument } = require("commander"); +const chalk = require("chalk"); +const { WALLET_PATH } = require("../../lib/constants"); +const { + getBlsStakeContractClient, + getPath, + readKeypair, + bs58Message, +} = require("../utils"); +const { PublicKey } = require("@solana/web3.js"); + +const acceptAdminCommand = new Command("accept-admin") + .option( + "--cluster ", + "solana cluster: mainnet, testnet, devnet, localnet, ", + ) + .option( + "--programId ", + "Program ID: Specify the program ID when working on devnet, testnet, or localnet; it will not work on mainnet.", + ) + .option( + "--signer ", + "signer: the signer is the payer of the transaction, default: " + + WALLET_PATH, + ) + .option( + "--squads ", + "squads: if true, use Squads to sign the transaction; default: false.", + ) + .option( + "--admin ", + "admin: the bless stake admin, in Squads mode, the admin will be the payer; in local mode, the admin must be a keypair. ", + ) + .description( + "accept-admin: accept the pending admin of the bless stake, the value is base58", + ); +const mint = new Argument("mint", "mint: the public key of the mint token"); +mint.required = true; +const pending = new Argument( + "pending-admin", + "pending-admin: The pending admin of the bless stake", +); +pending.required = true; + +acceptAdminCommand + .addArgument(mint) + .addArgument(pending) + .action(async (mint, pending, options) => { + options.cluster = options.cluster || "localnet"; + options.signer = options.signer || getPath(WALLET_PATH); + options.squads = options.squads || false; + try { + const keypair = readKeypair(options.signer); + const client = getBlsStakeContractClient( + options.cluster, + keypair, + options.programId, + ); + let mintPubkey = new PublicKey(mint); + const state = await client.blessStakeClient.getStakeState(mintPubkey); + if (options.squads) { + const pendingAdmin = new PublicKey(pending); + if (state.pendingAdmin.toBase58() != pendingAdmin.toBase58()) { + console.log( + chalk.red( + "accept admin is denied, pending admin is not matched, the state pending admin is " + + state.pendingAdmin.toBase58(), + ), + ); + process.exit(1); + } + const tx = await client.blessStakeClient.blessStakeAcceptPendingAdminTx( + mintPubkey, + pendingAdmin, + { signer: pendingAdmin }, + ); + const itx = await bs58Message( + client.connection, + tx.instructions, + keypair, + ); + + console.log("Bless stake accept admin transaction created: \n" + itx); + } else { + const pendingAdmin = readKeypair(pending); + if ( + state.pendingAdmin.toBase58() != pendingAdmin.publicKey.toBase58() + ) { + console.log( + chalk.red( + "Accept admin is denied, pending admin is not matched, the state pending admin is " + + state.pendingAdmin.toBase58(), + ), + ); + process.exit(1); + } + await client.blessStakeClient.blessStakeAcceptPendingAdmin( + mintPubkey, + pendingAdmin.publicKey, + { + signer: keypair.publicKey, + signerKeypair: [keypair, pendingAdmin], + }, + ); + } + console.log(chalk.green("Bless stake accept pending admin success.")); + process.exit(0); + } catch (e) { + console.log(chalk.red("Bless stake accept pending admin failed: " + e)); + process.exit(1); + } + }); + +module.exports = acceptAdminCommand; diff --git a/command/stake/deposit.js b/command/stake/deposit.js new file mode 100644 index 0000000..4468983 --- /dev/null +++ b/command/stake/deposit.js @@ -0,0 +1,112 @@ +const { Command, Argument } = require("commander"); +const { + getBlsStakeContractClient, + getPath, + readKeypair, + bs58Message, +} = require("../utils"); +const { WALLET_PATH } = require("../../lib/constants"); +const anchor = require("@coral-xyz/anchor"); +const chalk = require("chalk"); +const { PublicKey } = require("@solana/web3.js"); +const depositCommand = new Command("deposit") + .option( + "--cluster ", + "solana cluster: mainnet, testnet, devnet, localnet, ", + ) + .option( + "--signer ", + "the signer is the admin of the stake contract: " + WALLET_PATH, + ) + .option( + "--squads ", + "squads: if true, use Squads to sign the transaction; default: false.", + ) + .option( + "--programId ", + "Program ID: Specify the program ID when working on devnet, testnet, or localnet; it will not work on mainnet.", + ) + .description("deposit: deposit the token amount and stake the token amount"); +const mint = new Argument( + "mint", + "mint: the mint is the mint token base58 value ", +); +const amount = new Argument("amount", "deposit the token amount"); +const periods = new Argument("periods", "stake periods for earns the rewards."); +amount.required = true; +periods.required = true; +mint.required = true; +depositCommand + .addArgument(mint) + .addArgument(amount) + .addArgument(periods) + .action(async (mint, amount, periods, options) => { + options.cluster = options.cluster || "localnet"; + options.signer = options.signer || getPath(WALLET_PATH); + const sequence = new anchor.BN(Date.now()); + try { + amount = new anchor.BN(parseInt(amount)); + } catch { + console.log(chalk.red("amount must be a number")); + process.exit(1); + } + try { + periods = parseInt(periods); + } catch { + console.log(chalk.red("periods must be a number")); + process.exit(1); + } + try { + const keypair = readKeypair(options.signer); + const client = getBlsStakeContractClient( + options.cluster, + keypair, + options.programId, + ); + let mintPubkey = null; + try { + mintPubkey = new PublicKey(mint); + } catch (e) { + console.log(chalk.red("Invalid mint parameter: " + e)); + process.exit(1); + } + + if (options.squads) { + const tx = await client.blessStakeClient.blessUserStakeStateCreateTx( + mintPubkey, + sequence, + amount, + periods, + { + signer: keypair.publicKey, + signerKeypair: [keypair], + }, + ); + const itx = await bs58Message( + client.connection, + tx.instructions, + keypair, + ); + console.log(`User stake ${sequence} transaction created : ${itx}`); + } else { + const keypair = readKeypair(options.signer); + const tx = await client.blessStakeClient.blessUserStakeStateCreate( + mintPubkey, + sequence, + amount, + periods, + { + signer: keypair.publicKey, + signerKeypair: [keypair], + }, + ); + console.log(chalk.green(`User stake ${sequence} success, tx: ${tx}`)); + process.exit(0); + } + } catch (e) { + console.log(chalk.red("User stake failed: " + e)); + process.exit(1); + } + }); + +module.exports = depositCommand; diff --git a/command/stake/index.js b/command/stake/index.js new file mode 100644 index 0000000..d5cc0fd --- /dev/null +++ b/command/stake/index.js @@ -0,0 +1,26 @@ +const { Command } = require("commander"); +const stakeInitializeCommand = require("./stake_init.js"); +const setPendingAdminCommand = require("./set_pending_admin.js"); +const acceptAdminCommand = require("./accept_admin.js"); +const setAprCommand = require("./set_apr.js"); +const setAprFactorCommand = require("./set_apr_factor.js"); +const setPauseCommand = require("./pause.js"); +const depositCommand = require("./deposit.js"); +const unstakeCommand = require("./unstake.js"); +const withdrawCommand = require("./withdraw.js"); + +const stakeCommand = new Command("stake").description( + "stake: The operations for stake contract.", +); + +stakeCommand.addCommand(stakeInitializeCommand); +stakeCommand.addCommand(setPendingAdminCommand); +stakeCommand.addCommand(setAprFactorCommand); +stakeCommand.addCommand(acceptAdminCommand); +stakeCommand.addCommand(setPauseCommand); +stakeCommand.addCommand(withdrawCommand); +stakeCommand.addCommand(depositCommand); +stakeCommand.addCommand(unstakeCommand); +stakeCommand.addCommand(setAprCommand); + +module.exports = stakeCommand; diff --git a/command/stake/pause.js b/command/stake/pause.js new file mode 100644 index 0000000..700c895 --- /dev/null +++ b/command/stake/pause.js @@ -0,0 +1,118 @@ +const { Command, Argument } = require("commander"); +const chalk = require("chalk"); +const { WALLET_PATH } = require("../../lib/constants"); +const { + getBlsStakeContractClient, + getPath, + readKeypair, + bs58Message, +} = require("../utils"); +const { PublicKey } = require("@solana/web3.js"); + +const setPauseCommand = new Command("pause") + .option( + "--cluster ", + "solana cluster: mainnet, testnet, devnet, localnet, ", + ) + .option( + "--programId ", + "Program ID: Specify the program ID when working on devnet, testnet, or localnet; it will not work on mainnet.", + ) + .option( + "--signer ", + "signer: the signer is the payer of the transaction, default: " + + WALLET_PATH, + ) + .option( + "--squads ", + "squads: if true, use Squads to sign the transaction; default: false.", + ) + .option( + "--admin ", + "admin: the bless stake admin, in Squads mode, the admin will be the payer; in local mode, the admin must be a keypair. ", + ) + .description("pause: pause the stake activity"); +const mint = new Argument("mint", "mint: the public key of the mint token"); +mint.required = true; +const status = new Argument( + "status", + "status: the status of the stake activity", +); +status.required = true; + +setPauseCommand + .addArgument(mint) + .addArgument(status) + .action(async (mint, status, options) => { + options.cluster = options.cluster || "localnet"; + options.signer = options.signer || getPath(WALLET_PATH); + options.squads = options.squads || false; + try { + const keypair = readKeypair(options.signer); + const client = getBlsStakeContractClient( + options.cluster, + keypair, + options.programId, + ); + let mintPubkey = new PublicKey(mint); + const state = await client.blessStakeClient.getStakeState(mintPubkey); + status = status === "true" ? true : false; + if (options.squads) { + if (options.admin == null) { + console.log(chalk.red("admin is required.")); + process.exit(1); + } + const adminPubkey = new PublicKey(options.admin); + if (state.admin.toBase58() != adminPubkey.toBase58()) { + console.log( + chalk.red( + "set pause status is denied, admin is not matched, the state admin is " + + state.admin.toBase58(), + ), + ); + process.exit(1); + } + const tx = await client.blessStakeClient.blessStakeSetPauseTx( + mintPubkey, + adminPubkey, + status, + { signer: adminPubkey }, + ); + const itx = await bs58Message( + client.connection, + tx.instructions, + keypair, + ); + + console.log("Bless stake set the pause transaction created: \n" + itx); + } else { + options.admin = options.admin || getPath(WALLET_PATH); + const adminKeypair = readKeypair(options.admin); + if (state.admin.toBase58() != adminKeypair.publicKey.toBase58()) { + console.log( + chalk.red( + "set pause status is denied, admin is not matched, the state admin is " + + state.admin.toBase58(), + ), + ); + process.exit(1); + } + await client.blessStakeClient.blessStakeSetPause( + mintPubkey, + adminKeypair.publicKey, + status, + { + signer: keypair.publicKey, + signerKeypair: [keypair, adminKeypair], + }, + ); + } + console.log(chalk.green("Bless stake set pause status success.")); + process.exit(0); + } catch (e) { + console.log(chalk.red("Bless stake set pause status failed: " + e)); + process.exit(1); + } + }); + +module.exports = setPauseCommand; diff --git a/command/stake/set_apr.js b/command/stake/set_apr.js new file mode 100644 index 0000000..67701b2 --- /dev/null +++ b/command/stake/set_apr.js @@ -0,0 +1,131 @@ +const { Command, Argument } = require("commander"); +const chalk = require("chalk"); +const { WALLET_PATH } = require("../../lib/constants"); +const { + getBlsStakeContractClient, + getPath, + readKeypair, + bs58Message, +} = require("../utils"); +const { PublicKey } = require("@solana/web3.js"); + +const setAprCommand = new Command("set-apr") + .option( + "--cluster ", + "solana cluster: mainnet, testnet, devnet, localnet, ", + ) + .option( + "--programId ", + "Program ID: Specify the program ID when working on devnet, testnet, or localnet; it will not work on mainnet.", + ) + .option( + "--signer ", + "signer: the signer is the payer of the bless stake, default: " + + WALLET_PATH, + ) + .option( + "--admin ", + "admin: the admin of the bless stake, default: " + WALLET_PATH, + ) + .option( + "--squads ", + "squads: if true, use Squads to sign the transaction; default: false.", + ) + .description("set-apr: set the APR configuration of the bless stake"); +const mint = new Argument("mint", "mint: the public key of the mint token"); +mint.required = true; + +const apr = new Argument( + "apr", + 'apr: the APR configure, e.g. [{"periods": 0, "apr": { "numerator": 4, "denominator": 100 }},\ + {"periods": 1,"apr": { "numerator": 5, "denominator": 100 }},\ + {"periods": 4,"apr": { "numerator": 55, "denominator": 1000 }},\ + {"periods": 26,"apr": { "numerator": 6, "denominator": 100 }},\ + {"periods": 52,"apr": { "numerator": 7, "denominator": 100 }}]', +); +mint.required = true; +apr.required = true; + +setAprCommand + .addArgument(mint) + .addArgument(apr) + .action(async (mint, apr, options) => { + options.cluster = options.cluster || "localnet"; + options.signer = options.signer || getPath(WALLET_PATH); + + options.squads = options.squads || false; + try { + try { + apr = JSON.parse(apr); + } catch { + console.log(chalk.red("the APR configure must be json format. ")); + process.exit(1); + } + const keypair = readKeypair(options.signer); + const client = getBlsStakeContractClient( + options.cluster, + keypair, + options.programId, + ); + let mintPubkey = new PublicKey(mint); + const state = await client.blessStakeClient.getStakeState(mintPubkey); + if (options.squads) { + if (options.admin == null) { + console.log(chalk.red("admin is required.")); + process.exit(1); + } + const adminPubkey = new PublicKey(options.admin); + if (state.admin.toBase58() != adminPubkey.toBase58()) { + console.log( + chalk.red( + "Set apr configure is denied, admin is not matched, the state admin is " + + state.admin.toBase58(), + ), + ); + process.exit(1); + } + const tx = await client.blessStakeClient.blessStakeSetAprRangeTx( + mintPubkey, + adminPubkey, + apr, + { signer: adminPubkey }, + ); + const itx = await bs58Message( + client.connection, + tx.instructions, + keypair, + ); + console.log( + "Bless stake set apr configure transaction created: \n" + itx, + ); + } else { + options.admin = options.admin || getPath(WALLET_PATH); + const adminKeypair = readKeypair(options.admin); + if (state.admin.toBase58() != adminKeypair.publicKey.toBase58()) { + console.log( + chalk.red( + "Set APR configure is denied, admin is not matched, the state admin is " + + state.admin.toBase58(), + ), + ); + process.exit(1); + } + await client.blessStakeClient.blessStakeSetAprRange( + mintPubkey, + adminKeypair.publicKey, + apr, + { + signer: keypair.publicKey, + signerKeypair: [keypair, adminKeypair], + }, + ); + } + console.log(chalk.green("Stake contract set APR configure success.")); + process.exit(0); + } catch (e) { + console.log(chalk.red("Stake contract set APR configure failed: " + e)); + process.exit(1); + } + }); + +module.exports = setAprCommand; diff --git a/command/stake/set_apr_factor.js b/command/stake/set_apr_factor.js new file mode 100644 index 0000000..8b85cf3 --- /dev/null +++ b/command/stake/set_apr_factor.js @@ -0,0 +1,146 @@ +const { Command, Argument } = require("commander"); +const chalk = require("chalk"); +const { WALLET_PATH } = require("../../lib/constants"); +const { + getBlsStakeContractClient, + getPath, + readKeypair, + bs58Message, +} = require("../utils"); +const { PublicKey } = require("@solana/web3.js"); + +const setAprFactorCommand = new Command("set-factor") + .option( + "--cluster ", + "solana cluster: mainnet, testnet, devnet, localnet, ", + ) + .option( + "--programId ", + "Program ID: Specify the program ID when working on devnet, testnet, or localnet; it will not work on mainnet.", + ) + .option( + "--signer ", + "signer: the signer is the payer of the bless stake, default: " + + WALLET_PATH, + ) + .option( + "--admin ", + "admin: the admin of the bless stake, default: " + WALLET_PATH, + ) + .option( + "--squads ", + "squads: if true, use Squads to sign the transaction; default: false.", + ) + .description("set-factor: set the APR factor of the bless stake"); +const mint = new Argument("mint", "mint: the public key of the mint token"); +mint.required = true; + +const secondsPerPeriods = new Argument( + "secondsPerPeriods", + "secondsPerPeriods: the seconds per periods", +); +const periodsPerYear = new Argument( + "periodsPerYear", + "periodsPerYear: periods per year", +); +mint.required = true; +secondsPerPeriods.required = true; +periodsPerYear.required = true; + +const parseIntWithError = function (n, err) { + let num = null; + try { + num = parseInt(n); + } catch { + console.log(chalk.red(err)); + process.exit(1); + } + return num; +}; +setAprFactorCommand + .addArgument(mint) + .addArgument(secondsPerPeriods) + .addArgument(periodsPerYear) + .action(async (mint, secondsPerPeriods, periodsPerYear, options) => { + options.cluster = options.cluster || "localnet"; + options.signer = options.signer || getPath(WALLET_PATH); + + options.squads = options.squads || false; + try { + secondsPerPeriods = parseIntWithError( + secondsPerPeriods, + "the secondsPerPeriods must be number format. ", + ); + periodsPerYear = parseIntWithError( + periodsPerYear, + "the periodsPerYear must be number format. ", + ); + + const keypair = readKeypair(options.signer); + const client = getBlsStakeContractClient( + options.cluster, + keypair, + options.programId, + ); + let mintPubkey = new PublicKey(mint); + const state = await client.blessStakeClient.getStakeState(mintPubkey); + if (options.squads) { + if (options.admin == null) { + console.log(chalk.red("admin is required.")); + process.exit(1); + } + const adminPubkey = new PublicKey(options.admin); + if (state.admin.toBase58() != adminPubkey.toBase58()) { + console.log( + chalk.red( + "Set APR factor is denied, admin is not matched, the state admin is " + + state.admin.toBase58(), + ), + ); + process.exit(1); + } + const tx = await client.blessStakeClient.blessStakeSetAprFactorTx( + mintPubkey, + adminPubkey, + secondsPerPeriods, + periodsPerYear, + { signer: adminPubkey }, + ); + const itx = await bs58Message( + client.connection, + tx.instructions, + keypair, + ); + console.log("Bless stake set APR factor transaction created: \n" + itx); + } else { + options.admin = options.admin || getPath(WALLET_PATH); + const adminKeypair = readKeypair(options.admin); + if (state.admin.toBase58() != adminKeypair.publicKey.toBase58()) { + console.log( + chalk.red( + "Set APR factor is denied, admin is not matched, the state admin is " + + state.admin.toBase58(), + ), + ); + process.exit(1); + } + await client.blessStakeClient.blessStakeSetAprFactor( + mintPubkey, + adminKeypair.publicKey, + secondsPerPeriods, + periodsPerYear, + { + signer: keypair.publicKey, + signerKeypair: [keypair, adminKeypair], + }, + ); + } + console.log(chalk.green("Stake contract set APR factor success.")); + process.exit(0); + } catch (e) { + console.log(chalk.red("Stake contract set APR factor failed: " + e)); + process.exit(1); + } + }); + +module.exports = setAprFactorCommand; diff --git a/command/stake/set_pending_admin.js b/command/stake/set_pending_admin.js new file mode 100644 index 0000000..448bddb --- /dev/null +++ b/command/stake/set_pending_admin.js @@ -0,0 +1,124 @@ +const { Command, Argument } = require("commander"); +const chalk = require("chalk"); +const { WALLET_PATH } = require("../../lib/constants"); +const { + getBlsStakeContractClient, + getPath, + readKeypair, + bs58Message, +} = require("../utils"); +const { PublicKey } = require("@solana/web3.js"); + +const setPendingAdminCommand = new Command("pending-admin") + .option( + "--cluster ", + "solana cluster: mainnet, testnet, devnet, localnet, ", + ) + .option( + "--programId ", + "Program ID: Specify the program ID when working on devnet, testnet, or localnet; it will not work on mainnet.", + ) + .option( + "--signer ", + "signer: the signer is the payer of the bless stake, default: " + + WALLET_PATH, + ) + .option( + "--admin ", + "admin: the admin of the bless stake, default: " + WALLET_PATH, + ) + .option( + "--squads ", + "squads: if true, use Squads to sign the transaction; default: false.", + ) + .description( + "pending-admin: set the pending admin of the bless stake, the value is base58", + ); +const mint = new Argument("mint", "mint: the public key of the mint token"); +mint.required = true; +const pending = new Argument( + "pending-admin", + "pending-admin: the pending admin of the bless stake", +); +pending.required = true; + +setPendingAdminCommand + .addArgument(mint) + .addArgument(pending) + .action(async (mint, pending, options) => { + options.cluster = options.cluster || "localnet"; + options.signer = options.signer || getPath(WALLET_PATH); + + options.squads = options.squads || false; + try { + const keypair = readKeypair(options.signer); + const client = getBlsStakeContractClient( + options.cluster, + keypair, + options.programId, + ); + let pendingAdmin = new PublicKey(pending); + let mintPubkey = new PublicKey(mint); + const state = await client.blessStakeClient.getStakeState(mintPubkey); + if (options.squads) { + if (options.admin == null) { + console.log(chalk.red("admin is required.")); + process.exit(1); + } + const adminPubkey = new PublicKey(options.admin); + if (state.admin.toBase58() != adminPubkey.toBase58()) { + console.log( + chalk.red( + "Set pending admin is denied, admin is not matched, the state admin is " + + state.admin.toBase58(), + ), + ); + process.exit(1); + } + const tx = await client.blessStakeClient.blessStakeProposeAdminTx( + mintPubkey, + adminPubkey, + pendingAdmin, + { signer: adminPubkey }, + ); + const itx = await bs58Message( + client.connection, + tx.instructions, + keypair, + ); + console.log( + "Bless stake set pending admin transaction created: \n" + itx, + ); + } else { + options.admin = options.admin || getPath(WALLET_PATH); + const adminKeypair = readKeypair(options.admin); + if (state.admin.toBase58() != adminKeypair.publicKey.toBase58()) { + console.log( + chalk.red( + "Set pending admin is denied, admin is not matched, the state admin is " + + state.admin.toBase58(), + ), + ); + process.exit(1); + } + await client.blessStakeClient.blessStakeProposeAdmin( + mintPubkey, + adminKeypair.publicKey, + pendingAdmin, + { + signer: keypair.publicKey, + signerKeypair: [keypair, adminKeypair], + }, + ); + } + console.log(chalk.green("Stake contract set pending admin success.")); + process.exit(0); + } catch (e) { + console.log( + chalk.red("Stake contract set the pending admin failed: " + e), + ); + process.exit(1); + } + }); + +module.exports = setPendingAdminCommand; diff --git a/command/stake/stake_init.js b/command/stake/stake_init.js new file mode 100644 index 0000000..ce4dbea --- /dev/null +++ b/command/stake/stake_init.js @@ -0,0 +1,65 @@ +const { Command, Argument } = require("commander"); +const { getBlsStakeContractClient, getPath, readKeypair } = require("../utils"); +const { WALLET_PATH } = require("../../lib/constants"); +const chalk = require("chalk"); +const { PublicKey } = require("@solana/web3.js"); +const stakeInitializeCommand = new Command("init") + .option( + "--cluster ", + "solana cluster: mainnet, testnet, devnet, localnet, ", + ) + .option( + "--signer ", + "the signer is the admin of the stake contract: " + WALLET_PATH, + ) + .option( + "--programId ", + "Program ID: Specify the program ID when working on devnet, testnet, or localnet; it will not work on mainnet.", + ) + .description("init: initialize the stake state"); +const mint = new Argument( + "mint", + "mint: the mint is the mint token base58 value ", +); +const apr = new Argument( + "apr", + "apr: the APR configuration, e.g.\ + [{periods: 0, apr: { numerator: 4, denominator: 100 }},\ + {periods: 1,apr: { numerator: 5, denominator: 100 }},\ + {periods: 4,apr: { numerator: 55, denominator: 1000 }},\ + {periods: 26,apr: { numerator: 6, denominator: 100 }},\ + {periods: 52,apr: { numerator: 7, denominator: 100 }}]", +); +apr.required = false; +mint.required = true; +stakeInitializeCommand + .addArgument(mint) + .addArgument(apr) + .action(async (mint, apr, options) => { + options.cluster = options.cluster || "localnet"; + options.signer = options.signer || getPath(WALLET_PATH); + try { + const keypair = readKeypair(options.signer); + const client = getBlsStakeContractClient( + options.cluster, + keypair, + options.programId, + ); + let mintPubkey = null; + try { + mintPubkey = new PublicKey(mint); + } catch (e) { + console.log(chalk.red("Invalid mint parameter: " + e)); + process.exit(1); + } + if (apr == null) apr = []; + await client.blessStakeClient.initializeBlessStakeState(mintPubkey, apr); + console.log(chalk.green("Stake state initialization complete.")); + process.exit(0); + } catch (e) { + console.log(chalk.red("Stake state initialization failed: " + e)); + process.exit(1); + } + }); + +module.exports = stakeInitializeCommand; diff --git a/command/stake/unstake.js b/command/stake/unstake.js new file mode 100644 index 0000000..4970277 --- /dev/null +++ b/command/stake/unstake.js @@ -0,0 +1,98 @@ +const { Command, Argument } = require("commander"); +const { + getBlsStakeContractClient, + getPath, + readKeypair, + bs58Message, +} = require("../utils"); +const { WALLET_PATH } = require("../../lib/constants"); +const anchor = require("@coral-xyz/anchor"); +const chalk = require("chalk"); +const { PublicKey } = require("@solana/web3.js"); +const unstakeCommand = new Command("unstake") + .option( + "--cluster ", + "solana cluster: mainnet, testnet, devnet, localnet, ", + ) + .option( + "--signer ", + "the signer is the admin of the stake contract: " + WALLET_PATH, + ) + .option( + "--squads ", + "squads: if true, use Squads to sign the transaction; default: false.", + ) + .option( + "--programId ", + "Program ID: Specify the program ID when working on devnet, testnet, or localnet; it will not work on mainnet.", + ) + .description("unstake: unstake with the sequence number"); +const mint = new Argument( + "mint", + "mint: the mint is the mint token base58 value ", +); +const seq = new Argument("sequence", "the stake sequence."); +seq.required = true; +mint.required = true; +unstakeCommand + .addArgument(mint) + .addArgument(seq) + .action(async (mint, seq, options) => { + options.cluster = options.cluster || "localnet"; + options.signer = options.signer || getPath(WALLET_PATH); + try { + seq = new anchor.BN(parseInt(seq)); + } catch { + console.log(chalk.red("sequence must be a number")); + process.exit(1); + } + try { + const keypair = readKeypair(options.signer); + const client = getBlsStakeContractClient( + options.cluster, + keypair, + options.programId, + ); + let mintPubkey = null; + try { + mintPubkey = new PublicKey(mint); + } catch (e) { + console.log(chalk.red("Invalid mint parameter: " + e)); + process.exit(1); + } + + if (options.squads) { + const tx = await client.blessStakeClient.blessUserUnstakeTx( + mintPubkey, + seq, + { + signer: keypair.publicKey, + signerKeypair: [keypair], + }, + ); + const itx = await bs58Message( + client.connection, + tx.instructions, + keypair, + ); + console.log(`User unstake transaction created : ${itx}`); + } else { + const keypair = readKeypair(options.signer); + const tx = await client.blessStakeClient.blessUserUnstake( + mintPubkey, + seq, + { + signer: keypair.publicKey, + signerKeypair: [keypair], + }, + ); + console.log(chalk.green(`User unstake success, tx: ${tx}`)); + process.exit(0); + } + } catch (e) { + console.log(chalk.red("User unstake failed: " + e)); + process.exit(1); + } + }); + +module.exports = unstakeCommand; diff --git a/command/stake/withdraw.js b/command/stake/withdraw.js new file mode 100644 index 0000000..0878281 --- /dev/null +++ b/command/stake/withdraw.js @@ -0,0 +1,98 @@ +const { Command, Argument } = require("commander"); +const { + getBlsStakeContractClient, + getPath, + readKeypair, + bs58Message, +} = require("../utils"); +const { WALLET_PATH } = require("../../lib/constants"); +const anchor = require("@coral-xyz/anchor"); +const chalk = require("chalk"); +const { PublicKey } = require("@solana/web3.js"); +const withdrawCommand = new Command("withdraw") + .option( + "--cluster ", + "solana cluster: mainnet, testnet, devnet, localnet, ", + ) + .option( + "--signer ", + "the signer is the admin of the stake contract: " + WALLET_PATH, + ) + .option( + "--squads ", + "squads: if true, use Squads to sign the transaction; default: false.", + ) + .option( + "--programId ", + "Program ID: Specify the program ID when working on devnet, testnet, or localnet; it will not work on mainnet.", + ) + .description("withdraw: withdraw with the sequence number"); +const mint = new Argument( + "mint", + "mint: the mint is the mint token base58 value ", +); +const seq = new Argument("sequence", "the stake sequence."); +seq.required = true; +mint.required = true; +withdrawCommand + .addArgument(mint) + .addArgument(seq) + .action(async (mint, seq, options) => { + options.cluster = options.cluster || "localnet"; + options.signer = options.signer || getPath(WALLET_PATH); + try { + seq = new anchor.BN(parseInt(seq)); + } catch { + console.log(chalk.red("sequence must be a number")); + process.exit(1); + } + try { + const keypair = readKeypair(options.signer); + const client = getBlsStakeContractClient( + options.cluster, + keypair, + options.programId, + ); + let mintPubkey = null; + try { + mintPubkey = new PublicKey(mint); + } catch (e) { + console.log(chalk.red("Invalid mint parameter: " + e)); + process.exit(1); + } + + if (options.squads) { + const tx = await client.blessStakeClient.blessUserWithdrawTx( + mintPubkey, + seq, + { + signer: keypair.publicKey, + signerKeypair: [keypair], + }, + ); + const itx = await bs58Message( + client.connection, + tx.instructions, + keypair, + ); + console.log(`User withdraw transaction created : ${itx}`); + } else { + const keypair = readKeypair(options.signer); + const tx = await client.blessStakeClient.blessUserWithdraw( + mintPubkey, + seq, + { + signer: keypair.publicKey, + signerKeypair: [keypair], + }, + ); + console.log(chalk.green(`User withdraw success, tx: ${tx}`)); + process.exit(0); + } + } catch (e) { + console.log(chalk.red("User withdraw failed: " + e)); + process.exit(1); + } + }); + +module.exports = withdrawCommand; diff --git a/command/time/index.js b/command/time/index.js new file mode 100644 index 0000000..aea04c5 --- /dev/null +++ b/command/time/index.js @@ -0,0 +1,3 @@ +const timeCommand = require("./time.js") + +module.exports = timeCommand; \ No newline at end of file diff --git a/command/time.js b/command/time/time.js similarity index 100% rename from command/time.js rename to command/time/time.js diff --git a/command/time_accept_admin.js b/command/time/time_accept_admin.js similarity index 90% rename from command/time_accept_admin.js rename to command/time/time_accept_admin.js index 9f6732e..b6223a9 100644 --- a/command/time_accept_admin.js +++ b/command/time/time_accept_admin.js @@ -1,13 +1,13 @@ const { Command, Argument } = require("commander"); const anchor = require("@coral-xyz/anchor"); const chalk = require("chalk"); -const { WALLET_PATH } = require("../lib/constants"); +const { WALLET_PATH } = require("../../lib/constants"); const { getBlsTimeContractClient, getPath, readKeypair, bs58Message, -} = require("./utils"); +} = require("../utils"); const { PublicKey } = require("@solana/web3.js"); const timeAcceptAdminCommand = new Command("accept-admin") @@ -21,11 +21,11 @@ const timeAcceptAdminCommand = new Command("accept-admin") ) .option( "--squads ", - "squads: if squads true, use squads to signature, default is false.", + "squads: if true, use Squads to sign the transaction; default: false.", ) .option( "--pending ", - "pending: if squads true, use pending admin to signature in squads", + "pending: if squads true, use pending admin to signature in Squads", ) .option( "--signer ", @@ -51,7 +51,7 @@ timeAcceptAdminCommand.addArgument(mint).action(async (mint, options) => { try { mintPubkey = new PublicKey(mint); } catch (e) { - console.log(chalk.red("invaild mint parameter: " + e)); + console.log(chalk.red("invalid mint parameter: " + e)); process.exit(1); } const state = await client.blessTimeClient.getTimeState(mintPubkey); @@ -95,7 +95,7 @@ timeAcceptAdminCommand.addArgument(mint).action(async (mint, options) => { process.exit(0); } } catch (e) { - console.log(chalk.red("accept admin of time contract fail: " + e)); + console.log(chalk.red("accept admin of time contract failed: " + e)); process.exit(1); } }); diff --git a/command/time_init.js b/command/time/time_init.js similarity index 88% rename from command/time_init.js rename to command/time/time_init.js index 72c6472..6c31398 100644 --- a/command/time_init.js +++ b/command/time/time_init.js @@ -1,6 +1,6 @@ const { Command, Argument } = require("commander"); -const { getBlsTimeContractClient, getPath, readKeypair } = require("./utils"); -const { WALLET_PATH } = require("../lib/constants"); +const { getBlsTimeContractClient, getPath, readKeypair } = require("../utils"); +const { WALLET_PATH } = require("../../lib/constants"); const chalk = require("chalk"); const { PublicKey } = require("@solana/web3.js"); const timeInitCommand = new Command("init") @@ -36,14 +36,14 @@ timeInitCommand.addArgument(mint).action(async (mint, options) => { try { mintPubkey = new PublicKey(mint); } catch (e) { - console.log(chalk.red("invaild mint parameter: " + e)); + console.log(chalk.red("invalid mint parameter: " + e)); process.exit(1); } await client.blessTimeClient.initializeBlessTimeState(mintPubkey); console.log(chalk.green("time state initial success.")); process.exit(0); } catch (e) { - console.log(chalk.red("time state initial fail: " + e)); + console.log(chalk.red("time state initial failed: " + e)); process.exit(1); } }); diff --git a/command/time_set_merkle_tree.js b/command/time/time_set_merkle_tree.js similarity index 90% rename from command/time_set_merkle_tree.js rename to command/time/time_set_merkle_tree.js index dbb3ba9..e974ca3 100644 --- a/command/time_set_merkle_tree.js +++ b/command/time/time_set_merkle_tree.js @@ -4,8 +4,8 @@ const { getPath, readKeypair, bs58Message, -} = require("./utils"); -const { WALLET_PATH } = require("../lib/constants"); +} = require("../utils"); +const { WALLET_PATH } = require("../../lib/constants"); const chalk = require("chalk"); const { PublicKey } = require("@solana/web3.js"); const timeSetMerkleRootCommand = new Command("merkle-root") @@ -23,7 +23,7 @@ const timeSetMerkleRootCommand = new Command("merkle-root") ) .option( "--squads ", - "squads: if squads true, use squads to signature, default is false.", + "squads: if true, use Squads to sign the transaction; default: false.", ) .option( "--admin ", @@ -52,7 +52,7 @@ timeSetMerkleRootCommand try { mintPubkey = new PublicKey(mint); } catch (e) { - console.log(chalk.red("invaild mint parameter: " + e)); + console.log(chalk.red("invalid mint parameter: " + e)); process.exit(1); } const client = getBlsTimeContractClient( @@ -80,7 +80,7 @@ timeSetMerkleRootCommand try { merkleTreeRootBuff = new PublicKey(merkleTreeRoot).toBuffer(); } catch (e) { - console.log(chalk.red("invaild merkle tree parameter: " + e)); + console.log(chalk.red("invalid merkle tree parameter: " + e)); process.exit(1); } const tx = await client.blessTimeClient.getSetMerkleTreeRootTx( @@ -112,7 +112,7 @@ timeSetMerkleRootCommand try { merkleTreeRootBuff = new PublicKey(merkleTreeRoot).toBuffer(); } catch (e) { - console.log(chalk.red("invaild merkle tree parameter: " + e)); + console.log(chalk.red("invalid merkle tree parameter: " + e)); process.exit(1); } await client.blessTimeClient.setMerkleTreeRoot( @@ -123,7 +123,7 @@ timeSetMerkleRootCommand process.exit(0); } } catch (e) { - console.log(chalk.red("set merkle tree fail: " + e)); + console.log(chalk.red("set merkle tree failed: " + e)); process.exit(1); } }); diff --git a/command/time_set_pause.js b/command/time/time_set_pause.js similarity index 92% rename from command/time_set_pause.js rename to command/time/time_set_pause.js index d00580c..1fe40c2 100644 --- a/command/time_set_pause.js +++ b/command/time/time_set_pause.js @@ -4,8 +4,8 @@ const { getPath, readKeypair, bs58Message, -} = require("./utils"); -const { WALLET_PATH } = require("../lib/constants"); +} = require("../utils"); +const { WALLET_PATH } = require("../../lib/constants"); const chalk = require("chalk"); const { PublicKey } = require("@solana/web3.js"); const timeSetPausedCommand = new Command("set-paused") @@ -23,7 +23,7 @@ const timeSetPausedCommand = new Command("set-paused") ) .option( "--squads ", - "squads: if squads true, use squads to signature, default is false.", + "squads: if true, use Squads to sign the transaction; default: false.", ) .option( "--admin ", @@ -48,7 +48,7 @@ timeSetPausedCommand try { mintPubkey = new PublicKey(mint); } catch (e) { - console.log(chalk.red("invaild mint parameter: " + e)); + console.log(chalk.red("invalid mint parameter: " + e)); process.exit(1); } const client = getBlsTimeContractClient( @@ -108,7 +108,7 @@ timeSetPausedCommand process.exit(0); } } catch (e) { - console.log(chalk.red("set paused fail: " + e)); + console.log(chalk.red("set paused failed: " + e)); process.exit(1); } }); diff --git a/command/time_set_pending_admin.js b/command/time/time_set_pending_admin.js similarity index 92% rename from command/time_set_pending_admin.js rename to command/time/time_set_pending_admin.js index a2c1577..3b186fa 100644 --- a/command/time_set_pending_admin.js +++ b/command/time/time_set_pending_admin.js @@ -1,13 +1,13 @@ const { Command, Argument } = require("commander"); const anchor = require("@coral-xyz/anchor"); const chalk = require("chalk"); -const { WALLET_PATH } = require("../lib/constants"); +const { WALLET_PATH } = require("../../lib/constants"); const { getBlsTimeContractClient, getPath, readKeypair, bs58Message, -} = require("./utils"); +} = require("../utils"); const { PublicKey } = require("@solana/web3.js"); const timeSetPendingAdminCommand = new Command("pending-admin") @@ -26,7 +26,7 @@ const timeSetPendingAdminCommand = new Command("pending-admin") ) .option( "--squads ", - "squads: if squads true, use squads to signature, default is false.", + "squads: if true, use Squads to sign the transaction; default: false.", ) .option( "--admin ", @@ -62,7 +62,7 @@ timeSetPendingAdminCommand try { mintPubkey = new PublicKey(mint); } catch (e) { - console.log(chalk.red("invaild mint parameter: " + e)); + console.log(chalk.red("invalid mint parameter: " + e)); process.exit(1); } @@ -118,7 +118,7 @@ timeSetPendingAdminCommand } process.exit(0); } catch (e) { - console.log(chalk.red("set the pending admin fail: " + e)); + console.log(chalk.red("set the pending admin failed: " + e)); process.exit(1); } }); diff --git a/command/tools/index.js b/command/tools/index.js new file mode 100644 index 0000000..0042ff8 --- /dev/null +++ b/command/tools/index.js @@ -0,0 +1,3 @@ +const toolsCommand = require("./tools.js"); + +module.exports = toolsCommand; \ No newline at end of file diff --git a/command/tools.js b/command/tools/tools.js similarity index 100% rename from command/tools.js rename to command/tools/tools.js diff --git a/command/tools_gen_users.js b/command/tools/tools_gen_users.js similarity index 95% rename from command/tools_gen_users.js rename to command/tools/tools_gen_users.js index 0899fa9..ef4a63b 100644 --- a/command/tools_gen_users.js +++ b/command/tools/tools_gen_users.js @@ -3,7 +3,7 @@ const { Keypair } = require("@solana/web3.js"); const chalk = require("chalk"); const fs = require("fs"); const cliProgress = require("cli-progress"); -const { formatTime } = require("./utils.js"); +const { formatTime } = require("../utils.js"); const genUsersDoCommand = new Command("gen_users") .option("--file", "Output file path (default: ./users.json)") @@ -54,7 +54,7 @@ genUsersDoCommand.addArgument(num).action(async (num, options) => { console.log( chalk.green( "\nSuccessfully generated users, time spent: " + - formatTime((new Date().getTime() - now) / 1000), + formatTime((new Date().getTime() - now) / 1000), ), ); process.exit(0); diff --git a/command/tools_merkle_root.js b/command/tools/tools_merkle_root.js similarity index 91% rename from command/tools_merkle_root.js rename to command/tools/tools_merkle_root.js index 6ea6072..fa194af 100644 --- a/command/tools_merkle_root.js +++ b/command/tools/tools_merkle_root.js @@ -1,17 +1,15 @@ const { Command, Argument } = require("commander"); -const { Keypair, PublicKey } = require("@solana/web3.js"); +const { PublicKey } = require("@solana/web3.js"); const chalk = require("chalk"); const fs = require("fs"); const cliProgress = require("cli-progress"); const { streamArray } = require("stream-json/streamers/StreamArray"); const { chain } = require("stream-chain"); const { parser } = require("stream-json"); -const { pick } = require("stream-json/filters/Pick"); const anchor = require("@coral-xyz/anchor"); const keccak256 = require("keccak256"); const { MerkleTree } = require("merkletreejs"); -const { formatTime } = require("./utils.js"); -const assert = require("assert"); +const { formatTime } = require("../utils.js"); const { bs58 } = require("@coral-xyz/anchor/dist/cjs/utils/bytes/index.js"); const genMerkleTreeCommand = new Command("gen_merkle_tree") @@ -79,7 +77,7 @@ genMerkleTreeCommand.addArgument(file).action(async (file, options) => { ]); pipeline.on("end", () => { const tree = new MerkleTree(leaves, keccak256, { sortPairs: true }); - delete leaves; + leaves = null; bar.update(50); writeStream.write("["); pipeline2.on("data", ({ key, value }) => { @@ -122,9 +120,9 @@ genMerkleTreeCommand.addArgument(file).action(async (file, options) => { console.log( chalk.green( "\nMerkle tree root:" + - new PublicKey(tree.getRoot()).toBase58() + - ", spent time: " + - formatTime((new Date().getTime() - now) / 1000), + new PublicKey(tree.getRoot()).toBase58() + + ", spent time: " + + formatTime((new Date().getTime() - now) / 1000), " total: " + (last + 1), ), ); diff --git a/command/utils.js b/command/utils.js index 371bd42..dce6efc 100644 --- a/command/utils.js +++ b/command/utils.js @@ -19,6 +19,11 @@ const { BlsClient: BlsTimeContractClient, setDevProgramId: setBlsTimeContractDevProgramId, } = require("@blessnetwork/bless-time-contract"); + +const { + BlsClient: BlsStakeContractClient, + setDevProgramId: setBlsStakeContractDevProgramId, +} = require("@blessnetwork/bless-stake"); const { bs58 } = require("@coral-xyz/anchor/dist/cjs/utils/bytes"); const getProvider = (input) => { let url = input; @@ -88,6 +93,20 @@ function getBlsTimeContractClient(net, keypair, programId) { return client; } +function getBlsStakeContractClient(net, keypair, programId) { + if (programId != null) + setBlsStakeContractDevProgramId(new PublicKey(programId)); + const connection = getConnection(net); + + const wallet = new anchor.Wallet(keypair); + const provider = new anchor.AnchorProvider(connection, wallet, { + commitment: "confirmed", + }); + + const client = new BlsStakeContractClient({ provider }); + return client; +} + const getMetadata = async (uri) => { const resp = await fetch(uri); const metaJson = await resp.json(); @@ -163,5 +182,6 @@ module.exports = { getBlsContractClient, getProvider, getBlsTimeContractClient, + getBlsStakeContractClient, BlessTokenAccounts, }; diff --git a/index.js b/index.js index 19fb654..1dec08c 100755 --- a/index.js +++ b/index.js @@ -4,17 +4,22 @@ const packageJson = require("./package.json"); const Box = require("cli-box"); const chalk = require("chalk"); const { Command } = require("commander"); -const registerCommand = require("./command/register.js"); +const registerCommand = require("./command/register"); const blesstokenCommand = require("./command/bless_token.js"); -const timeCommand = require("./command/time.js"); +const timeCommand = require("./command/time"); const analyzeCommand = require("./command/analyze.js"); -const programCommand = require("./command/program.js"); -const toolsCommand = require("./command/tools.js"); -const tokenMetaSetAdminCommand = require("./command/bles_meta_set_pending_admin.js"); -const tokenMetaAcceptAdminCommand = require("./command/bles_meta_accept_admin.js"); -const blessMetaUpdateCommand = require("./command/bles_meta_update.js"); -const blessMetaCreateCommand = require("./command/bles_meta_create.js"); -const blessMetaInitCommand = require("./command/bles_meta_init.js"); +const programCommand = require("./command/program/program.js"); +const toolsCommand = require("./command/tools"); +const stakeCommand = require("./command/stake"); + +const { + blessMetaInitCommand, + blessMetaCreateCommand, + blessMetaUpdateCommand, + tokenMetaSetAdminCommand, + tokenMetaAcceptAdminCommand, +} = require("./command/meta") + const program = new Command(); async function main() { @@ -45,6 +50,7 @@ async function main() { program.addCommand(timeCommand); program.addCommand(programCommand); program.addCommand(toolsCommand); + program.addCommand(stakeCommand); const tokenMetaCommand = new Command("token-meta").description( "token-meta: the operations for the bless token meta.", ); diff --git a/package-lock.json b/package-lock.json index 50819ea..33e165f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "license": "ISC", "dependencies": { "@blessnetwork/bless-contract": "^0.0.5", + "@blessnetwork/bless-stake": "^0.0.2", "@blessnetwork/bless-time-contract": "^0.0.4", "@blessnetwork/node-verification-ledger": "^0.0.7", "@coral-xyz/anchor": "^0.31.1", @@ -580,6 +581,86 @@ "vite-plugin-dts": "^4.5.4" } }, + "node_modules/@blessnetwork/bless-stake": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/@blessnetwork/bless-stake/-/bless-stake-0.0.2.tgz", + "integrity": "sha512-b6jwKxGIEWJ2g2EChmG8szjMaub0UMSmAXPu2HUDQP6C9bxoAci9RLbW2pGJYURsthA+cylL1ku4wjGiUwpL4A==", + "license": "MIT", + "dependencies": { + "@coral-xyz/anchor": "^0.32.1", + "@noble/ed25519": "^1.6.0", + "@radix-ui/react-dialog": "^1.1.11", + "@radix-ui/react-dropdown-menu": "^2.1.12", + "@radix-ui/react-label": "^2.1.4", + "@radix-ui/react-slot": "^1.2.0", + "@solana/spl-token": "^0.4.13", + "@solana/wallet-adapter-base": "0.9.26", + "@solana/wallet-adapter-react": "0.15.38", + "@solana/wallet-adapter-react-ui": "0.9.38", + "@solana/web3.js": "1.98.2", + "@tailwindcss/vite": "^4.1.4", + "@tanstack/react-query": "^5.74.7", + "bs58": "^6.0.0", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "jotai": "^2.12.3", + "lucide-react": "^0.503.0", + "next-themes": "^0.4.6", + "react": "^19.1.0", + "react-dom": "^19.1.0", + "react-router": "^7.5.2", + "sonner": "^2.0.3", + "tailwind-merge": "^3.2.0", + "tailwindcss": "^4.1.4", + "tnode": "^0.1.1", + "toml": "^3.0.0", + "tw-animate-css": "^1.2.8", + "tweetnacl": "^1.0.3", + "vite-plugin-dts": "^4.5.4" + } + }, + "node_modules/@blessnetwork/bless-stake/node_modules/@coral-xyz/anchor": { + "version": "0.32.1", + "resolved": "https://registry.npmjs.org/@coral-xyz/anchor/-/anchor-0.32.1.tgz", + "integrity": "sha512-zAyxFtfeje2FbMA1wzgcdVs7Hng/MijPKpRijoySPCicnvcTQs/+dnPZ/cR+LcXM9v9UYSyW81uRNYZtN5G4yg==", + "license": "(MIT OR Apache-2.0)", + "dependencies": { + "@coral-xyz/anchor-errors": "^0.31.1", + "@coral-xyz/borsh": "^0.31.1", + "@noble/hashes": "^1.3.1", + "@solana/web3.js": "^1.69.0", + "bn.js": "^5.1.2", + "bs58": "^4.0.1", + "buffer-layout": "^1.2.2", + "camelcase": "^6.3.0", + "cross-fetch": "^3.1.5", + "eventemitter3": "^4.0.7", + "pako": "^2.0.3", + "superstruct": "^0.15.4", + "toml": "^3.0.0" + }, + "engines": { + "node": ">=17" + } + }, + "node_modules/@blessnetwork/bless-stake/node_modules/@coral-xyz/anchor/node_modules/bs58": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", + "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", + "license": "MIT", + "dependencies": { + "base-x": "^3.0.2" + } + }, + "node_modules/@blessnetwork/bless-stake/node_modules/base-x": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.11.tgz", + "integrity": "sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, "node_modules/@blessnetwork/bless-time-contract": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/@blessnetwork/bless-time-contract/-/bless-time-contract-0.0.4.tgz", diff --git a/package.json b/package.json index 3ed1c7b..01f51de 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "author": "bless", "license": "ISC", "dependencies": { + "@blessnetwork/bless-stake": "^0.0.2", "@blessnetwork/bless-contract": "^0.0.5", "@blessnetwork/bless-time-contract": "^0.0.4", "@blessnetwork/node-verification-ledger": "^0.0.7",