nara-sdk 1.0.32 → 1.0.34

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 CHANGED
@@ -45,6 +45,7 @@ export {
45
45
  transferAuthority,
46
46
  closeBuffer,
47
47
  deleteSkill,
48
+ getConfig as getSkillsConfig,
48
49
  initConfig as initSkillsConfig,
49
50
  updateAdmin as updateSkillsAdmin,
50
51
  updateFeeRecipient as updateSkillsFeeRecipient,
@@ -96,6 +97,8 @@ export {
96
97
  updateFeeRecipient,
97
98
  updateRegisterFee,
98
99
  updatePointsConfig,
100
+ setReferral,
101
+ updateReferralConfig,
99
102
  type AgentRecord,
100
103
  type AgentInfo,
101
104
  type MemoryMode,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nara-sdk",
3
- "version": "1.0.32",
3
+ "version": "1.0.34",
4
4
  "description": "SDK for the Nara chain (Solana-compatible)",
5
5
  "module": "index.ts",
6
6
  "main": "index.ts",
@@ -12,6 +12,7 @@ import {
12
12
  } from "@solana/web3.js";
13
13
  import * as anchor from "@coral-xyz/anchor";
14
14
  import { Program, AnchorProvider, Wallet } from "@coral-xyz/anchor";
15
+ import { getAssociatedTokenAddressSync, TOKEN_2022_PROGRAM_ID } from "@solana/spl-token";
15
16
  import type { NaraAgentRegistry } from "./idls/nara_agent_registry";
16
17
  import { DEFAULT_AGENT_REGISTRY_PROGRAM_ID } from "./constants";
17
18
 
@@ -74,8 +75,8 @@ export interface AgentRecord {
74
75
  memory: PublicKey;
75
76
  /** 0 = no memory, increments on each upload */
76
77
  version: number;
77
- /** Accumulated activity points */
78
- points: number;
78
+ /** Referral agent ID, null if none */
79
+ referralId: string | null;
79
80
  createdAt: number;
80
81
  updatedAt: number;
81
82
  }
@@ -149,6 +150,45 @@ function getMetaPda(programId: PublicKey, agentPubkey: PublicKey): PublicKey {
149
150
  return pda;
150
151
  }
151
152
 
153
+ function getPointMintPda(programId: PublicKey): PublicKey {
154
+ const [pda] = PublicKey.findProgramAddressSync(
155
+ [Buffer.from("point_mint")],
156
+ programId
157
+ );
158
+ return pda;
159
+ }
160
+
161
+ function getMintAuthorityPda(programId: PublicKey): PublicKey {
162
+ const [pda] = PublicKey.findProgramAddressSync(
163
+ [Buffer.from("mint_authority")],
164
+ programId
165
+ );
166
+ return pda;
167
+ }
168
+
169
+ /**
170
+ * Build referral-related accounts for register_agent / log_activity.
171
+ * Returns the referral agent PDA, its authority, and the authority's ATA for point_mint.
172
+ */
173
+ async function resolveReferralAccounts(
174
+ connection: Connection,
175
+ referralAgentId: string,
176
+ programId: PublicKey,
177
+ pointMint: PublicKey
178
+ ): Promise<{ referralAgent: PublicKey; referralAuthority: PublicKey; referralPointAccount: PublicKey }> {
179
+ const referralAgent = getAgentPda(programId, referralAgentId);
180
+ const accountInfo = await connection.getAccountInfo(referralAgent);
181
+ if (!accountInfo) {
182
+ throw new Error(`Referral agent "${referralAgentId}" not found`);
183
+ }
184
+ // Authority is first 32 bytes after 8-byte discriminator
185
+ const referralAuthority = new PublicKey(accountInfo.data.subarray(8, 40));
186
+ const referralPointAccount = getAssociatedTokenAddressSync(
187
+ pointMint, referralAuthority, true, TOKEN_2022_PROGRAM_ID
188
+ );
189
+ return { referralAgent, referralAuthority, referralPointAccount };
190
+ }
191
+
152
192
  /** Bio/Metadata header: 8-byte discriminator + 64-byte _reserved */
153
193
  const BIO_META_HEADER_SIZE = 72;
154
194
 
@@ -156,8 +196,9 @@ const BIO_META_HEADER_SIZE = 72;
156
196
  * Parse AgentRecord from raw account data (bytemuck zero-copy layout).
157
197
  * Layout (after 8-byte discriminator):
158
198
  * 32 authority | 32 pending_buffer | 32 memory |
159
- * 8 created_at | 8 updated_at | 8 points |
160
- * 4 version | 4 agent_id_len | 32 agent_id | 64 _reserved
199
+ * 8 created_at | 8 updated_at |
200
+ * 4 version | 4 agent_id_len | 32 agent_id |
201
+ * 4 referral_id_len | 32 referral_id | 4 _padding | 64 _reserved
161
202
  */
162
203
  function parseAgentRecordData(data: Buffer | Uint8Array): AgentRecord {
163
204
  const buf = Buffer.from(data);
@@ -169,11 +210,15 @@ function parseAgentRecordData(data: Buffer | Uint8Array): AgentRecord {
169
210
 
170
211
  const createdAt = Number(buf.readBigInt64LE(offset)); offset += 8;
171
212
  const updatedAt = Number(buf.readBigInt64LE(offset)); offset += 8;
172
- const points = Number(buf.readBigUInt64LE(offset)); offset += 8;
173
213
 
174
214
  const version = buf.readUInt32LE(offset); offset += 4;
175
215
  const agentIdLen = buf.readUInt32LE(offset); offset += 4;
176
- const agentId = buf.subarray(offset, offset + agentIdLen).toString("utf-8");
216
+ const agentId = buf.subarray(offset, offset + agentIdLen).toString("utf-8"); offset += 32;
217
+
218
+ const referralIdLen = buf.readUInt32LE(offset); offset += 4;
219
+ const referralId = referralIdLen > 0
220
+ ? buf.subarray(offset, offset + referralIdLen).toString("utf-8")
221
+ : null;
177
222
 
178
223
  return {
179
224
  authority,
@@ -181,7 +226,7 @@ function parseAgentRecordData(data: Buffer | Uint8Array): AgentRecord {
181
226
  pendingBuffer: pendingBuffer.equals(PublicKey.default) ? null : pendingBuffer,
182
227
  memory,
183
228
  version,
184
- points,
229
+ referralId,
185
230
  createdAt,
186
231
  updatedAt,
187
232
  };
@@ -285,10 +330,14 @@ export async function getConfig(
285
330
  options?: AgentRegistryOptions
286
331
  ): Promise<{
287
332
  admin: PublicKey;
288
- registerFee: number;
289
333
  feeRecipient: PublicKey;
334
+ pointMint: PublicKey;
335
+ registerFee: number;
290
336
  pointsSelf: number;
291
337
  pointsReferral: number;
338
+ referralRegisterFee: number;
339
+ referralFeeShare: number;
340
+ referralRegisterPoints: number;
292
341
  }> {
293
342
  const pid = new PublicKey(options?.programId ?? DEFAULT_AGENT_REGISTRY_PROGRAM_ID);
294
343
  const configPda = getConfigPda(pid);
@@ -300,10 +349,14 @@ export async function getConfig(
300
349
  let offset = 8; // skip discriminator
301
350
  const admin = new PublicKey(buf.subarray(offset, offset + 32)); offset += 32;
302
351
  const feeRecipient = new PublicKey(buf.subarray(offset, offset + 32)); offset += 32;
352
+ const pointMint = new PublicKey(buf.subarray(offset, offset + 32)); offset += 32;
303
353
  const registerFee = Number(buf.readBigUInt64LE(offset)); offset += 8;
304
354
  const pointsSelf = Number(buf.readBigUInt64LE(offset)); offset += 8;
305
- const pointsReferral = Number(buf.readBigUInt64LE(offset));
306
- return { admin, registerFee, feeRecipient, pointsSelf, pointsReferral };
355
+ const pointsReferral = Number(buf.readBigUInt64LE(offset)); offset += 8;
356
+ const referralRegisterFee = Number(buf.readBigUInt64LE(offset)); offset += 8;
357
+ 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 };
307
360
  }
308
361
 
309
362
  // ─── Agent CRUD ─────────────────────────────────────────────────
@@ -315,20 +368,35 @@ export async function registerAgent(
315
368
  connection: Connection,
316
369
  wallet: Keypair,
317
370
  agentId: string,
318
- options?: AgentRegistryOptions
371
+ options?: AgentRegistryOptions,
372
+ referralAgentId?: string
319
373
  ): Promise<{ signature: string; agentPubkey: PublicKey }> {
320
374
  if (/[A-Z]/.test(agentId)) {
321
375
  throw new Error(`Agent ID must not contain uppercase letters: "${agentId}"`);
322
376
  }
323
377
  const program = createProgram(connection, wallet, options?.programId);
324
- const configPda = getConfigPda(program.programId);
325
- const config = await program.account.programConfig.fetch(configPda);
378
+ const config = await getConfig(connection, options);
379
+ const pointMint = getPointMintPda(program.programId);
380
+
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;
392
+ }
326
393
 
327
394
  const signature = await program.methods
328
395
  .registerAgent(agentId)
329
396
  .accounts({
330
397
  authority: wallet.publicKey,
331
398
  feeRecipient: config.feeRecipient,
399
+ ...referralAccounts,
332
400
  } as any)
333
401
  .signers([wallet])
334
402
  .rpc();
@@ -599,14 +667,31 @@ export async function logActivity(
599
667
  referralAgentId?: string
600
668
  ): Promise<string> {
601
669
  const program = createProgram(connection, wallet, options?.programId);
670
+ const pointMint = getPointMintPda(program.programId);
671
+ const authorityPointAccount = getAssociatedTokenAddressSync(
672
+ pointMint, wallet.publicKey, true, TOKEN_2022_PROGRAM_ID
673
+ );
674
+
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
+
602
688
  return program.methods
603
689
  .logActivity(agentId, model, activity, log)
604
690
  .accounts({
605
691
  authority: wallet.publicKey,
692
+ authorityPointAccount,
606
693
  instructions: SYSVAR_INSTRUCTIONS_PUBKEY,
607
- referralAgent: referralAgentId
608
- ? getAgentPda(program.programId, referralAgentId)
609
- : null,
694
+ ...referralAccounts,
610
695
  } as any)
611
696
  .signers([wallet])
612
697
  .rpc();
@@ -629,18 +714,60 @@ export async function makeLogActivityIx(
629
714
  referralAgentId?: string
630
715
  ): Promise<TransactionInstruction> {
631
716
  const program = createProgram(connection, Keypair.generate(), options?.programId);
717
+ const pointMint = getPointMintPda(program.programId);
718
+ const authorityPointAccount = getAssociatedTokenAddressSync(
719
+ pointMint, authority, true, TOKEN_2022_PROGRAM_ID
720
+ );
721
+
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
+
632
735
  return program.methods
633
736
  .logActivity(agentId, model, activity, log)
634
737
  .accounts({
635
738
  authority,
739
+ authorityPointAccount,
636
740
  instructions: SYSVAR_INSTRUCTIONS_PUBKEY,
637
- referralAgent: referralAgentId
638
- ? getAgentPda(program.programId, referralAgentId)
639
- : null,
741
+ ...referralAccounts,
640
742
  } as any)
641
743
  .instruction();
642
744
  }
643
745
 
746
+ // ─── Referral ────────────────────────────────────────────────────
747
+
748
+ /**
749
+ * Set a referral agent for the given agent. Can only be set once.
750
+ * The referral agent must exist and cannot be the agent itself.
751
+ */
752
+ export async function setReferral(
753
+ connection: Connection,
754
+ wallet: Keypair,
755
+ agentId: string,
756
+ referralAgentId: string,
757
+ options?: AgentRegistryOptions
758
+ ): Promise<string> {
759
+ const program = createProgram(connection, wallet, options?.programId);
760
+ const referralAgent = getAgentPda(program.programId, referralAgentId);
761
+ return program.methods
762
+ .setReferral(agentId)
763
+ .accounts({
764
+ authority: wallet.publicKey,
765
+ referralAgent,
766
+ } as any)
767
+ .signers([wallet])
768
+ .rpc();
769
+ }
770
+
644
771
  // ─── Admin functions ────────────────────────────────────────────
645
772
 
646
773
  /**
@@ -732,3 +859,28 @@ export async function updatePointsConfig(
732
859
  .signers([wallet])
733
860
  .rpc();
734
861
  }
862
+
863
+ /**
864
+ * Update the referral configuration (admin-only).
865
+ * @param referralRegisterFee - Fee charged on referral registrations (lamports)
866
+ * @param referralFeeShare - Share of registration fee given to referrer (lamports, must <= referralRegisterFee)
867
+ * @param referralRegisterPoints - Points awarded to referrer on registration
868
+ */
869
+ export async function updateReferralConfig(
870
+ connection: Connection,
871
+ wallet: Keypair,
872
+ referralRegisterFee: number | anchor.BN,
873
+ referralFeeShare: number | anchor.BN,
874
+ referralRegisterPoints: number | anchor.BN,
875
+ options?: AgentRegistryOptions
876
+ ): Promise<string> {
877
+ const program = createProgram(connection, wallet, options?.programId);
878
+ const fee = typeof referralRegisterFee === "number" ? new anchor.BN(referralRegisterFee) : referralRegisterFee;
879
+ const share = typeof referralFeeShare === "number" ? new anchor.BN(referralFeeShare) : referralFeeShare;
880
+ const pts = typeof referralRegisterPoints === "number" ? new anchor.BN(referralRegisterPoints) : referralRegisterPoints;
881
+ return program.methods
882
+ .updateReferralConfig(fee, share, pts)
883
+ .accounts({ admin: wallet.publicKey } as any)
884
+ .signers([wallet])
885
+ .rpc();
886
+ }