naracli 1.0.56 → 1.0.58
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/nara-cli.ts +3 -3
- package/dist/nara-cli-bundle.cjs +103 -17
- package/package.json +1 -1
- package/src/cli/commands/agent.ts +3 -3
- package/src/cli/commands/quest.ts +88 -10
- package/src/cli/commands/skills.ts +1 -1
- package/src/cli/commands/wallet.ts +2 -2
- package/src/cli/index.ts +5 -5
package/bin/nara-cli.ts
CHANGED
|
@@ -15,13 +15,13 @@ const program = new Command();
|
|
|
15
15
|
// Set program metadata
|
|
16
16
|
program
|
|
17
17
|
.name("naracli")
|
|
18
|
-
.description("CLI for the Nara chain (
|
|
18
|
+
.description("CLI for the Nara chain. Native coin is NARA (not SOL). Mine NARA for free via PoMI quests, manage wallets, register agents, and more. Run 'naracli <command> --help' for details on any command.")
|
|
19
19
|
.version(version);
|
|
20
20
|
|
|
21
21
|
// Add global options
|
|
22
22
|
program
|
|
23
|
-
.option("-r, --rpc-url <url>", "RPC endpoint
|
|
24
|
-
.option("-w, --wallet <path>", "Path to wallet keypair JSON file")
|
|
23
|
+
.option("-r, --rpc-url <url>", "RPC endpoint (default: https://mainnet-api.nara.build/)")
|
|
24
|
+
.option("-w, --wallet <path>", "Path to wallet keypair JSON file (default: ~/.config/nara/id.json)")
|
|
25
25
|
.option("-j, --json", "Output in JSON format");
|
|
26
26
|
|
|
27
27
|
// Register all command modules
|
package/dist/nara-cli-bundle.cjs
CHANGED
|
@@ -126972,6 +126972,29 @@ async function getStakeInfo(connection, user, options) {
|
|
|
126972
126972
|
return null;
|
|
126973
126973
|
}
|
|
126974
126974
|
}
|
|
126975
|
+
async function getQuestConfig(connection, options) {
|
|
126976
|
+
const kp = import_web390.Keypair.generate();
|
|
126977
|
+
const program3 = createProgram2(connection, kp, options?.programId);
|
|
126978
|
+
const programId = new import_web390.PublicKey(options?.programId ?? DEFAULT_QUEST_PROGRAM_ID);
|
|
126979
|
+
const [configPda] = import_web390.PublicKey.findProgramAddressSync(
|
|
126980
|
+
[new TextEncoder().encode("quest_config")],
|
|
126981
|
+
programId
|
|
126982
|
+
);
|
|
126983
|
+
const config = await program3.account.gameConfig.fetch(configPda);
|
|
126984
|
+
return {
|
|
126985
|
+
authority: config.authority,
|
|
126986
|
+
minRewardCount: config.minRewardCount,
|
|
126987
|
+
maxRewardCount: config.maxRewardCount,
|
|
126988
|
+
stakeBpsHigh: Number(config.stakeBpsHigh.toString()),
|
|
126989
|
+
stakeBpsLow: Number(config.stakeBpsLow.toString()),
|
|
126990
|
+
decayMs: Number(config.decayMs.toString()),
|
|
126991
|
+
treasury: config.treasury,
|
|
126992
|
+
questAuthority: config.questAuthority,
|
|
126993
|
+
minQuestInterval: Number(config.minQuestInterval.toString()),
|
|
126994
|
+
rewardPerShare: Number(config.rewardPerShare.toString()),
|
|
126995
|
+
extraReward: Number(config.extraReward.toString())
|
|
126996
|
+
};
|
|
126997
|
+
}
|
|
126975
126998
|
|
|
126976
126999
|
// node_modules/.pnpm/nara-sdk@1.0.54_bufferutil@4.1.0_fastestsmallesttextencoderdecoder@1.0.22_typescript@5.9.3_utf-8-validate@6.0.6/node_modules/nara-sdk/src/skills.ts
|
|
126977
127000
|
var import_web391 = __toESM(require_index_cjs(), 1);
|
|
@@ -130513,8 +130536,8 @@ ${result.base64}`);
|
|
|
130513
130536
|
var _DEFAULT_WALLET_PATH = process.env.WALLET_PATH || "~/.config/nara/id.json";
|
|
130514
130537
|
var DEFAULT_WALLET_PATH2 = _DEFAULT_WALLET_PATH.startsWith("~") ? (0, import_node_path3.join)((0, import_node_os3.homedir)(), _DEFAULT_WALLET_PATH.slice(1)) : _DEFAULT_WALLET_PATH;
|
|
130515
130538
|
function registerWalletCommands(program3) {
|
|
130516
|
-
const wallet = program3.command("wallet").description("Wallet management
|
|
130517
|
-
wallet.command("create").description("Create a new wallet").option("-o, --output <path>", "Output path for wallet file (default: ~/.config/nara/id.json)").action(async (options) => {
|
|
130539
|
+
const wallet = program3.command("wallet").description("Wallet management \u2014 create or import a keypair for signing transactions");
|
|
130540
|
+
wallet.command("create").description("Create a new wallet keypair (saved to ~/.config/nara/id.json by default)").option("-o, --output <path>", "Output path for wallet file (default: ~/.config/nara/id.json)").action(async (options) => {
|
|
130518
130541
|
try {
|
|
130519
130542
|
await handleWalletCreate(options);
|
|
130520
130543
|
} catch (error) {
|
|
@@ -130963,6 +130986,14 @@ async function handleQuestGet(options) {
|
|
|
130963
130986
|
}
|
|
130964
130987
|
return;
|
|
130965
130988
|
}
|
|
130989
|
+
let stakeRequired = quest.effectiveStakeRequirement > 0;
|
|
130990
|
+
try {
|
|
130991
|
+
const config = await getQuestConfig(connection);
|
|
130992
|
+
if (quest.rewardCount < config.maxRewardCount) {
|
|
130993
|
+
stakeRequired = false;
|
|
130994
|
+
}
|
|
130995
|
+
} catch {
|
|
130996
|
+
}
|
|
130966
130997
|
const data = {
|
|
130967
130998
|
round: quest.round,
|
|
130968
130999
|
question: quest.question,
|
|
@@ -130974,7 +131005,8 @@ async function handleQuestGet(options) {
|
|
|
130974
131005
|
deadline: new Date(quest.deadline * 1e3).toLocaleString(),
|
|
130975
131006
|
timeRemaining: formatTimeRemaining(quest.timeRemaining),
|
|
130976
131007
|
expired: quest.expired,
|
|
130977
|
-
|
|
131008
|
+
stakeRequired,
|
|
131009
|
+
stakeRequirement: stakeRequired ? `${quest.effectiveStakeRequirement.toFixed(4)} NARA` : "0 NARA",
|
|
130978
131010
|
stakeHigh: `${quest.stakeHigh} NARA`,
|
|
130979
131011
|
stakeLow: `${quest.stakeLow} NARA`,
|
|
130980
131012
|
avgParticipantStake: `${quest.avgParticipantStake} NARA`
|
|
@@ -130991,8 +131023,10 @@ async function handleQuestGet(options) {
|
|
|
130991
131023
|
console.log(
|
|
130992
131024
|
` Reward slots: ${quest.winnerCount}/${quest.rewardCount} (${quest.remainingSlots} remaining)`
|
|
130993
131025
|
);
|
|
130994
|
-
if (
|
|
131026
|
+
if (stakeRequired) {
|
|
130995
131027
|
console.log(` Stake requirement: ${quest.effectiveStakeRequirement.toFixed(4)} NARA (decays ${quest.stakeHigh} \u2192 ${quest.stakeLow})`);
|
|
131028
|
+
} else {
|
|
131029
|
+
console.log(` Stake requirement: none`);
|
|
130996
131030
|
}
|
|
130997
131031
|
console.log(` Deadline: ${new Date(quest.deadline * 1e3).toLocaleString()}`);
|
|
130998
131032
|
if (quest.timeRemaining > 0) {
|
|
@@ -131003,6 +131037,49 @@ async function handleQuestGet(options) {
|
|
|
131003
131037
|
console.log("");
|
|
131004
131038
|
}
|
|
131005
131039
|
}
|
|
131040
|
+
async function handleQuestConfig(options) {
|
|
131041
|
+
const rpcUrl = getRpcUrl(options.rpcUrl);
|
|
131042
|
+
const connection = new import_web398.Connection(rpcUrl, "confirmed");
|
|
131043
|
+
let config;
|
|
131044
|
+
try {
|
|
131045
|
+
config = await getQuestConfig(connection);
|
|
131046
|
+
} catch (err) {
|
|
131047
|
+
printError(`Failed to fetch quest config: ${err.message}`);
|
|
131048
|
+
process.exit(1);
|
|
131049
|
+
}
|
|
131050
|
+
const DECIMALS = 1e9;
|
|
131051
|
+
const rewardPerShare = config.rewardPerShare / DECIMALS;
|
|
131052
|
+
const extraReward = config.extraReward / DECIMALS;
|
|
131053
|
+
const stakeBpsHigh = config.stakeBpsHigh;
|
|
131054
|
+
const stakeBpsLow = config.stakeBpsLow;
|
|
131055
|
+
const data = {
|
|
131056
|
+
authority: config.authority.toBase58(),
|
|
131057
|
+
questAuthority: config.questAuthority.toBase58(),
|
|
131058
|
+
treasury: config.treasury.toBase58(),
|
|
131059
|
+
minRewardCount: config.minRewardCount,
|
|
131060
|
+
maxRewardCount: config.maxRewardCount,
|
|
131061
|
+
rewardPerShare,
|
|
131062
|
+
extraReward,
|
|
131063
|
+
stakeBpsHigh,
|
|
131064
|
+
stakeBpsLow,
|
|
131065
|
+
decayMs: config.decayMs,
|
|
131066
|
+
minQuestInterval: config.minQuestInterval
|
|
131067
|
+
};
|
|
131068
|
+
if (options.json) {
|
|
131069
|
+
formatOutput(data, true);
|
|
131070
|
+
} else {
|
|
131071
|
+
console.log("");
|
|
131072
|
+
console.log(` Min Reward Count: ${data.minRewardCount}`);
|
|
131073
|
+
console.log(` Max Reward Count: ${data.maxRewardCount}`);
|
|
131074
|
+
console.log(` Reward Per Share: ${rewardPerShare} NARA`);
|
|
131075
|
+
console.log(` Extra Reward: ${extraReward} NARA`);
|
|
131076
|
+
console.log(` Stake BPS High: ${stakeBpsHigh / 100}%`);
|
|
131077
|
+
console.log(` Stake BPS Low: ${stakeBpsLow / 100}%`);
|
|
131078
|
+
console.log(` Decay (ms): ${data.decayMs}`);
|
|
131079
|
+
console.log(` Min Quest Interval: ${data.minQuestInterval}s`);
|
|
131080
|
+
console.log("");
|
|
131081
|
+
}
|
|
131082
|
+
}
|
|
131006
131083
|
async function handleQuestAnswer(answer, options) {
|
|
131007
131084
|
const rpcUrl = getRpcUrl(options.rpcUrl);
|
|
131008
131085
|
const connection = new import_web398.Connection(rpcUrl, "confirmed");
|
|
@@ -131208,8 +131285,8 @@ function handleSubmitError(err) {
|
|
|
131208
131285
|
process.exit(1);
|
|
131209
131286
|
}
|
|
131210
131287
|
function registerQuestCommands(program3) {
|
|
131211
|
-
const quest = program3.command("quest").description("
|
|
131212
|
-
quest.command("get").description("Get current quest info").action(async (_opts, cmd) => {
|
|
131288
|
+
const quest = program3.command("quest").description("PoMI quest commands \u2014 mine NARA by answering on-chain quests with ZK proofs");
|
|
131289
|
+
quest.command("get").description("Get current quest info (question, deadline, difficulty, stake requirement)").action(async (_opts, cmd) => {
|
|
131213
131290
|
try {
|
|
131214
131291
|
const globalOpts = cmd.optsWithGlobals();
|
|
131215
131292
|
await handleQuestGet(globalOpts);
|
|
@@ -131218,7 +131295,7 @@ function registerQuestCommands(program3) {
|
|
|
131218
131295
|
process.exit(1);
|
|
131219
131296
|
}
|
|
131220
131297
|
});
|
|
131221
|
-
quest.command("answer <answer>").description("Submit
|
|
131298
|
+
quest.command("answer <answer>").description("Submit a quest answer with ZK proof. Generates a proof locally and submits on-chain. Use --relay when balance is 0 (gasless). Always pass --agent and --model for reward tracking.").option("--relay [url]", `Submit via gasless relay (default: ${DEFAULT_QUEST_RELAY_URL2}, backup: https://quest2-api.nara.build/)`).option("--agent <name>", "Agent/platform type: claude-code, cursor, chatgpt, openclaw, etc. (default: naracli)").option("--model <name>", "AI model used: claude-opus-4-6, claude-sonnet-4-6, gpt-4o, etc.").option("--referral <agent-id>", "Referral agent ID for earning referral points").option("--stake [amount]", 'Stake NARA in the same tx ("auto" to top-up to requirement, or an exact amount)').action(async (answer, opts, cmd) => {
|
|
131222
131299
|
try {
|
|
131223
131300
|
const globalOpts = cmd.optsWithGlobals();
|
|
131224
131301
|
const relayUrl = opts.relay === true ? DEFAULT_QUEST_RELAY_URL2 : opts.relay;
|
|
@@ -131229,6 +131306,15 @@ function registerQuestCommands(program3) {
|
|
|
131229
131306
|
process.exit(1);
|
|
131230
131307
|
}
|
|
131231
131308
|
});
|
|
131309
|
+
quest.command("config").description("Show quest program config (reward counts, stake params, decay, intervals)").action(async (_opts, cmd) => {
|
|
131310
|
+
try {
|
|
131311
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
131312
|
+
await handleQuestConfig(globalOpts);
|
|
131313
|
+
} catch (error) {
|
|
131314
|
+
printError(error.message);
|
|
131315
|
+
process.exit(1);
|
|
131316
|
+
}
|
|
131317
|
+
});
|
|
131232
131318
|
quest.command("stake <amount>").description("Stake NARA to participate in quests").action(async (amount, _opts, cmd) => {
|
|
131233
131319
|
try {
|
|
131234
131320
|
const globalOpts = cmd.optsWithGlobals();
|
|
@@ -133147,7 +133233,7 @@ async function handleSkillsDelete(name, options) {
|
|
|
133147
133233
|
}
|
|
133148
133234
|
}
|
|
133149
133235
|
function registerSkillsCommands(program3) {
|
|
133150
|
-
const skills = program3.command("skills").description("
|
|
133236
|
+
const skills = program3.command("skills").description("On-chain skill registry \u2014 register, publish, install, and manage AI agent skills");
|
|
133151
133237
|
skills.command("register <name> <author>").description("Register a new skill on-chain").action(async (name, author, _opts, cmd) => {
|
|
133152
133238
|
try {
|
|
133153
133239
|
const globalOpts = cmd.optsWithGlobals();
|
|
@@ -133813,8 +133899,8 @@ async function handleAgentClear(options) {
|
|
|
133813
133899
|
}
|
|
133814
133900
|
}
|
|
133815
133901
|
function registerAgentCommands(program3) {
|
|
133816
|
-
const agent = program3.command("agent").description("Agent Registry
|
|
133817
|
-
agent.command("register <agent-id>").description("Register a new agent on-chain").option("--referral <agent-id>", "Referral agent ID").action(async (agentId, opts, cmd) => {
|
|
133902
|
+
const agent = program3.command("agent").description("Agent Registry \u2014 register an on-chain AI agent identity to earn extra rewards and points from PoMI mining");
|
|
133903
|
+
agent.command("register <agent-id>").description("Register a new agent on-chain (costs 1 NARA, 50% off with referral). Agent ID must be lowercase alphanumeric with hyphens.").option("--referral <agent-id>", "Referral agent ID \u2014 saves 50% on registration fee").action(async (agentId, opts, cmd) => {
|
|
133818
133904
|
try {
|
|
133819
133905
|
const globalOpts = cmd.optsWithGlobals();
|
|
133820
133906
|
await handleAgentRegister(agentId, { ...globalOpts, ...opts });
|
|
@@ -134048,7 +134134,7 @@ function registerCommands(program3) {
|
|
|
134048
134134
|
registerZkIdCommands(program3);
|
|
134049
134135
|
registerAgentCommands(program3);
|
|
134050
134136
|
registerConfigCommands(program3);
|
|
134051
|
-
program3.command("address").description("Show wallet address").action(async () => {
|
|
134137
|
+
program3.command("address").description("Show wallet public address (run this first to check if a wallet exists)").action(async () => {
|
|
134052
134138
|
const opts = program3.opts();
|
|
134053
134139
|
try {
|
|
134054
134140
|
await handleWalletAddress(opts);
|
|
@@ -134057,7 +134143,7 @@ function registerCommands(program3) {
|
|
|
134057
134143
|
process.exit(1);
|
|
134058
134144
|
}
|
|
134059
134145
|
});
|
|
134060
|
-
program3.command("balance").description("Check NARA balance").argument("[address]", "Wallet address (optional, defaults to current wallet)").action(async (address) => {
|
|
134146
|
+
program3.command("balance").description("Check NARA balance (native coin, not SOL)").argument("[address]", "Wallet address (optional, defaults to current wallet)").action(async (address) => {
|
|
134061
134147
|
const opts = program3.opts();
|
|
134062
134148
|
try {
|
|
134063
134149
|
await handleWalletBalance(address, opts);
|
|
@@ -134066,7 +134152,7 @@ function registerCommands(program3) {
|
|
|
134066
134152
|
process.exit(1);
|
|
134067
134153
|
}
|
|
134068
134154
|
});
|
|
134069
|
-
program3.command("token-balance <token-address>").description("Check token balance").option("--owner <address>", "Owner address (optional, defaults to current wallet)").action(async (tokenAddress, options) => {
|
|
134155
|
+
program3.command("token-balance <token-address>").description("Check token balance (supports SPL Token and Token-2022)").option("--owner <address>", "Owner address (optional, defaults to current wallet)").action(async (tokenAddress, options) => {
|
|
134070
134156
|
const opts = program3.opts();
|
|
134071
134157
|
try {
|
|
134072
134158
|
await handleTokenBalance(tokenAddress, { ...opts, ...options });
|
|
@@ -134123,7 +134209,7 @@ function registerCommands(program3) {
|
|
|
134123
134209
|
process.exit(1);
|
|
134124
134210
|
}
|
|
134125
134211
|
});
|
|
134126
|
-
program3.command("sign <base64-tx>").description("Sign a base64-encoded transaction").option("--send", "
|
|
134212
|
+
program3.command("sign <base64-tx>").description("Sign a base64-encoded transaction (supports legacy and versioned transactions)").option("--send", "Sign and broadcast the transaction on-chain", false).action(async (base64Tx, options) => {
|
|
134127
134213
|
const opts = program3.opts();
|
|
134128
134214
|
try {
|
|
134129
134215
|
const wallet = await loadWallet(opts.wallet);
|
|
@@ -134174,10 +134260,10 @@ function registerCommands(program3) {
|
|
|
134174
134260
|
}
|
|
134175
134261
|
|
|
134176
134262
|
// bin/nara-cli.ts
|
|
134177
|
-
var version2 = true ? "1.0.
|
|
134263
|
+
var version2 = true ? "1.0.58" : "dev";
|
|
134178
134264
|
var program2 = new Command();
|
|
134179
|
-
program2.name("naracli").description("CLI for the Nara chain (
|
|
134180
|
-
program2.option("-r, --rpc-url <url>", "RPC endpoint
|
|
134265
|
+
program2.name("naracli").description("CLI for the Nara chain. Native coin is NARA (not SOL). Mine NARA for free via PoMI quests, manage wallets, register agents, and more. Run 'naracli <command> --help' for details on any command.").version(version2);
|
|
134266
|
+
program2.option("-r, --rpc-url <url>", "RPC endpoint (default: https://mainnet-api.nara.build/)").option("-w, --wallet <path>", "Path to wallet keypair JSON file (default: ~/.config/nara/id.json)").option("-j, --json", "Output in JSON format");
|
|
134181
134267
|
registerCommands(program2);
|
|
134182
134268
|
if (!process.argv.slice(2).length) {
|
|
134183
134269
|
program2.outputHelp();
|
package/package.json
CHANGED
|
@@ -304,13 +304,13 @@ async function handleAgentClear(options: GlobalOptions) {
|
|
|
304
304
|
export function registerAgentCommands(program: Command): void {
|
|
305
305
|
const agent = program
|
|
306
306
|
.command("agent")
|
|
307
|
-
.description("Agent Registry
|
|
307
|
+
.description("Agent Registry — register an on-chain AI agent identity to earn extra rewards and points from PoMI mining");
|
|
308
308
|
|
|
309
309
|
// agent register
|
|
310
310
|
agent
|
|
311
311
|
.command("register <agent-id>")
|
|
312
|
-
.description("Register a new agent on-chain")
|
|
313
|
-
.option("--referral <agent-id>", "Referral agent ID")
|
|
312
|
+
.description("Register a new agent on-chain (costs 1 NARA, 50% off with referral). Agent ID must be lowercase alphanumeric with hyphens.")
|
|
313
|
+
.option("--referral <agent-id>", "Referral agent ID — saves 50% on registration fee")
|
|
314
314
|
.action(async (agentId: string, opts: { referral?: string }, cmd: Command) => {
|
|
315
315
|
try {
|
|
316
316
|
const globalOpts = cmd.optsWithGlobals() as GlobalOptions;
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
import type { GlobalOptions } from "../types";
|
|
17
17
|
import {
|
|
18
18
|
getQuestInfo,
|
|
19
|
+
getQuestConfig,
|
|
19
20
|
hasAnswered,
|
|
20
21
|
generateProof,
|
|
21
22
|
submitAnswer,
|
|
@@ -106,6 +107,17 @@ async function handleQuestGet(options: GlobalOptions) {
|
|
|
106
107
|
return;
|
|
107
108
|
}
|
|
108
109
|
|
|
110
|
+
// Stake only applies when reward slots have reached maxRewardCount
|
|
111
|
+
let stakeRequired = quest.effectiveStakeRequirement > 0;
|
|
112
|
+
try {
|
|
113
|
+
const config = await getQuestConfig(connection);
|
|
114
|
+
if (quest.rewardCount < config.maxRewardCount) {
|
|
115
|
+
stakeRequired = false;
|
|
116
|
+
}
|
|
117
|
+
} catch {
|
|
118
|
+
// If config fetch fails, fall back to showing stake as-is
|
|
119
|
+
}
|
|
120
|
+
|
|
109
121
|
const data: Record<string, any> = {
|
|
110
122
|
round: quest.round,
|
|
111
123
|
question: quest.question,
|
|
@@ -117,7 +129,8 @@ async function handleQuestGet(options: GlobalOptions) {
|
|
|
117
129
|
deadline: new Date(quest.deadline * 1000).toLocaleString(),
|
|
118
130
|
timeRemaining: formatTimeRemaining(quest.timeRemaining),
|
|
119
131
|
expired: quest.expired,
|
|
120
|
-
|
|
132
|
+
stakeRequired,
|
|
133
|
+
stakeRequirement: stakeRequired ? `${quest.effectiveStakeRequirement.toFixed(4)} NARA` : "0 NARA",
|
|
121
134
|
stakeHigh: `${quest.stakeHigh} NARA`,
|
|
122
135
|
stakeLow: `${quest.stakeLow} NARA`,
|
|
123
136
|
avgParticipantStake: `${quest.avgParticipantStake} NARA`,
|
|
@@ -135,8 +148,10 @@ async function handleQuestGet(options: GlobalOptions) {
|
|
|
135
148
|
console.log(
|
|
136
149
|
` Reward slots: ${quest.winnerCount}/${quest.rewardCount} (${quest.remainingSlots} remaining)`
|
|
137
150
|
);
|
|
138
|
-
if (
|
|
151
|
+
if (stakeRequired) {
|
|
139
152
|
console.log(` Stake requirement: ${quest.effectiveStakeRequirement.toFixed(4)} NARA (decays ${quest.stakeHigh} → ${quest.stakeLow})`);
|
|
153
|
+
} else {
|
|
154
|
+
console.log(` Stake requirement: none`);
|
|
140
155
|
}
|
|
141
156
|
console.log(` Deadline: ${new Date(quest.deadline * 1000).toLocaleString()}`);
|
|
142
157
|
if (quest.timeRemaining > 0) {
|
|
@@ -148,6 +163,55 @@ async function handleQuestGet(options: GlobalOptions) {
|
|
|
148
163
|
}
|
|
149
164
|
}
|
|
150
165
|
|
|
166
|
+
// ─── Command: quest config ───────────────────────────────────────
|
|
167
|
+
async function handleQuestConfig(options: GlobalOptions) {
|
|
168
|
+
const rpcUrl = getRpcUrl(options.rpcUrl);
|
|
169
|
+
const connection = new Connection(rpcUrl, "confirmed");
|
|
170
|
+
|
|
171
|
+
let config;
|
|
172
|
+
try {
|
|
173
|
+
config = await getQuestConfig(connection);
|
|
174
|
+
} catch (err: any) {
|
|
175
|
+
printError(`Failed to fetch quest config: ${err.message}`);
|
|
176
|
+
process.exit(1);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const DECIMALS = 1e9;
|
|
180
|
+
const rewardPerShare = config.rewardPerShare / DECIMALS;
|
|
181
|
+
const extraReward = config.extraReward / DECIMALS;
|
|
182
|
+
const stakeBpsHigh = config.stakeBpsHigh;
|
|
183
|
+
const stakeBpsLow = config.stakeBpsLow;
|
|
184
|
+
|
|
185
|
+
const data = {
|
|
186
|
+
authority: config.authority.toBase58(),
|
|
187
|
+
questAuthority: config.questAuthority.toBase58(),
|
|
188
|
+
treasury: config.treasury.toBase58(),
|
|
189
|
+
minRewardCount: config.minRewardCount,
|
|
190
|
+
maxRewardCount: config.maxRewardCount,
|
|
191
|
+
rewardPerShare,
|
|
192
|
+
extraReward,
|
|
193
|
+
stakeBpsHigh,
|
|
194
|
+
stakeBpsLow,
|
|
195
|
+
decayMs: config.decayMs,
|
|
196
|
+
minQuestInterval: config.minQuestInterval,
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
if (options.json) {
|
|
200
|
+
formatOutput(data, true);
|
|
201
|
+
} else {
|
|
202
|
+
console.log("");
|
|
203
|
+
console.log(` Min Reward Count: ${data.minRewardCount}`);
|
|
204
|
+
console.log(` Max Reward Count: ${data.maxRewardCount}`);
|
|
205
|
+
console.log(` Reward Per Share: ${rewardPerShare} NARA`);
|
|
206
|
+
console.log(` Extra Reward: ${extraReward} NARA`);
|
|
207
|
+
console.log(` Stake BPS High: ${stakeBpsHigh / 100}%`);
|
|
208
|
+
console.log(` Stake BPS Low: ${stakeBpsLow / 100}%`);
|
|
209
|
+
console.log(` Decay (ms): ${data.decayMs}`);
|
|
210
|
+
console.log(` Min Quest Interval: ${data.minQuestInterval}s`);
|
|
211
|
+
console.log("");
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
151
215
|
// ─── Command: quest answer ───────────────────────────────────────
|
|
152
216
|
async function handleQuestAnswer(
|
|
153
217
|
answer: string,
|
|
@@ -400,12 +464,12 @@ function handleSubmitError(err: any) {
|
|
|
400
464
|
export function registerQuestCommands(program: Command): void {
|
|
401
465
|
const quest = program
|
|
402
466
|
.command("quest")
|
|
403
|
-
.description("
|
|
467
|
+
.description("PoMI quest commands — mine NARA by answering on-chain quests with ZK proofs");
|
|
404
468
|
|
|
405
469
|
// quest get
|
|
406
470
|
quest
|
|
407
471
|
.command("get")
|
|
408
|
-
.description("Get current quest info")
|
|
472
|
+
.description("Get current quest info (question, deadline, difficulty, stake requirement)")
|
|
409
473
|
.action(async (_opts: any, cmd: Command) => {
|
|
410
474
|
try {
|
|
411
475
|
const globalOpts = cmd.optsWithGlobals() as GlobalOptions;
|
|
@@ -419,12 +483,12 @@ export function registerQuestCommands(program: Command): void {
|
|
|
419
483
|
// quest answer
|
|
420
484
|
quest
|
|
421
485
|
.command("answer <answer>")
|
|
422
|
-
.description("Submit
|
|
423
|
-
.option("--relay [url]", `Submit via relay
|
|
424
|
-
.option("--agent <name>", "Agent
|
|
425
|
-
.option("--model <name>", "
|
|
426
|
-
.option("--referral <agent-id>", "Referral agent ID")
|
|
427
|
-
.option("--stake [amount]", 'Stake NARA
|
|
486
|
+
.description("Submit a quest answer with ZK proof. Generates a proof locally and submits on-chain. Use --relay when balance is 0 (gasless). Always pass --agent and --model for reward tracking.")
|
|
487
|
+
.option("--relay [url]", `Submit via gasless relay (default: ${DEFAULT_QUEST_RELAY_URL}, backup: https://quest2-api.nara.build/)`)
|
|
488
|
+
.option("--agent <name>", "Agent/platform type: claude-code, cursor, chatgpt, openclaw, etc. (default: naracli)")
|
|
489
|
+
.option("--model <name>", "AI model used: claude-opus-4-6, claude-sonnet-4-6, gpt-4o, etc.")
|
|
490
|
+
.option("--referral <agent-id>", "Referral agent ID for earning referral points")
|
|
491
|
+
.option("--stake [amount]", 'Stake NARA in the same tx ("auto" to top-up to requirement, or an exact amount)')
|
|
428
492
|
.action(async (answer: string, opts: any, cmd: Command) => {
|
|
429
493
|
try {
|
|
430
494
|
const globalOpts = cmd.optsWithGlobals() as GlobalOptions;
|
|
@@ -437,6 +501,20 @@ export function registerQuestCommands(program: Command): void {
|
|
|
437
501
|
}
|
|
438
502
|
});
|
|
439
503
|
|
|
504
|
+
// quest config
|
|
505
|
+
quest
|
|
506
|
+
.command("config")
|
|
507
|
+
.description("Show quest program config (reward counts, stake params, decay, intervals)")
|
|
508
|
+
.action(async (_opts: any, cmd: Command) => {
|
|
509
|
+
try {
|
|
510
|
+
const globalOpts = cmd.optsWithGlobals() as GlobalOptions;
|
|
511
|
+
await handleQuestConfig(globalOpts);
|
|
512
|
+
} catch (error: any) {
|
|
513
|
+
printError(error.message);
|
|
514
|
+
process.exit(1);
|
|
515
|
+
}
|
|
516
|
+
});
|
|
517
|
+
|
|
440
518
|
// quest stake
|
|
441
519
|
quest
|
|
442
520
|
.command("stake <amount>")
|
|
@@ -281,7 +281,7 @@ async function handleSkillsDelete(name: string, options: GlobalOptions & { yes?:
|
|
|
281
281
|
export function registerSkillsCommands(program: Command): void {
|
|
282
282
|
const skills = program
|
|
283
283
|
.command("skills")
|
|
284
|
-
.description("
|
|
284
|
+
.description("On-chain skill registry — register, publish, install, and manage AI agent skills");
|
|
285
285
|
|
|
286
286
|
// skills register
|
|
287
287
|
skills
|
|
@@ -55,12 +55,12 @@ const DEFAULT_WALLET_PATH = _DEFAULT_WALLET_PATH.startsWith("~")
|
|
|
55
55
|
export function registerWalletCommands(program: Command): void {
|
|
56
56
|
const wallet = program
|
|
57
57
|
.command("wallet")
|
|
58
|
-
.description("Wallet management
|
|
58
|
+
.description("Wallet management — create or import a keypair for signing transactions");
|
|
59
59
|
|
|
60
60
|
// wallet create
|
|
61
61
|
wallet
|
|
62
62
|
.command("create")
|
|
63
|
-
.description("Create a new wallet")
|
|
63
|
+
.description("Create a new wallet keypair (saved to ~/.config/nara/id.json by default)")
|
|
64
64
|
.option("-o, --output <path>", "Output path for wallet file (default: ~/.config/nara/id.json)")
|
|
65
65
|
.action(async (options: { output?: string }) => {
|
|
66
66
|
try {
|
package/src/cli/index.ts
CHANGED
|
@@ -85,7 +85,7 @@ export function registerCommands(program: Command): void {
|
|
|
85
85
|
// Top-level: address
|
|
86
86
|
program
|
|
87
87
|
.command("address")
|
|
88
|
-
.description("Show wallet address")
|
|
88
|
+
.description("Show wallet public address (run this first to check if a wallet exists)")
|
|
89
89
|
.action(async () => {
|
|
90
90
|
const opts = program.opts() as GlobalOptions;
|
|
91
91
|
try {
|
|
@@ -99,7 +99,7 @@ export function registerCommands(program: Command): void {
|
|
|
99
99
|
// Top-level: balance
|
|
100
100
|
program
|
|
101
101
|
.command("balance")
|
|
102
|
-
.description("Check NARA balance")
|
|
102
|
+
.description("Check NARA balance (native coin, not SOL)")
|
|
103
103
|
.argument("[address]", "Wallet address (optional, defaults to current wallet)")
|
|
104
104
|
.action(async (address: string | undefined) => {
|
|
105
105
|
const opts = program.opts() as WalletBalanceOptions;
|
|
@@ -114,7 +114,7 @@ export function registerCommands(program: Command): void {
|
|
|
114
114
|
// Top-level: token-balance
|
|
115
115
|
program
|
|
116
116
|
.command("token-balance <token-address>")
|
|
117
|
-
.description("Check token balance")
|
|
117
|
+
.description("Check token balance (supports SPL Token and Token-2022)")
|
|
118
118
|
.option("--owner <address>", "Owner address (optional, defaults to current wallet)")
|
|
119
119
|
.action(async (tokenAddress: string, options: { owner?: string }) => {
|
|
120
120
|
const opts = program.opts() as TokenBalanceOptions;
|
|
@@ -199,8 +199,8 @@ export function registerCommands(program: Command): void {
|
|
|
199
199
|
// Top-level: sign
|
|
200
200
|
program
|
|
201
201
|
.command("sign <base64-tx>")
|
|
202
|
-
.description("Sign a base64-encoded transaction")
|
|
203
|
-
.option("--send", "
|
|
202
|
+
.description("Sign a base64-encoded transaction (supports legacy and versioned transactions)")
|
|
203
|
+
.option("--send", "Sign and broadcast the transaction on-chain", false)
|
|
204
204
|
.action(async (base64Tx: string, options: { send?: boolean }) => {
|
|
205
205
|
const opts = program.opts() as GlobalOptions;
|
|
206
206
|
try {
|