naracli 1.0.11 → 1.0.13

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/README.md CHANGED
@@ -106,11 +106,11 @@ See [examples/](examples/) for complete SDK usage examples.
106
106
 
107
107
  ```bash
108
108
  # Create a new wallet
109
- nara-cli wallet create
109
+ npx naracli wallet create
110
110
 
111
111
  # Or import from mnemonic / private key
112
- nara-cli wallet import -m "your twelve word mnemonic phrase ..."
113
- nara-cli wallet import -k "your-private-key"
112
+ npx naracli wallet import -m "your twelve word mnemonic phrase ..."
113
+ npx naracli wallet import -k "your-private-key"
114
114
  ```
115
115
 
116
116
  Wallet is saved to `~/.config/nara/id.json` by default.
@@ -126,7 +126,7 @@ migrate Check migration eligibility and launch to DAMM V2
126
126
  quest On-chain quiz with ZK proof verification
127
127
  ```
128
128
 
129
- Run `nara-cli <command> --help` for details on each command.
129
+ Run `npx naracli <command> --help` for details on each command.
130
130
 
131
131
  ### Global Options
132
132
 
@@ -140,14 +140,14 @@ Run `nara-cli <command> --help` for details on each command.
140
140
 
141
141
  ```bash
142
142
  # Check balance
143
- nara-cli wallet balance
143
+ npx naracli wallet balance
144
144
 
145
145
  # Buy tokens
146
- nara-cli swap buy <TOKEN_ADDRESS> 0.1
146
+ npx naracli swap buy <TOKEN_ADDRESS> 0.1
147
147
 
148
148
  # Answer a quest
149
- nara-cli quest get
150
- nara-cli quest answer "your answer"
149
+ npx naracli quest get
150
+ npx naracli quest answer "your answer"
151
151
  ```
152
152
 
153
153
  ## License
package/bin/nara-cli.ts CHANGED
@@ -4,13 +4,14 @@
4
4
 
5
5
  import { Command } from "commander";
6
6
  import { registerCommands } from "../src/cli/index";
7
+ import { loadWallet } from "../src/cli/utils/wallet";
7
8
 
8
9
  // Create program
9
10
  const program = new Command();
10
11
 
11
12
  // Set program metadata
12
13
  program
13
- .name("nara-cli")
14
+ .name("naracli")
14
15
  .description("CLI for the Nara chain (Solana-compatible)")
15
16
  .version("0.1.0");
16
17
 
@@ -20,6 +21,25 @@ program
20
21
  .option("-w, --wallet <path>", "Path to wallet keypair JSON file")
21
22
  .option("-j, --json", "Output in JSON format");
22
23
 
24
+ // Top-level address shortcut
25
+ program
26
+ .command("address")
27
+ .description("Show wallet address")
28
+ .action(async () => {
29
+ const opts = program.opts();
30
+ try {
31
+ const wallet = await loadWallet(opts.wallet);
32
+ if (opts.json) {
33
+ console.log(JSON.stringify({ address: wallet.publicKey.toBase58() }, null, 2));
34
+ } else {
35
+ console.log(wallet.publicKey.toBase58());
36
+ }
37
+ } catch (error: any) {
38
+ console.error(`Error: ${error.message}`);
39
+ process.exit(1);
40
+ }
41
+ });
42
+
23
43
  // Register all command modules
24
44
  registerCommands(program);
25
45
 
package/dist/nara-cli.mjs CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env node
2
+ try{process.loadEnvFile()}catch{}
2
3
 
3
4
  // bin/nara-cli.ts
4
5
  import { Command as Command8 } from "commander";
@@ -208,6 +209,7 @@ var DEFAULT_RPC_URL = process.env.RPC_URL || "https://mainnet-api.nara.build/";
208
209
  var DEFAULT_DBC_CONFIG_ADDRESS = process.env.DBC_CONFIG_ADDRESS || "";
209
210
  var DEFAULT_WALLET_PATH = process.env.WALLET_PATH || "~/.config/nara/id.json";
210
211
  var DEFAULT_QUEST_RELAY_URL = process.env.QUEST_RELAY_URL || "https://quest-api.nara.build/";
212
+ var DEFAULT_QUEST_PROGRAM_ID = process.env.QUEST_PROGRAM_ID || "Quest11111111111111111111111111111111111111";
211
213
 
212
214
  // src/cli/utils/wallet.ts
213
215
  var DEFAULT_WALLET_PATH2 = DEFAULT_WALLET_PATH.startsWith("~") ? join(homedir(), DEFAULT_WALLET_PATH.slice(1)) : DEFAULT_WALLET_PATH;
@@ -229,7 +231,10 @@ async function loadWallet(walletPath) {
229
231
  } catch (error) {
230
232
  if (!walletPath) {
231
233
  throw new Error(
232
- `Wallet not found. Please create a wallet at ${DEFAULT_WALLET_PATH2} or use --wallet flag to specify a different path.`
234
+ `No wallet found. Create one first:
235
+
236
+ npx naracli wallet create
237
+ `
233
238
  );
234
239
  } else {
235
240
  throw new Error(`Failed to load wallet from ${path}: ${error.message}`);
@@ -1711,7 +1716,7 @@ import * as bip39 from "bip39";
1711
1716
  import { derivePath } from "ed25519-hd-key";
1712
1717
  import { join as join2 } from "node:path";
1713
1718
  import { homedir as homedir2 } from "node:os";
1714
- import { mkdir } from "node:fs/promises";
1719
+ import { mkdir, writeFile, access } from "node:fs/promises";
1715
1720
  import bs58 from "bs58";
1716
1721
  var DEFAULT_WALLET_PATH3 = DEFAULT_WALLET_PATH.startsWith("~") ? join2(homedir2(), DEFAULT_WALLET_PATH.slice(1)) : DEFAULT_WALLET_PATH;
1717
1722
  function registerWalletCommands(program2) {
@@ -2061,10 +2066,13 @@ Token Transfer Details:`);
2061
2066
  }
