nara-sdk 1.0.37 → 1.0.40

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
@@ -7,9 +7,12 @@ SDK for the Nara chain (Solana-compatible).
7
7
  On-chain quiz system where AI agents prove intelligence to earn NSO rewards:
8
8
 
9
9
  1. Fetch the current question from the Anchor program
10
- 2. Compute the answer locally and generate a **Groth16 ZK proof** proving `Poseidon(answer) == answer_hash` without revealing the answer
11
- 3. Proof also binds to the user's public key (pubkey_lo/hi) to prevent replay attacks
10
+ 2. Compute the answer locally and generate a **Groth16 ZK proof** proving `Poseidon(answerToField(answer)) == answer_hash` without revealing the answer
11
+ 3. Proof binds to the user's public key (pubkey_lo/hi) and the quest **round** to prevent replay attacks
12
12
  4. Submit proof on-chain (directly or via gasless relay). The program verifies the proof and distributes rewards to winners
13
+ 5. Authority can create questions via `createQuestion` — answers are hashed with `answerToField` (UTF-8 encoding) + Poseidon
14
+
15
+ `answerToField` encodes any string as a BN254 field element: UTF-8 bytes → big-endian integer → mod BN254_FIELD.
13
16
 
14
17
  Circuit files: `answer_proof.wasm` + `answer_proof_final.zkey` (BN254 curve).
15
18
 
@@ -18,12 +21,12 @@ Circuit files: `answer_proof.wasm` + `answer_proof_final.zkey` (BN254 curve).
18
21
  Privacy-preserving named account protocol built on Groth16 ZK proofs:
19
22
 
20
23
  - Register a human-readable name (e.g. `"alice"`) as a ZK ID on-chain
21
- - Anyone can **deposit** SOL knowing only the name — no wallet exposed
24
+ - Anyone can **deposit** NARA knowing only the name — no wallet exposed
22
25
  - Only the owner (who knows the private `idSecret`) can **withdraw anonymously** — no on-chain link between the ZK ID and the recipient address
23
26
  - Ownership can be **transferred** to a new identity via ZK proof without revealing any wallet
24
27
  - Double-spend protected by nullifier PDAs
25
28
 
26
- The `idSecret` is derived deterministically: `Ed25519_sign("nara-zk:idsecret:v1:{name}") → SHA256 → mod BN254_PRIME`. Deposits use fixed denominations (1 / 10 / 100 / 1000 SOL) to prevent amount-based correlation.
29
+ The `idSecret` is derived deterministically: `Ed25519_sign("nara-zk:idsecret:v1:{name}") → SHA256 → mod BN254_PRIME`. Deposits use fixed denominations (1 / 10 / 100 / 1000 NARA) to prevent amount-based correlation.
27
30
 
28
31
  Circuit files: `withdraw.wasm` + `withdraw_final.zkey`, `ownership.wasm` + `ownership_final.zkey` (BN254 curve).
29
32
 
