nara-sdk 1.0.34 → 1.0.36
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/index.ts +2 -0
- package/package.json +1 -1
- package/src/quest.ts +57 -0
package/index.ts
CHANGED
package/package.json
CHANGED
package/src/quest.ts
CHANGED
|
@@ -264,11 +264,18 @@ export async function hasAnswered(
|
|
|
264
264
|
/**
|
|
265
265
|
* Generate a ZK proof for a quest answer.
|
|
266
266
|
* Throws if the answer is wrong (circuit assertion fails).
|
|
267
|
+
*
|
|
268
|
+
* @param answer - The answer string (passed directly as circuit input)
|
|
269
|
+
* @param answerHash - The on-chain answer hash bytes
|
|
270
|
+
* @param userPubkey - The user's public key (binds proof to user)
|
|
271
|
+
* @param round - The quest round number (binds proof to round, prevents replay)
|
|
272
|
+
* @param options - Optional circuit paths
|
|
267
273
|
*/
|
|
268
274
|
export async function generateProof(
|
|
269
275
|
answer: string,
|
|
270
276
|
answerHash: number[],
|
|
271
277
|
userPubkey: PublicKey,
|
|
278
|
+
round: string,
|
|
272
279
|
options?: QuestOptions
|
|
273
280
|
): Promise<{ solana: ZkProof; hex: ZkProofHex }> {
|
|
274
281
|
const wasmPath = options?.circuitWasmPath ?? process.env.QUEST_CIRCUIT_WASM ?? DEFAULT_CIRCUIT_WASM;
|
|
@@ -285,6 +292,7 @@ export async function generateProof(
|
|
|
285
292
|
answer_hash: answerHashFieldStr,
|
|
286
293
|
pubkey_lo: lo,
|
|
287
294
|
pubkey_hi: hi,
|
|
295
|
+
round: round,
|
|
288
296
|
},
|
|
289
297
|
wasmPath,
|
|
290
298
|
zkeyPath
|
|
@@ -427,3 +435,52 @@ export async function parseQuestReward(
|
|
|
427
435
|
winner,
|
|
428
436
|
};
|
|
429
437
|
}
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* Compute the Poseidon answer hash for a given answer string.
|
|
441
|
+
* Uses answerToField (UTF-8 encoding) consistent with on-chain question creation.
|
|
442
|
+
*/
|
|
443
|
+
export async function computeAnswerHash(answer: string): Promise<number[]> {
|
|
444
|
+
const circomlibjs = await import("circomlibjs");
|
|
445
|
+
const poseidon = await circomlibjs.buildPoseidon();
|
|
446
|
+
const fieldVal = answerToField(answer);
|
|
447
|
+
const hashRaw = poseidon([fieldVal]);
|
|
448
|
+
const hashStr: string = poseidon.F.toString(hashRaw);
|
|
449
|
+
return Array.from(toBigEndian32(BigInt(hashStr)));
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
/**
|
|
453
|
+
* Create a new quest question on-chain (authority only).
|
|
454
|
+
*
|
|
455
|
+
* @param connection - Solana connection
|
|
456
|
+
* @param wallet - Authority keypair (must be the program authority)
|
|
457
|
+
* @param question - The question text
|
|
458
|
+
* @param answer - The answer string (will be hashed with Poseidon + answerToField)
|
|
459
|
+
* @param deadlineSeconds - Duration in seconds from now until the deadline
|
|
460
|
+
* @param rewardSol - Total reward amount in SOL/NARA
|
|
461
|
+
* @param difficulty - Difficulty level (default: 1)
|
|
462
|
+
* @param options - Optional program ID override
|
|
463
|
+
*/
|
|
464
|
+
export async function createQuestion(
|
|
465
|
+
connection: Connection,
|
|
466
|
+
wallet: Keypair,
|
|
467
|
+
question: string,
|
|
468
|
+
answer: string,
|
|
469
|
+
deadlineSeconds: number,
|
|
470
|
+
rewardSol: number,
|
|
471
|
+
difficulty: number = 1,
|
|
472
|
+
options?: QuestOptions
|
|
473
|
+
): Promise<string> {
|
|
474
|
+
const program = createProgram(connection, wallet, options?.programId);
|
|
475
|
+
const answerHash = await computeAnswerHash(answer);
|
|
476
|
+
const deadline = new anchor.BN(Math.floor(Date.now() / 1000) + deadlineSeconds);
|
|
477
|
+
const rewardAmount = new anchor.BN(Math.round(rewardSol * LAMPORTS_PER_SOL));
|
|
478
|
+
|
|
479
|
+
const signature = await program.methods
|
|
480
|
+
.createQuestion(question, answerHash as any, deadline, rewardAmount, difficulty)
|
|
481
|
+
.accounts({ authority: wallet.publicKey } as any)
|
|
482
|
+
.signers([wallet])
|
|
483
|
+
.rpc();
|
|
484
|
+
|
|
485
|
+
return signature;
|
|
486
|
+
}
|