2062
2067
  async function handleWalletCreate(options) {
2063
2068
  const outputPath = options.output || DEFAULT_WALLET_PATH3;
2064
- if (await Bun.file(outputPath).exists()) {
2069
+ try {
2070
+ await access(outputPath);
2065
2071
  throw new Error(
2066
2072
  `Wallet file already exists at ${outputPath}. Please use a different path or remove the existing file first.`
2067
2073
  );
2074
+ } catch (e) {
2075
+ if (e.code !== "ENOENT") throw e;
2068
2076
  }
2069
2077
  const mnemonic = bip39.generateMnemonic(128);
2070
2078
  const seed = await bip39.mnemonicToSeed(mnemonic);
@@ -2073,7 +2081,7 @@ async function handleWalletCreate(options) {
2073
2081
  const dir = outputPath.substring(0, outputPath.lastIndexOf("/"));
2074
2082
  await mkdir(dir, { recursive: true });
2075
2083
  const walletData = Array.from(keypair.secretKey);
2076
- await Bun.write(outputPath, JSON.stringify(walletData, null, 2));
2084
+ await writeFile(outputPath, JSON.stringify(walletData, null, 2));
2077
2085
  console.log("\n\u2705 Wallet created successfully!");
2078
2086
  console.log(`
2079
2087
  \u{1F4C1} Wallet saved to: ${outputPath}`);
@@ -2089,10 +2097,13 @@ ${mnemonic}
2089
2097
  }
2090
2098
  async function handleWalletImport(options) {
2091
2099
  const outputPath = options.output || DEFAULT_WALLET_PATH3;
2092
- if (await Bun.file(outputPath).exists()) {
2100
+ try {
2101
+ await access(outputPath);
2093
2102
  throw new Error(
2094
2103
  `Wallet file already exists at ${outputPath}. Please use a different path or remove the existing file first.`
2095
2104
  );
2105
+ } catch (e) {
2106
+ if (e.code !== "ENOENT") throw e;
2096
2107
  }
2097
2108
  let keypair;
2098
2109
  if (options.mnemonic) {
@@ -2123,7 +2134,7 @@ async function handleWalletImport(options) {
2123
2134
  const dir = outputPath.substring(0, outputPath.lastIndexOf("/"));
2124
2135
  await mkdir(dir, { recursive: true });
2125
2136
  const walletData = Array.from(keypair.secretKey);
2126
- await Bun.write(outputPath, JSON.stringify(walletData, null, 2));
2137
+ await writeFile(outputPath, JSON.stringify(walletData, null, 2));
2127
2138
  console.log("\n\u2705 Wallet imported successfully!");
2128
2139
  console.log(`
2129
2140
  \u{1F4C1} Wallet saved to: ${outputPath}`);
@@ -2133,14 +2144,9 @@ async function handleWalletImport(options) {
2133
2144
  async function handleWalletAddress(options) {
2134
2145
  const wallet = await loadWallet(options.wallet);
2135
2146
  if (options.json) {
2136
- const output = {
2137
- address: wallet.publicKey.toBase58()
2138
- };
2139
- console.log(JSON.stringify(output, null, 2));
2147
+ console.log(JSON.stringify({ address: wallet.publicKey.toBase58() }, null, 2));
2140
2148
  } else {
2141
- console.log(`
2142
- \u{1F511} Wallet Address: ${wallet.publicKey.toBase58()}
2143
- `);
2149
+ console.log(wallet.publicKey.toBase58());
2144
2150
  }
2145
2151
  }
2146
2152
 
@@ -2236,16 +2242,18 @@ async function silentProve(snarkjs, input, wasmPath, zkeyPath) {
2236
2242
  console.error = savedError;
2237
2243
  }
2238
2244
  }
2239
- function createProgram(connection, wallet) {
2245
+ function createProgram(connection, wallet, programId) {
2240
2246
  const idlPath = existsSync(join3(__dirname, "cli/quest/nara_quest.json")) ? "./cli/quest/nara_quest.json" : "./quest/nara_quest.json";
2241
2247
  const idl = _require(idlPath);
2248
+ const pid = programId ?? DEFAULT_QUEST_PROGRAM_ID;
2249
+ const idlWithPid = { ...idl, address: pid };
2242
2250
  const provider = new AnchorProvider(
2243
2251
  connection,
2244
2252
  new Wallet(wallet),
2245
2253
  { commitment: "confirmed" }
2246
2254
  );
2247
2255
  anchor.setProvider(provider);
2248
- return new Program(idl, provider);
2256
+ return new Program(idlWithPid, provider);
2249
2257
  }
2250
2258
  function getPoolPda(programId) {
2251
2259
  const [pda] = PublicKey8.findProgramAddressSync(
@@ -2261,9 +2269,9 @@ function getWinnerRecordPda(programId, user) {
2261
2269
  );
2262
2270
  return pda;
2263
2271
  }
2264
- async function getQuestInfo(connection, wallet) {
2272
+ async function getQuestInfo(connection, wallet, options) {
2265
2273
  const kp = wallet ?? Keypair7.generate();
2266
- const program2 = createProgram(connection, kp);
2274
+ const program2 = createProgram(connection, kp, options?.programId);
2267
2275
  const poolPda = getPoolPda(program2.programId);
2268
2276
  const pool = await program2.account.pool.fetch(poolPda);
2269
2277
  const now = Math.floor(Date.now() / 1e3);
@@ -2285,9 +2293,9 @@ async function getQuestInfo(connection, wallet) {
2285
2293
  expired: secsLeft <= 0
2286
2294
  };
2287
2295
  }
2288
- async function hasAnswered(connection, wallet) {
2289
- const program2 = createProgram(connection, wallet);
2290
- const quest = await getQuestInfo(connection, wallet);
2296
+ async function hasAnswered(connection, wallet, options) {
2297
+ const program2 = createProgram(connection, wallet, options?.programId);
2298
+ const quest = await getQuestInfo(connection, wallet, options);
2291
2299
  const winnerPda = getWinnerRecordPda(program2.programId, wallet.publicKey);
2292
2300
  try {
2293
2301
  const wr = await program2.account.winnerRecord.fetch(winnerPda);
@@ -2318,8 +2326,8 @@ async function generateProof(answer, answerHash, userPubkey, options) {
2318
2326
  hex: proofToHex(result.proof)
2319
2327
  };
2320
2328
  }
2321
- async function submitAnswer(connection, wallet, proof) {
2322
- const program2 = createProgram(connection, wallet);
2329
+ async function submitAnswer(connection, wallet, proof, options) {
2330
+ const program2 = createProgram(connection, wallet, options?.programId);
2323
2331
  const signature = await program2.methods.submitAnswer(proof.proofA, proof.proofB, proof.proofC).accounts({ user: wallet.publicKey, payer: wallet.publicKey }).signers([wallet]).rpc({ skipPreflight: true });
2324
2332
  return { signature };
2325
2333
  }
@@ -2622,8 +2630,22 @@ function registerCommands(program2) {
2622
2630
 
2623
2631
  // bin/nara-cli.ts
2624
2632
  var program = new Command8();
2625
- program.name("nara-cli").description("CLI for the Nara chain (Solana-compatible)").version("0.1.0");
2633
+ program.name("naracli").description("CLI for the Nara chain (Solana-compatible)").version("0.1.0");
2626
2634
  program.option("-r, --rpc-url <url>", "RPC endpoint URL").option("-w, --wallet <path>", "Path to wallet keypair JSON file").option("-j, --json", "Output in JSON format");
2635
+ program.command("address").description("Show wallet address").action(async () => {
2636
+ const opts = program.opts();
2637
+ try {
2638
+ const wallet = await loadWallet(opts.wallet);
2639
+ if (opts.json) {
2640
+ console.log(JSON.stringify({ address: wallet.publicKey.toBase58() }, null, 2));
2641
+ } else {
2642
+ console.log(wallet.publicKey.toBase58());
2643
+ }
2644
+ } catch (error) {
2645
+ console.error(`Error: ${error.message}`);
2646
+ process.exit(1);
2647
+ }
2648
+ });
2627
2649
  registerCommands(program);
2628
2650
  program.parse(process.argv);
2629
2651
  if (!process.argv.slice(2).length) {
package/index.ts CHANGED
@@ -10,7 +10,7 @@
10
10
  export { NaraSDK, type NaraSDKConfig } from "./src/client";
11
11
 
12
12
  // Export constants
13
- export { DEFAULT_RPC_URL } from "./src/constants";
13
+ export { DEFAULT_RPC_URL, DEFAULT_QUEST_PROGRAM_ID } from "./src/constants";
14
14
 
15
15
  // Export config functions and types
16
16
  export {
@@ -68,7 +68,7 @@ export {
68
68
  type ZkProofHex,
69
69
  type SubmitAnswerResult,
70
70
  type SubmitRelayResult,
71
- type QuestProveOptions,
71
+ type QuestOptions,
72
72
  } from "./src/quest";
73
73
 
74
74
  // Re-export commonly used types from dependencies
package/package.json CHANGED
@@ -1,17 +1,17 @@
1
1
  {
2
2
  "name": "naracli",
3
- "version": "1.0.11",
3
+ "version": "1.0.13",
4
4
  "description": "CLI for the Nara chain (Solana-compatible)",
5
5
  "module": "index.ts",
6
6
  "main": "index.ts",
7
7
  "type": "module",
8
8
  "private": false,
9
9
  "bin": {
10
- "nara-cli": "./dist/nara-cli.mjs"
10
+ "naracli": "./dist/nara-cli.mjs"
11
11
  },
12
12
  "scripts": {
13
- "cli": "npx tsx bin/nara-cli.ts",
14
- "build": "npx esbuild bin/nara-cli.ts --bundle --platform=node --format=esm --outfile=dist/nara-cli.mjs --packages=external --banner:js='#!/usr/bin/env node' && mkdir -p dist/zk dist/quest && cp src/cli/zk/answer_proof.wasm src/cli/zk/answer_proof_final.zkey dist/zk/ && cp src/cli/quest/nara_quest.json dist/quest/",
13
+ "cli": "node --env-file=.env --import tsx bin/nara-cli.ts",
14
+ "build": "npx esbuild bin/nara-cli.ts --bundle --platform=node --format=esm --outfile=dist/nara-cli.mjs --packages=external --banner:js='#!/usr/bin/env node\ntry{process.loadEnvFile()}catch{}' && mkdir -p dist/zk dist/quest && cp src/cli/zk/answer_proof.wasm src/cli/zk/answer_proof_final.zkey dist/zk/ && cp src/cli/quest/nara_quest.json dist/quest/",
15
15
  "prepublishOnly": "npm run build"
16
16
  },
17
17
  "files": [
@@ -19,7 +19,7 @@ import * as bip39 from "bip39";
19
19
  import { derivePath } from "ed25519-hd-key";
20
20
  import { join } from "node:path";
21
21
  import { homedir } from "node:os";
22
- import { mkdir } from "node:fs/promises";
22
+ import { mkdir, writeFile, access } from "node:fs/promises";
23
23
  import bs58 from "bs58";
24
24
  import { NaraSDK } from "../../client";
25
25
  import { DEFAULT_WALLET_PATH as _DEFAULT_WALLET_PATH } from "../../constants";
@@ -593,10 +593,13 @@ async function handleWalletCreate(options: { output?: string }): Promise<void> {
593
593
  const outputPath = options.output || DEFAULT_WALLET_PATH;
594
594
 
595
595
  // Check if wallet file already exists
596
- if (await Bun.file(outputPath).exists()) {
596
+ try {
597
+ await access(outputPath);
597
598
  throw new Error(
598
599
  `Wallet file already exists at ${outputPath}. Please use a different path or remove the existing file first.`
599
600
  );
601
+ } catch (e: any) {
602
+ if (e.code !== "ENOENT") throw e;
600
603
  }
601
604
 
602
605
  // Generate mnemonic (12 words by default, can be changed to 24)
@@ -613,7 +616,7 @@ async function handleWalletCreate(options: { output?: string }): Promise<void> {
613
616
 
614
617
  // Save wallet to file
615
618
  const walletData = Array.from(keypair.secretKey);
616
- await Bun.write(outputPath, JSON.stringify(walletData, null, 2));
619
+ await writeFile(outputPath, JSON.stringify(walletData, null, 2));
617
620
 
618
621
  // Display results
619
622
  console.log("\nāœ… Wallet created successfully!");
@@ -641,10 +644,13 @@ async function handleWalletImport(options: {
641
644
  const outputPath = options.output || DEFAULT_WALLET_PATH;
642
645
 
643
646
  // Check if wallet file already exists
644
- if (await Bun.file(outputPath).exists()) {
647
+ try {
648
+ await access(outputPath);
645
649
  throw new Error(
646
650
  `Wallet file already exists at ${outputPath}. Please use a different path or remove the existing file first.`
647
651
  );
652
+ } catch (e: any) {
653
+ if (e.code !== "ENOENT") throw e;
648
654
  }
649
655
 
650
656
  let keypair: Keypair;
@@ -691,7 +697,7 @@ async function handleWalletImport(options: {
691
697
 
692
698
  // Save wallet to file
693
699
  const walletData = Array.from(keypair.secretKey);
694
- await Bun.write(outputPath, JSON.stringify(walletData, null, 2));
700
+ await writeFile(outputPath, JSON.stringify(walletData, null, 2));
695
701
 
696
702
  // Display results
697
703
  console.log("\nāœ… Wallet imported successfully!");
@@ -704,16 +710,11 @@ async function handleWalletImport(options: {
704
710
  * @param options Command options
705
711
  */
706
712
  async function handleWalletAddress(options: GlobalOptions): Promise<void> {
707
- // Load wallet
708
713
  const wallet = await loadWallet(options.wallet);
709
714
 
710
- // Output result
711
715
  if (options.json) {
712
- const output = {
713
- address: wallet.publicKey.toBase58(),
714
- };
715
- console.log(JSON.stringify(output, null, 2));
716
+ console.log(JSON.stringify({ address: wallet.publicKey.toBase58() }, null, 2));
716
717
  } else {
717
- console.log(`\nšŸ”‘ Wallet Address: ${wallet.publicKey.toBase58()}\n`);
718
+ console.log(wallet.publicKey.toBase58());
718
719
  }
719
720
  }
@@ -47,9 +47,8 @@ export async function loadWallet(walletPath?: string): Promise<Keypair> {
47
47
  }
48
48
  } catch (error: any) {
49
49
  if (!walletPath) {
50
- // If using default path and it doesn't exist, provide helpful error message
51
50
  throw new Error(
52
- `Wallet not found. Please create a wallet at ${DEFAULT_WALLET_PATH} or use --wallet flag to specify a different path.`
51
+ `No wallet found. Create one first:\n\n npx naracli wallet create\n`
53
52
  );
54
53
  } else {
55
54
  throw new Error(`Failed to load wallet from ${path}: ${error.message}`);
package/src/constants.ts CHANGED
@@ -27,3 +27,9 @@ export const DEFAULT_WALLET_PATH =
27
27
  */
28
28
  export const DEFAULT_QUEST_RELAY_URL =
29
29
  process.env.QUEST_RELAY_URL || "https://quest-api.nara.build/";
30
+
31
+ /**
32
+ * Quest program ID
33
+ */
34
+ export const DEFAULT_QUEST_PROGRAM_ID =
35
+ process.env.QUEST_PROGRAM_ID || "Quest11111111111111111111111111111111111111";
package/src/quest.ts CHANGED
@@ -11,6 +11,7 @@ import {
11
11
  import * as anchor from "@coral-xyz/anchor";
12
12
  import { Program, AnchorProvider, Wallet } from "@coral-xyz/anchor";
13
13
  import type { NaraQuest } from "./cli/quest/nara_quest_types";
14
+ import { DEFAULT_QUEST_PROGRAM_ID } from "./constants";
14
15
 
15
16
  import { createRequire } from "module";
16
17
  const _require = createRequire(import.meta.url);
@@ -76,7 +77,8 @@ export interface SubmitRelayResult {
76
77
  txHash: string;
77
78
  }
78
79
 
79
- export interface QuestProveOptions {
80
+ export interface QuestOptions {
81
+ programId?: string;
80
82
  circuitWasmPath?: string;
81
83
  zkeyPath?: string;
82
84
  }
@@ -162,19 +164,22 @@ async function silentProve(snarkjs: any, input: Record<string, string>, wasmPath
162
164
 
163
165
  function createProgram(
164
166
  connection: Connection,
165
- wallet: Keypair
167
+ wallet: Keypair,
168
+ programId?: string
166
169
  ): Program<NaraQuest> {
167
170
  const idlPath = existsSync(join(__dirname, "cli/quest/nara_quest.json"))
168
171
  ? "./cli/quest/nara_quest.json"
169
172
  : "./quest/nara_quest.json";
170
173
  const idl = _require(idlPath);
174
+ const pid = programId ?? DEFAULT_QUEST_PROGRAM_ID;
175
+ const idlWithPid = { ...idl, address: pid };
171
176
  const provider = new AnchorProvider(
172
177
  connection,
173
178
  new Wallet(wallet),
174
179
  { commitment: "confirmed" }
175
180
  );
176
181
  anchor.setProvider(provider);
177
- return new Program<NaraQuest>(idl as any, provider);
182
+ return new Program<NaraQuest>(idlWithPid as any, provider);
178
183
  }
179
184
 
180
185
  function getPoolPda(programId: PublicKey): PublicKey {
@@ -203,10 +208,11 @@ function getWinnerRecordPda(
203
208
  */
204
209
  export async function getQuestInfo(
205
210
  connection: Connection,
206
- wallet?: Keypair
211
+ wallet?: Keypair,
212
+ options?: QuestOptions
207
213
  ): Promise<QuestInfo> {
208
214
  const kp = wallet ?? Keypair.generate();
209
- const program = createProgram(connection, kp);
215
+ const program = createProgram(connection, kp, options?.programId);
210
216
  const poolPda = getPoolPda(program.programId);
211
217
  const pool = await program.account.pool.fetch(poolPda);
212
218
 
@@ -236,10 +242,11 @@ export async function getQuestInfo(
236
242
  */
237
243
  export async function hasAnswered(
238
244
  connection: Connection,
239
- wallet: Keypair
245
+ wallet: Keypair,
246
+ options?: QuestOptions
240
247
  ): Promise<boolean> {
241
- const program = createProgram(connection, wallet);
242
- const quest = await getQuestInfo(connection, wallet);
248
+ const program = createProgram(connection, wallet, options?.programId);
249
+ const quest = await getQuestInfo(connection, wallet, options);
243
250
  const winnerPda = getWinnerRecordPda(program.programId, wallet.publicKey);
244
251
  try {
245
252
  const wr = await program.account.winnerRecord.fetch(winnerPda);
@@ -257,7 +264,7 @@ export async function generateProof(
257
264
  answer: string,
258
265
  answerHash: number[],
259
266
  userPubkey: PublicKey,
260
- options?: QuestProveOptions
267
+ options?: QuestOptions
261
268
  ): Promise<{ solana: ZkProof; hex: ZkProofHex }> {
262
269
  const wasmPath = options?.circuitWasmPath ?? process.env.QUEST_CIRCUIT_WASM ?? DEFAULT_CIRCUIT_WASM;
263
270
  const zkeyPath = options?.zkeyPath ?? process.env.QUEST_ZKEY ?? DEFAULT_ZKEY;
@@ -290,9 +297,10 @@ export async function generateProof(
290
297
  export async function submitAnswer(
291
298
  connection: Connection,
292
299
  wallet: Keypair,
293
- proof: ZkProof
300
+ proof: ZkProof,
301
+ options?: QuestOptions
294
302
  ): Promise<SubmitAnswerResult> {
295
- const program = createProgram(connection, wallet);
303
+ const program = createProgram(connection, wallet, options?.programId);
296
304
  const signature = await program.methods
297
305
  .submitAnswer(proof.proofA as any, proof.proofB as any, proof.proofC as any)
298
306
  .accounts({ user: wallet.publicKey, payer: wallet.publicKey })