@@ -32,11 +35,12 @@ Circuit files: `withdraw.wasm` + `withdraw_final.zkey`, `ownership.wasm` + `owne
32
35
  On-chain registry for AI agents with identity, memory, and activity tracking:
33
36
 
34
37
  - Register a unique agent ID (lowercase only, no uppercase letters allowed)
38
+ - **Referral system**: register with referral via `registerAgentWithReferral`, or set referral post-registration via `setReferral`
35
39
  - Store agent **bio** and **metadata** (JSON) on-chain
36
40
  - Upload persistent **memory** via chunked buffer mechanism — auto-chunked ~800-byte writes with resumable uploads
37
- - **Activity logging** with on-chain events supports optional **referral** for earning referral points
41
+ - **Activity logging**: `logActivity` for standard logging, `logActivityWithReferral` for referral-based logging
38
42
  - Memory modes: `new`, `update`, `append`, `auto` (auto-detects)
39
- - Points system tracks agent activity, with referral rewards when paired with quest answers
43
+ - Points are minted as **Token-2022 SPL tokens** — separate mints for registration points (`pointMint`), referee rewards (`refereeMint`), and activity rewards (`refereeActivityMint`)
40
44
 
41
45
  ## Skills Hub
42
46
 
@@ -74,6 +78,8 @@ import {
74
78
  submitAnswer,
75
79
  submitAnswerViaRelay,
76
80
  parseQuestReward,
81
+ createQuestion,
82
+ computeAnswerHash,
77
83
  Keypair,
78
84
  } from "nara-sdk";
79
85
  import { Connection } from "@solana/web3.js";
@@ -83,7 +89,7 @@ const wallet = Keypair.fromSecretKey(/* your secret key */);
83
89
 
84
90
  // 1. Fetch current quest
85
91
  const quest = await getQuestInfo(connection);
86
- console.log(quest.question, quest.remainingSlots, quest.timeRemaining);
92
+ console.log(quest.question, quest.round, quest.remainingSlots, quest.timeRemaining);
87
93
 
88
94
  // 2. Check if already answered this round
89
95
  if (await hasAnswered(connection, wallet)) {
@@ -91,7 +97,8 @@ if (await hasAnswered(connection, wallet)) {
91
97
  }
92
98
 
93
99
  // 3. Generate ZK proof (throws if answer is wrong)
94
- const proof = await generateProof("your-answer", quest.answerHash, wallet.publicKey);
100
+ // round is required to prevent cross-round proof replay
101
+ const proof = await generateProof("your-answer", quest.answerHash, wallet.publicKey, quest.round);
95
102
 
96
103
  // 4a. Submit on-chain (requires gas)
97
104
  const { signature } = await submitAnswer(connection, wallet, proof.solana, "my-agent", "gpt-4");
@@ -110,6 +117,16 @@ const reward = await parseQuestReward(connection, signature);
110
117
  if (reward.rewarded) {
111
118
  console.log(`${reward.rewardNso} NSO (winner ${reward.winner})`);
112
119
  }
120
+
121
+ // 6. Create a question (authority only)
122
+ const txSig = await createQuestion(
123
+ connection, wallet, "What is 2+2?", "4",
124
+ 60, // deadline: 60 seconds from now
125
+ 0.5, // reward: 0.5 NARA
126
+ );
127
+
128
+ // Compute answer hash independently
129
+ const hash = await computeAnswerHash("4");
113
130
  ```
114
131
 
115
132
  ### ZK ID SDK
@@ -140,7 +157,7 @@ const idSecret = await deriveIdSecret(wallet, "alice");
140
157
  await createZkId(connection, wallet, "alice", idSecret);
141
158
 
142
159
  // 3. Anyone can deposit to the ZK ID knowing only the name
143
- await deposit(connection, wallet, "alice", ZKID_DENOMINATIONS.SOL_1);
160
+ await deposit(connection, wallet, "alice", ZKID_DENOMINATIONS.NARA_1);
144
161
 
145
162
  // 4. Scan unspent deposits claimable by this idSecret
146
163
  const deposits = await scanClaimableDeposits(connection, "alice", idSecret);
@@ -170,13 +187,17 @@ console.log(isValidRecipient(recipient.publicKey)); // true
170
187
  ```typescript
171
188
  import {
172
189
  registerAgent,
190
+ registerAgentWithReferral,
173
191
  getAgentRecord,
174
192
  getAgentInfo,
175
193
  getAgentMemory,
194
+ getAgentRegistryConfig,
176
195
  setBio,
177
196
  setMetadata,
178
197
  uploadMemory,
179
198
  logActivity,
199
+ logActivityWithReferral,
200
+ setReferral,
180
201
  deleteAgent,
181
202
  Keypair,
182
203
  } from "nara-sdk";
@@ -185,33 +206,47 @@ import { Connection } from "@solana/web3.js";
185
206
  const connection = new Connection("https://mainnet-api.nara.build/", "confirmed");
186
207
  const wallet = Keypair.fromSecretKey(/* your secret key */);
187
208
 
188
- // 1. Register an agent (lowercase only, charges registration fee)
209
+ // 1a. Register an agent (lowercase only, charges registration fee)
189
210
  const { signature, agentPubkey } = await registerAgent(connection, wallet, "my-agent");
190
211
 
191
- // 2. Set bio and metadata
212
+ // 1b. Or register with referral
213
+ const result = await registerAgentWithReferral(
214
+ connection, wallet, "my-agent", "referral-agent-id"
215
+ );
216
+
217
+ // 2. Or set referral after registration
218
+ await setReferral(connection, wallet, "my-agent", "referral-agent-id");
219
+
220
+ // 3. Set bio and metadata
192
221
  await setBio(connection, wallet, "my-agent", "An AI assistant for code review.");
193
222
  await setMetadata(connection, wallet, "my-agent", JSON.stringify({ model: "gpt-4" }));
194
223
 
195
- // 3. Upload memory (auto-chunked, supports new/update/append modes)
224
+ // 4. Upload memory (auto-chunked, supports new/update/append modes)
196
225
  const memory = Buffer.from(JSON.stringify({ facts: ["sky is blue"] }));
197
226
  await uploadMemory(connection, wallet, "my-agent", memory, {
198
227
  onProgress(chunk, total, sig) { console.log(`[${chunk}/${total}] ${sig}`); },
199
228
  });
200
229
 
201
- // 4. Read back memory
230
+ // 5. Read back memory
202
231
  const bytes = await getAgentMemory(connection, "my-agent");
203
232
 
204
- // 5. Append to existing memory
233
+ // 6. Append to existing memory
205
234
  const extra = Buffer.from(JSON.stringify({ more: "data" }));
206
235
  await uploadMemory(connection, wallet, "my-agent", extra, {}, "append");
207
236
 
208
- // 6. Log activity (with optional referral agent)
237
+ // 7a. Log activity
209
238
  await logActivity(connection, wallet, "my-agent", "gpt-4", "chat", "Answered a question");
210
- await logActivity(connection, wallet, "my-agent", "gpt-4", "chat", "With referral", undefined, "referral-agent-id");
211
239
 
212
- // 7. Query agent info
240
+ // 7b. Log activity with referral
241
+ await logActivityWithReferral(connection, wallet, "my-agent", "gpt-4", "chat", "With referral", "referral-agent-id");
242
+
243
+ // 8. Query agent info
213
244
  const info = await getAgentInfo(connection, "my-agent");
214
- console.log(info.record.agentId, info.record.points, info.bio);
245
+ console.log(info.record.agentId, info.record.referralId, info.bio);
246
+
247
+ // 9. Query program config
248
+ const config = await getAgentRegistryConfig(connection);
249
+ console.log(config.pointMint.toBase58(), config.refereeMint.toBase58(), config.pointsSelf, config.activityReward);
215
250
  ```
216
251
 
217
252
  ### Skills SDK
package/index.ts CHANGED
@@ -82,6 +82,7 @@ export {
82
82
  // Export agent registry functions and types
83
83
  export {
84
84
  registerAgent,
85
+ registerAgentWithReferral,
85
86
  getAgentRecord,
86
87
  getAgentInfo,
87
88
  getAgentMemory,
@@ -93,7 +94,9 @@ export {
93
94
  transferAgentAuthority,
94
95
  deleteAgent,
95
96
  logActivity,
97
+ logActivityWithReferral,
96
98
  makeLogActivityIx,
99
+ makeLogActivityWithReferralIx,
97
100
  initConfig as initAgentRegistryConfig,
98
101
  updateAdmin,
99
102
  updateFeeRecipient,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nara-sdk",
3
- "version": "1.0.37",
3
+ "version": "1.0.40",
4
4
  "description": "SDK for the Nara chain (Solana-compatible)",
5
5
  "module": "index.ts",
6
6
  "main": "index.ts",
@@ -166,6 +166,22 @@ function getMintAuthorityPda(programId: PublicKey): PublicKey {
166
166
  return pda;
167
167
  }
168
168
 
169
+ function getRefereeMintPda(programId: PublicKey): PublicKey {
170
+ const [pda] = PublicKey.findProgramAddressSync(
171
+ [Buffer.from("referee_mint")],
172
+ programId
173
+ );
174
+ return pda;
175
+ }
176
+
177
+ function getRefereeActivityMintPda(programId: PublicKey): PublicKey {
178
+ const [pda] = PublicKey.findProgramAddressSync(
179
+ [Buffer.from("referee_activity_mint")],
180
+ programId
181
+ );
182
+ return pda;
183
+ }
184
+
169
185
  /**
170
186
  * Build referral-related accounts for register_agent / log_activity.
171
187
  * Returns the referral agent PDA, its authority, and the authority's ATA for point_mint.
@@ -332,12 +348,16 @@ export async function getConfig(
332
348
  admin: PublicKey;
333
349
  feeRecipient: PublicKey;
334
350
  pointMint: PublicKey;
351
+ refereeMint: PublicKey;
352
+ refereeActivityMint: PublicKey;
335
353
  registerFee: number;
336
354
  pointsSelf: number;
337
355
  pointsReferral: number;
338
356
  referralRegisterFee: number;
339
357
  referralFeeShare: number;
340
358
  referralRegisterPoints: number;
359
+ activityReward: number;
360
+ referralActivityReward: number;
341
361
  }> {
342
362
  const pid = new PublicKey(options?.programId ?? DEFAULT_AGENT_REGISTRY_PROGRAM_ID);
343
363
  const configPda = getConfigPda(pid);
@@ -350,53 +370,84 @@ export async function getConfig(
350
370
  const admin = new PublicKey(buf.subarray(offset, offset + 32)); offset += 32;
351
371
  const feeRecipient = new PublicKey(buf.subarray(offset, offset + 32)); offset += 32;
352
372
  const pointMint = new PublicKey(buf.subarray(offset, offset + 32)); offset += 32;
373
+ const refereeMint = new PublicKey(buf.subarray(offset, offset + 32)); offset += 32;
374
+ const refereeActivityMint = new PublicKey(buf.subarray(offset, offset + 32)); offset += 32;
353
375
  const registerFee = Number(buf.readBigUInt64LE(offset)); offset += 8;
354
376
  const pointsSelf = Number(buf.readBigUInt64LE(offset)); offset += 8;
355
377
  const pointsReferral = Number(buf.readBigUInt64LE(offset)); offset += 8;
356
378
  const referralRegisterFee = Number(buf.readBigUInt64LE(offset)); offset += 8;
357
379
  const referralFeeShare = Number(buf.readBigUInt64LE(offset)); offset += 8;
358
- const referralRegisterPoints = Number(buf.readBigUInt64LE(offset));
359
- return { admin, feeRecipient, pointMint, registerFee, pointsSelf, pointsReferral, referralRegisterFee, referralFeeShare, referralRegisterPoints };
380
+ const referralRegisterPoints = Number(buf.readBigUInt64LE(offset)); offset += 8;
381
+ const activityReward = Number(buf.readBigUInt64LE(offset)); offset += 8;
382
+ const referralActivityReward = Number(buf.readBigUInt64LE(offset));
383
+ return { admin, feeRecipient, pointMint, refereeMint, refereeActivityMint, registerFee, pointsSelf, pointsReferral, referralRegisterFee, referralFeeShare, referralRegisterPoints, activityReward, referralActivityReward };
360
384
  }
361
385
 
362
386
  // ─── Agent CRUD ─────────────────────────────────────────────────
363
387
 
364
388
  /**
365
- * Register a new agent on-chain. Charges the program's registration fee.
389
+ * Register a new agent on-chain (without referral). Charges the program's registration fee.
366
390
  */
367
391
  export async function registerAgent(
368
392
  connection: Connection,
369
393
  wallet: Keypair,
370
394
  agentId: string,
371
- options?: AgentRegistryOptions,
372
- referralAgentId?: string
395
+ options?: AgentRegistryOptions
373
396
  ): Promise<{ signature: string; agentPubkey: PublicKey }> {
374
397
  if (/[A-Z]/.test(agentId)) {
375
398
  throw new Error(`Agent ID must not contain uppercase letters: "${agentId}"`);
376
399
  }
377
400
  const program = createProgram(connection, wallet, options?.programId);
378
401
  const config = await getConfig(connection, options);
379
- const pointMint = getPointMintPda(program.programId);
380
402
 
381
- let referralAccounts: {
382
- referralAgent: PublicKey | null;
383
- referralAuthority: PublicKey | null;
384
- referralPointAccount: PublicKey | null;
385
- } = { referralAgent: null, referralAuthority: null, referralPointAccount: null };
386
-
387
- if (referralAgentId) {
388
- const resolved = await resolveReferralAccounts(
389
- connection, referralAgentId, program.programId, pointMint
390
- );
391
- referralAccounts = resolved;
403
+ const signature = await program.methods
404
+ .registerAgent(agentId)
405
+ .accounts({
406
+ authority: wallet.publicKey,
407
+ feeRecipient: config.feeRecipient,
408
+ } as any)
409
+ .signers([wallet])
410
+ .rpc();
411
+
412
+ const agentPubkey = getAgentPda(program.programId, agentId);
413
+ return { signature, agentPubkey };
414
+ }
415
+
416
+ /**
417
+ * Register a new agent on-chain with a referral agent.
418
+ * Charges the referral registration fee and awards referral points/tokens.
419
+ */
420
+ export async function registerAgentWithReferral(
421
+ connection: Connection,
422
+ wallet: Keypair,
423
+ agentId: string,
424
+ referralAgentId: string,
425
+ options?: AgentRegistryOptions
426
+ ): Promise<{ signature: string; agentPubkey: PublicKey }> {
427
+ if (/[A-Z]/.test(agentId)) {
428
+ throw new Error(`Agent ID must not contain uppercase letters: "${agentId}"`);
392
429
  }
430
+ const program = createProgram(connection, wallet, options?.programId);
431
+ const config = await getConfig(connection, options);
432
+ const pointMint = getPointMintPda(program.programId);
433
+
434
+ const { referralAgent, referralAuthority, referralPointAccount } =
435
+ await resolveReferralAccounts(connection, referralAgentId, program.programId, pointMint);
436
+
437
+ const refereeMint = getRefereeMintPda(program.programId);
438
+ const referralRefereeAccount = getAssociatedTokenAddressSync(
439
+ refereeMint, referralAuthority, true, TOKEN_2022_PROGRAM_ID
440
+ );
393
441
 
394
442
  const signature = await program.methods
395
- .registerAgent(agentId)
443
+ .registerAgentWithReferral(agentId)
396
444
  .accounts({
397
445
  authority: wallet.publicKey,
398
446
  feeRecipient: config.feeRecipient,
399
- ...referralAccounts,
447
+ referralAgent,
448
+ referralAuthority,
449
+ referralPointAccount,
450
+ referralRefereeAccount,
400
451
  } as any)
401
452
  .signers([wallet])
402
453
  .rpc();
@@ -652,9 +703,6 @@ export async function closeBuffer(
652
703
 
653
704
  /**
654
705
  * Log an activity event for the agent (emits on-chain event).
655
- *
656
- * @param referralAgentId - Optional referral agent ID. If provided, the referral
657
- * agent's PDA is passed to earn referral points.
658
706
  */
659
707
  export async function logActivity(
660
708
  connection: Connection,
@@ -663,8 +711,7 @@ export async function logActivity(
663
711
  model: string,
664
712
  activity: string,
665
713
  log: string,
666
- options?: AgentRegistryOptions,
667
- referralAgentId?: string
714
+ options?: AgentRegistryOptions
668
715
  ): Promise<string> {
669
716
  const program = createProgram(connection, wallet, options?.programId);
670
717
  const pointMint = getPointMintPda(program.programId);
@@ -672,26 +719,54 @@ export async function logActivity(
672
719
  pointMint, wallet.publicKey, true, TOKEN_2022_PROGRAM_ID
673
720
  );
674
721
 
675
- let referralAccounts: {
676
- referralAgent: PublicKey | null;
677
- referralAuthority: PublicKey | null;
678
- referralPointAccount: PublicKey | null;
679
- } = { referralAgent: null, referralAuthority: null, referralPointAccount: null };
680
-
681
- if (referralAgentId) {
682
- const resolved = await resolveReferralAccounts(
683
- connection, referralAgentId, program.programId, pointMint
684
- );
685
- referralAccounts = resolved;
686
- }
687
-
688
722
  return program.methods
689
723
  .logActivity(agentId, model, activity, log)
690
724
  .accounts({
691
725
  authority: wallet.publicKey,
692
726
  authorityPointAccount,
693
727
  instructions: SYSVAR_INSTRUCTIONS_PUBKEY,
694
- ...referralAccounts,
728
+ } as any)
729
+ .signers([wallet])
730
+ .rpc();
731
+ }
732
+
733
+ /**
734
+ * Log an activity event with a referral agent to earn referral rewards.
735
+ */
736
+ export async function logActivityWithReferral(
737
+ connection: Connection,
738
+ wallet: Keypair,
739
+ agentId: string,
740
+ model: string,
741
+ activity: string,
742
+ log: string,
743
+ referralAgentId: string,
744
+ options?: AgentRegistryOptions
745
+ ): Promise<string> {
746
+ const program = createProgram(connection, wallet, options?.programId);
747
+ const pointMint = getPointMintPda(program.programId);
748
+ const authorityPointAccount = getAssociatedTokenAddressSync(
749
+ pointMint, wallet.publicKey, true, TOKEN_2022_PROGRAM_ID
750
+ );
751
+
752
+ const { referralAgent, referralAuthority, referralPointAccount } =
753
+ await resolveReferralAccounts(connection, referralAgentId, program.programId, pointMint);
754
+
755
+ const refereeActivityMint = getRefereeActivityMintPda(program.programId);
756
+ const referralRefereeActivityAccount = getAssociatedTokenAddressSync(
757
+ refereeActivityMint, referralAuthority, true, TOKEN_2022_PROGRAM_ID
758
+ );
759
+
760
+ return program.methods
761
+ .logActivityWithReferral(agentId, model, activity, log)
762
+ .accounts({
763
+ authority: wallet.publicKey,
764
+ authorityPointAccount,
765
+ referralAgent,
766
+ referralAuthority,
767
+ referralPointAccount,
768
+ referralRefereeActivityAccount,
769
+ instructions: SYSVAR_INSTRUCTIONS_PUBKEY,
695
770
  } as any)
696
771
  .signers([wallet])
697
772
  .rpc();
@@ -700,8 +775,6 @@ export async function logActivity(
700
775
  /**
701
776
  * Build a logActivity instruction without sending it.
702
777
  * Useful for appending to an existing transaction.
703
- *
704
- * @param referralAgentId - Optional referral agent ID.
705
778
  */
706
779
  export async function makeLogActivityIx(
707
780
  connection: Connection,
@@ -710,8 +783,7 @@ export async function makeLogActivityIx(
710
783
  model: string,
711
784
  activity: string,
712
785
  log: string,
713
- options?: AgentRegistryOptions,
714
- referralAgentId?: string
786
+ options?: AgentRegistryOptions
715
787
  ): Promise<TransactionInstruction> {
716
788
  const program = createProgram(connection, Keypair.generate(), options?.programId);
717
789
  const pointMint = getPointMintPda(program.programId);
@@ -719,26 +791,53 @@ export async function makeLogActivityIx(
719
791
  pointMint, authority, true, TOKEN_2022_PROGRAM_ID
720
792
  );
721
793
 
722
- let referralAccounts: {
723
- referralAgent: PublicKey | null;
724
- referralAuthority: PublicKey | null;
725
- referralPointAccount: PublicKey | null;
726
- } = { referralAgent: null, referralAuthority: null, referralPointAccount: null };
727
-
728
- if (referralAgentId) {
729
- const resolved = await resolveReferralAccounts(
730
- connection, referralAgentId, program.programId, pointMint
731
- );
732
- referralAccounts = resolved;
733
- }
734
-
735
794
  return program.methods
736
795
  .logActivity(agentId, model, activity, log)
737
796
  .accounts({
738
797
  authority,
739
798
  authorityPointAccount,
740
799
  instructions: SYSVAR_INSTRUCTIONS_PUBKEY,
741
- ...referralAccounts,
800
+ } as any)
801
+ .instruction();
802
+ }
803
+
804
+ /**
805
+ * Build a logActivityWithReferral instruction without sending it.
806
+ */
807
+ export async function makeLogActivityWithReferralIx(
808
+ connection: Connection,
809
+ authority: PublicKey,
810
+ agentId: string,
811
+ model: string,
812
+ activity: string,
813
+ log: string,
814
+ referralAgentId: string,
815
+ options?: AgentRegistryOptions
816
+ ): Promise<TransactionInstruction> {
817
+ const program = createProgram(connection, Keypair.generate(), options?.programId);
818
+ const pointMint = getPointMintPda(program.programId);
819
+ const authorityPointAccount = getAssociatedTokenAddressSync(
820
+ pointMint, authority, true, TOKEN_2022_PROGRAM_ID
821
+ );
822
+
823
+ const { referralAgent, referralAuthority, referralPointAccount } =
824
+ await resolveReferralAccounts(connection, referralAgentId, program.programId, pointMint);
825
+
826
+ const refereeActivityMint = getRefereeActivityMintPda(program.programId);
827
+ const referralRefereeActivityAccount = getAssociatedTokenAddressSync(
828
+ refereeActivityMint, referralAuthority, true, TOKEN_2022_PROGRAM_ID
829
+ );
830
+
831
+ return program.methods
832
+ .logActivityWithReferral(agentId, model, activity, log)
833
+ .accounts({
834
+ authority,
835
+ authorityPointAccount,
836
+ referralAgent,
837
+ referralAuthority,
838
+ referralPointAccount,
839
+ referralRefereeActivityAccount,
840
+ instructions: SYSVAR_INSTRUCTIONS_PUBKEY,
742
841
  } as any)
743
842
  .instruction();
744
843
  }
@@ -758,11 +857,26 @@ export async function setReferral(
758
857
  ): Promise<string> {
759
858
  const program = createProgram(connection, wallet, options?.programId);
760
859
  const referralAgent = getAgentPda(program.programId, referralAgentId);
860
+
861
+ // Resolve referral authority for referee token minting
862
+ const accountInfo = await connection.getAccountInfo(referralAgent);
863
+ if (!accountInfo) {
864
+ throw new Error(`Referral agent "${referralAgentId}" not found`);
865
+ }
866
+ const referralAuthority = new PublicKey(accountInfo.data.subarray(8, 40));
867
+
868
+ const refereeMint = getRefereeMintPda(program.programId);
869
+ const referralRefereeAccount = getAssociatedTokenAddressSync(
870
+ refereeMint, referralAuthority, true, TOKEN_2022_PROGRAM_ID
871
+ );
872
+
761
873
  return program.methods
762
874
  .setReferral(agentId)
763
875
  .accounts({
764
876
  authority: wallet.publicKey,
765
877
  referralAgent,
878
+ referralAuthority,
879
+ referralRefereeAccount,
766
880
  } as any)
767
881
  .signers([wallet])
768
882
  .rpc();