nara-sdk 1.0.30 → 1.0.32
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 +78 -11
- package/index.ts +12 -0
- package/package.json +1 -1
- package/src/agent_registry.ts +57 -30
- package/src/idls/nara_agent_registry.json +83 -1
- package/src/idls/nara_agent_registry.ts +83 -1
- package/src/skills.ts +3 -0
- package/src/zkid.ts +24 -0
package/README.md
CHANGED
|
@@ -27,11 +27,22 @@ The `idSecret` is derived deterministically: `Ed25519_sign("nara-zk:idsecret:v1:
|
|
|
27
27
|
|
|
28
28
|
Circuit files: `withdraw.wasm` + `withdraw_final.zkey`, `ownership.wasm` + `ownership_final.zkey` (BN254 curve).
|
|
29
29
|
|
|
30
|
+
## Agent Registry
|
|
31
|
+
|
|
32
|
+
On-chain registry for AI agents with identity, memory, and activity tracking:
|
|
33
|
+
|
|
34
|
+
- Register a unique agent ID (lowercase only, no uppercase letters allowed)
|
|
35
|
+
- Store agent **bio** and **metadata** (JSON) on-chain
|
|
36
|
+
- 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
|
|
38
|
+
- Memory modes: `new`, `update`, `append`, `auto` (auto-detects)
|
|
39
|
+
- Points system tracks agent activity, with referral rewards when paired with quest answers
|
|
40
|
+
|
|
30
41
|
## Skills Hub
|
|
31
42
|
|
|
32
43
|
On-chain skill registry for storing and managing AI agent skills:
|
|
33
44
|
|
|
34
|
-
- Skills are identified by a globally unique name (5–32 bytes)
|
|
45
|
+
- Skills are identified by a globally unique name (5–32 bytes, lowercase only, no uppercase letters allowed)
|
|
35
46
|
- Content is uploaded via a **chunked buffer mechanism** — large files are split into ~800-byte chunks across multiple transactions, with resumable writes
|
|
36
47
|
- Each skill tracks `version`, `authority`, `description`, `metadata` (JSON), and raw content bytes
|
|
37
48
|
- Only the skill's authority can modify or delete it
|
|
@@ -154,6 +165,55 @@ console.log(info?.depositCount, info?.commitmentStartIndex);
|
|
|
154
165
|
console.log(isValidRecipient(recipient.publicKey)); // true
|
|
155
166
|
```
|
|
156
167
|
|
|
168
|
+
### Agent Registry SDK
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
import {
|
|
172
|
+
registerAgent,
|
|
173
|
+
getAgentRecord,
|
|
174
|
+
getAgentInfo,
|
|
175
|
+
getAgentMemory,
|
|
176
|
+
setBio,
|
|
177
|
+
setMetadata,
|
|
178
|
+
uploadMemory,
|
|
179
|
+
logActivity,
|
|
180
|
+
deleteAgent,
|
|
181
|
+
Keypair,
|
|
182
|
+
} from "nara-sdk";
|
|
183
|
+
import { Connection } from "@solana/web3.js";
|
|
184
|
+
|
|
185
|
+
const connection = new Connection("https://mainnet-api.nara.build/", "confirmed");
|
|
186
|
+
const wallet = Keypair.fromSecretKey(/* your secret key */);
|
|
187
|
+
|
|
188
|
+
// 1. Register an agent (lowercase only, charges registration fee)
|
|
189
|
+
const { signature, agentPubkey } = await registerAgent(connection, wallet, "my-agent");
|
|
190
|
+
|
|
191
|
+
// 2. Set bio and metadata
|
|
192
|
+
await setBio(connection, wallet, "my-agent", "An AI assistant for code review.");
|
|
193
|
+
await setMetadata(connection, wallet, "my-agent", JSON.stringify({ model: "gpt-4" }));
|
|
194
|
+
|
|
195
|
+
// 3. Upload memory (auto-chunked, supports new/update/append modes)
|
|
196
|
+
const memory = Buffer.from(JSON.stringify({ facts: ["sky is blue"] }));
|
|
197
|
+
await uploadMemory(connection, wallet, "my-agent", memory, {
|
|
198
|
+
onProgress(chunk, total, sig) { console.log(`[${chunk}/${total}] ${sig}`); },
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
// 4. Read back memory
|
|
202
|
+
const bytes = await getAgentMemory(connection, "my-agent");
|
|
203
|
+
|
|
204
|
+
// 5. Append to existing memory
|
|
205
|
+
const extra = Buffer.from(JSON.stringify({ more: "data" }));
|
|
206
|
+
await uploadMemory(connection, wallet, "my-agent", extra, {}, "append");
|
|
207
|
+
|
|
208
|
+
// 6. Log activity (with optional referral agent)
|
|
209
|
+
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
|
+
|
|
212
|
+
// 7. Query agent info
|
|
213
|
+
const info = await getAgentInfo(connection, "my-agent");
|
|
214
|
+
console.log(info.record.agentId, info.record.points, info.bio);
|
|
215
|
+
```
|
|
216
|
+
|
|
157
217
|
### Skills SDK
|
|
158
218
|
|
|
159
219
|
```typescript
|
|
@@ -205,25 +265,32 @@ const bytes = await getSkillContent(connection, "my-skill");
|
|
|
205
265
|
|
|
206
266
|
## Environment Variables
|
|
207
267
|
|
|
208
|
-
| Variable
|
|
209
|
-
|
|
|
210
|
-
| `RPC_URL`
|
|
211
|
-
| `QUEST_RELAY_URL`
|
|
212
|
-
| `QUEST_PROGRAM_ID`
|
|
213
|
-
| `SKILLS_PROGRAM_ID` | `SkiLLHub11111111111111111111111111111111111`
|
|
214
|
-
| `ZKID_PROGRAM_ID`
|
|
268
|
+
| Variable | Default | Description |
|
|
269
|
+
| --- | --- | --- |
|
|
270
|
+
| `RPC_URL` | `https://mainnet-api.nara.build/` | Solana RPC endpoint |
|
|
271
|
+
| `QUEST_RELAY_URL` | `https://quest-api.nara.build/` | Gasless relay for quest submissions |
|
|
272
|
+
| `QUEST_PROGRAM_ID` | `Quest11111111111111111111111111111111111111` | Quest program address |
|
|
273
|
+
| `SKILLS_PROGRAM_ID` | `SkiLLHub11111111111111111111111111111111111` | Skills Hub program address |
|
|
274
|
+
| `ZKID_PROGRAM_ID` | `ZKidentity111111111111111111111111111111111` | ZK ID program address |
|
|
275
|
+
| `AGENT_REGISTRY_PROGRAM_ID` | `AgentRegistry111111111111111111111111111111` | Agent Registry program address |
|
|
215
276
|
|
|
216
277
|
## Examples
|
|
217
278
|
|
|
218
279
|
```bash
|
|
280
|
+
# Agent Registry example
|
|
281
|
+
PRIVATE_KEY=<base58> bun run examples/agent.ts
|
|
282
|
+
|
|
219
283
|
# Quest example
|
|
220
|
-
PRIVATE_KEY=<base58>
|
|
284
|
+
PRIVATE_KEY=<base58> bun run examples/quest.ts
|
|
285
|
+
|
|
286
|
+
# Quest with referral example
|
|
287
|
+
PRIVATE_KEY=<base58> bun run examples/quest_referral.ts
|
|
221
288
|
|
|
222
289
|
# Skills example
|
|
223
|
-
PRIVATE_KEY=<base58>
|
|
290
|
+
PRIVATE_KEY=<base58> bun run examples/skills.ts
|
|
224
291
|
|
|
225
292
|
# ZK ID example
|
|
226
|
-
PRIVATE_KEY=<base58>
|
|
293
|
+
PRIVATE_KEY=<base58> bun run examples/zkid.ts
|
|
227
294
|
```
|
|
228
295
|
|
|
229
296
|
## License
|
package/index.ts
CHANGED
|
@@ -67,6 +67,7 @@ export {
|
|
|
67
67
|
computeIdCommitment,
|
|
68
68
|
isValidRecipient,
|
|
69
69
|
generateValidRecipient,
|
|
70
|
+
getConfig as getZkIdConfig,
|
|
70
71
|
initializeConfig as initZkIdConfig,
|
|
71
72
|
updateConfig as updateZkIdConfig,
|
|
72
73
|
ZKID_DENOMINATIONS,
|
|
@@ -94,12 +95,23 @@ export {
|
|
|
94
95
|
updateAdmin,
|
|
95
96
|
updateFeeRecipient,
|
|
96
97
|
updateRegisterFee,
|
|
98
|
+
updatePointsConfig,
|
|
97
99
|
type AgentRecord,
|
|
98
100
|
type AgentInfo,
|
|
99
101
|
type MemoryMode,
|
|
100
102
|
type AgentRegistryOptions,
|
|
101
103
|
} from "./src/agent_registry";
|
|
102
104
|
|
|
105
|
+
// Export IDLs and types
|
|
106
|
+
export { default as NaraQuestIDL } from "./src/idls/nara_quest.json";
|
|
107
|
+
export { default as NaraSkillsHubIDL } from "./src/idls/nara_skills_hub.json";
|
|
108
|
+
export { default as NaraZkIDL } from "./src/idls/nara_zk.json";
|
|
109
|
+
export { default as NaraAgentRegistryIDL } from "./src/idls/nara_agent_registry.json";
|
|
110
|
+
export type { NaraQuest } from "./src/idls/nara_quest";
|
|
111
|
+
export type { NaraSkillsHub } from "./src/idls/nara_skills_hub";
|
|
112
|
+
export type { NaraZk } from "./src/idls/nara_zk";
|
|
113
|
+
export type { NaraAgentRegistry } from "./src/idls/nara_agent_registry";
|
|
114
|
+
|
|
103
115
|
// Re-export commonly used types from dependencies
|
|
104
116
|
export { PublicKey, Keypair, Transaction } from "@solana/web3.js";
|
|
105
117
|
export { default as BN } from "bn.js";
|
package/package.json
CHANGED
package/src/agent_registry.ts
CHANGED
|
@@ -265,19 +265,15 @@ export async function getAgentMemory(
|
|
|
265
265
|
agentId: string,
|
|
266
266
|
options?: AgentRegistryOptions
|
|
267
267
|
): Promise<Buffer | null> {
|
|
268
|
-
const
|
|
269
|
-
|
|
270
|
-
const raw = await program.account.agentRecord.fetch(agentPda);
|
|
271
|
-
const memoryPubkey = raw.memory as PublicKey;
|
|
272
|
-
|
|
273
|
-
if (memoryPubkey.equals(PublicKey.default)) {
|
|
268
|
+
const record = await getAgentRecord(connection, agentId, options);
|
|
269
|
+
if (record.memory.equals(PublicKey.default)) {
|
|
274
270
|
return null;
|
|
275
271
|
}
|
|
276
272
|
|
|
277
|
-
const accountInfo = await connection.getAccountInfo(
|
|
273
|
+
const accountInfo = await connection.getAccountInfo(record.memory);
|
|
278
274
|
if (!accountInfo) return null;
|
|
279
275
|
|
|
280
|
-
// Memory bytes start after the header (8 discriminator + 32 agent pubkey)
|
|
276
|
+
// Memory bytes start after the header (8 discriminator + 32 agent pubkey + 64 _reserved)
|
|
281
277
|
return Buffer.from(accountInfo.data.slice(MEMORY_HEADER_SIZE));
|
|
282
278
|
}
|
|
283
279
|
|
|
@@ -287,15 +283,27 @@ export async function getAgentMemory(
|
|
|
287
283
|
export async function getConfig(
|
|
288
284
|
connection: Connection,
|
|
289
285
|
options?: AgentRegistryOptions
|
|
290
|
-
): Promise<{
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
286
|
+
): Promise<{
|
|
287
|
+
admin: PublicKey;
|
|
288
|
+
registerFee: number;
|
|
289
|
+
feeRecipient: PublicKey;
|
|
290
|
+
pointsSelf: number;
|
|
291
|
+
pointsReferral: number;
|
|
292
|
+
}> {
|
|
293
|
+
const pid = new PublicKey(options?.programId ?? DEFAULT_AGENT_REGISTRY_PROGRAM_ID);
|
|
294
|
+
const configPda = getConfigPda(pid);
|
|
295
|
+
const accountInfo = await connection.getAccountInfo(configPda);
|
|
296
|
+
if (!accountInfo) {
|
|
297
|
+
throw new Error("Program config not initialized");
|
|
298
|
+
}
|
|
299
|
+
const buf = Buffer.from(accountInfo.data);
|
|
300
|
+
let offset = 8; // skip discriminator
|
|
301
|
+
const admin = new PublicKey(buf.subarray(offset, offset + 32)); offset += 32;
|
|
302
|
+
const feeRecipient = new PublicKey(buf.subarray(offset, offset + 32)); offset += 32;
|
|
303
|
+
const registerFee = Number(buf.readBigUInt64LE(offset)); offset += 8;
|
|
304
|
+
const pointsSelf = Number(buf.readBigUInt64LE(offset)); offset += 8;
|
|
305
|
+
const pointsReferral = Number(buf.readBigUInt64LE(offset));
|
|
306
|
+
return { admin, registerFee, feeRecipient, pointsSelf, pointsReferral };
|
|
299
307
|
}
|
|
300
308
|
|
|
301
309
|
// ─── Agent CRUD ─────────────────────────────────────────────────
|
|
@@ -309,6 +317,9 @@ export async function registerAgent(
|
|
|
309
317
|
agentId: string,
|
|
310
318
|
options?: AgentRegistryOptions
|
|
311
319
|
): Promise<{ signature: string; agentPubkey: PublicKey }> {
|
|
320
|
+
if (/[A-Z]/.test(agentId)) {
|
|
321
|
+
throw new Error(`Agent ID must not contain uppercase letters: "${agentId}"`);
|
|
322
|
+
}
|
|
312
323
|
const program = createProgram(connection, wallet, options?.programId);
|
|
313
324
|
const configPda = getConfigPda(program.programId);
|
|
314
325
|
const config = await program.account.programConfig.fetch(configPda);
|
|
@@ -355,14 +366,12 @@ export async function deleteAgent(
|
|
|
355
366
|
options?: AgentRegistryOptions
|
|
356
367
|
): Promise<string> {
|
|
357
368
|
const program = createProgram(connection, wallet, options?.programId);
|
|
358
|
-
const
|
|
359
|
-
const raw = await program.account.agentRecord.fetch(agentPda);
|
|
360
|
-
const memoryPubkey = raw.memory as PublicKey;
|
|
369
|
+
const record = await getAgentRecord(connection, agentId, options);
|
|
361
370
|
|
|
362
371
|
// When no memory exists, pass authority pubkey as placeholder
|
|
363
|
-
const memoryAccount =
|
|
372
|
+
const memoryAccount = record.memory.equals(PublicKey.default)
|
|
364
373
|
? wallet.publicKey
|
|
365
|
-
:
|
|
374
|
+
: record.memory;
|
|
366
375
|
|
|
367
376
|
return program.methods
|
|
368
377
|
.deleteAgent(agentId)
|
|
@@ -438,9 +447,8 @@ export async function uploadMemory(
|
|
|
438
447
|
const program = createProgram(connection, wallet, options?.programId);
|
|
439
448
|
const chunkSize = options?.chunkSize ?? DEFAULT_CHUNK_SIZE;
|
|
440
449
|
const totalLen = data.length;
|
|
441
|
-
const
|
|
442
|
-
const
|
|
443
|
-
const existingMemory = raw.memory as PublicKey;
|
|
450
|
+
const record = await getAgentRecord(connection, agentId, options);
|
|
451
|
+
const existingMemory = record.memory;
|
|
444
452
|
const hasMemory = !existingMemory.equals(PublicKey.default);
|
|
445
453
|
|
|
446
454
|
// Resolve mode
|
|
@@ -561,15 +569,13 @@ export async function closeBuffer(
|
|
|
561
569
|
options?: AgentRegistryOptions
|
|
562
570
|
): Promise<string> {
|
|
563
571
|
const program = createProgram(connection, wallet, options?.programId);
|
|
564
|
-
const
|
|
565
|
-
|
|
566
|
-
const bufferPubkey = raw.pendingBuffer as PublicKey;
|
|
567
|
-
if (bufferPubkey.equals(PublicKey.default)) {
|
|
572
|
+
const record = await getAgentRecord(connection, agentId, options);
|
|
573
|
+
if (!record.pendingBuffer) {
|
|
568
574
|
throw new Error(`Agent "${agentId}" has no pending buffer`);
|
|
569
575
|
}
|
|
570
576
|
return program.methods
|
|
571
577
|
.closeBuffer(agentId)
|
|
572
|
-
.accounts({ authority: wallet.publicKey, buffer:
|
|
578
|
+
.accounts({ authority: wallet.publicKey, buffer: record.pendingBuffer } as any)
|
|
573
579
|
.signers([wallet])
|
|
574
580
|
.rpc();
|
|
575
581
|
}
|
|
@@ -705,3 +711,24 @@ export async function updateRegisterFee(
|
|
|
705
711
|
.signers([wallet])
|
|
706
712
|
.rpc();
|
|
707
713
|
}
|
|
714
|
+
|
|
715
|
+
/**
|
|
716
|
+
* Update the points configuration (admin-only).
|
|
717
|
+
* Sets how many points are awarded per activity and per referral.
|
|
718
|
+
*/
|
|
719
|
+
export async function updatePointsConfig(
|
|
720
|
+
connection: Connection,
|
|
721
|
+
wallet: Keypair,
|
|
722
|
+
pointsSelf: number | anchor.BN,
|
|
723
|
+
pointsReferral: number | anchor.BN,
|
|
724
|
+
options?: AgentRegistryOptions
|
|
725
|
+
): Promise<string> {
|
|
726
|
+
const program = createProgram(connection, wallet, options?.programId);
|
|
727
|
+
const ps = typeof pointsSelf === "number" ? new anchor.BN(pointsSelf) : pointsSelf;
|
|
728
|
+
const pr = typeof pointsReferral === "number" ? new anchor.BN(pointsReferral) : pointsReferral;
|
|
729
|
+
return program.methods
|
|
730
|
+
.updatePointsConfig(ps, pr)
|
|
731
|
+
.accounts({ admin: wallet.publicKey } as any)
|
|
732
|
+
.signers([wallet])
|
|
733
|
+
.rpc();
|
|
734
|
+
}
|
|
@@ -504,6 +504,24 @@
|
|
|
504
504
|
]
|
|
505
505
|
}
|
|
506
506
|
},
|
|
507
|
+
{
|
|
508
|
+
"name": "config",
|
|
509
|
+
"pda": {
|
|
510
|
+
"seeds": [
|
|
511
|
+
{
|
|
512
|
+
"kind": "const",
|
|
513
|
+
"value": [
|
|
514
|
+
99,
|
|
515
|
+
111,
|
|
516
|
+
110,
|
|
517
|
+
102,
|
|
518
|
+
105,
|
|
519
|
+
103
|
|
520
|
+
]
|
|
521
|
+
}
|
|
522
|
+
]
|
|
523
|
+
}
|
|
524
|
+
},
|
|
507
525
|
{
|
|
508
526
|
"name": "referral_agent",
|
|
509
527
|
"docs": [
|
|
@@ -915,6 +933,57 @@
|
|
|
915
933
|
}
|
|
916
934
|
]
|
|
917
935
|
},
|
|
936
|
+
{
|
|
937
|
+
"name": "update_points_config",
|
|
938
|
+
"discriminator": [
|
|
939
|
+
15,
|
|
940
|
+
89,
|
|
941
|
+
27,
|
|
942
|
+
201,
|
|
943
|
+
127,
|
|
944
|
+
239,
|
|
945
|
+
187,
|
|
946
|
+
80
|
|
947
|
+
],
|
|
948
|
+
"accounts": [
|
|
949
|
+
{
|
|
950
|
+
"name": "admin",
|
|
951
|
+
"signer": true,
|
|
952
|
+
"relations": [
|
|
953
|
+
"config"
|
|
954
|
+
]
|
|
955
|
+
},
|
|
956
|
+
{
|
|
957
|
+
"name": "config",
|
|
958
|
+
"writable": true,
|
|
959
|
+
"pda": {
|
|
960
|
+
"seeds": [
|
|
961
|
+
{
|
|
962
|
+
"kind": "const",
|
|
963
|
+
"value": [
|
|
964
|
+
99,
|
|
965
|
+
111,
|
|
966
|
+
110,
|
|
967
|
+
102,
|
|
968
|
+
105,
|
|
969
|
+
103
|
|
970
|
+
]
|
|
971
|
+
}
|
|
972
|
+
]
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
],
|
|
976
|
+
"args": [
|
|
977
|
+
{
|
|
978
|
+
"name": "points_self",
|
|
979
|
+
"type": "u64"
|
|
980
|
+
},
|
|
981
|
+
{
|
|
982
|
+
"name": "points_referral",
|
|
983
|
+
"type": "u64"
|
|
984
|
+
}
|
|
985
|
+
]
|
|
986
|
+
},
|
|
918
987
|
{
|
|
919
988
|
"name": "update_register_fee",
|
|
920
989
|
"discriminator": [
|
|
@@ -1168,11 +1237,16 @@
|
|
|
1168
1237
|
},
|
|
1169
1238
|
{
|
|
1170
1239
|
"code": 6017,
|
|
1240
|
+
"name": "AgentIdNotLowercase",
|
|
1241
|
+
"msg": "Agent ID must be lowercase"
|
|
1242
|
+
},
|
|
1243
|
+
{
|
|
1244
|
+
"code": 6018,
|
|
1171
1245
|
"name": "QuestIxNotFound",
|
|
1172
1246
|
"msg": "No valid submit_answer instruction found in transaction"
|
|
1173
1247
|
},
|
|
1174
1248
|
{
|
|
1175
|
-
"code":
|
|
1249
|
+
"code": 6019,
|
|
1176
1250
|
"name": "ReferralNotFound",
|
|
1177
1251
|
"msg": "Referral agent not found"
|
|
1178
1252
|
}
|
|
@@ -1353,6 +1427,14 @@
|
|
|
1353
1427
|
"name": "register_fee",
|
|
1354
1428
|
"type": "u64"
|
|
1355
1429
|
},
|
|
1430
|
+
{
|
|
1431
|
+
"name": "points_self",
|
|
1432
|
+
"type": "u64"
|
|
1433
|
+
},
|
|
1434
|
+
{
|
|
1435
|
+
"name": "points_referral",
|
|
1436
|
+
"type": "u64"
|
|
1437
|
+
},
|
|
1356
1438
|
{
|
|
1357
1439
|
"name": "_reserved",
|
|
1358
1440
|
"type": {
|
|
@@ -510,6 +510,24 @@ export type NaraAgentRegistry = {
|
|
|
510
510
|
]
|
|
511
511
|
}
|
|
512
512
|
},
|
|
513
|
+
{
|
|
514
|
+
"name": "config",
|
|
515
|
+
"pda": {
|
|
516
|
+
"seeds": [
|
|
517
|
+
{
|
|
518
|
+
"kind": "const",
|
|
519
|
+
"value": [
|
|
520
|
+
99,
|
|
521
|
+
111,
|
|
522
|
+
110,
|
|
523
|
+
102,
|
|
524
|
+
105,
|
|
525
|
+
103
|
|
526
|
+
]
|
|
527
|
+
}
|
|
528
|
+
]
|
|
529
|
+
}
|
|
530
|
+
},
|
|
513
531
|
{
|
|
514
532
|
"name": "referralAgent",
|
|
515
533
|
"docs": [
|
|
@@ -921,6 +939,57 @@ export type NaraAgentRegistry = {
|
|
|
921
939
|
}
|
|
922
940
|
]
|
|
923
941
|
},
|
|
942
|
+
{
|
|
943
|
+
"name": "updatePointsConfig",
|
|
944
|
+
"discriminator": [
|
|
945
|
+
15,
|
|
946
|
+
89,
|
|
947
|
+
27,
|
|
948
|
+
201,
|
|
949
|
+
127,
|
|
950
|
+
239,
|
|
951
|
+
187,
|
|
952
|
+
80
|
|
953
|
+
],
|
|
954
|
+
"accounts": [
|
|
955
|
+
{
|
|
956
|
+
"name": "admin",
|
|
957
|
+
"signer": true,
|
|
958
|
+
"relations": [
|
|
959
|
+
"config"
|
|
960
|
+
]
|
|
961
|
+
},
|
|
962
|
+
{
|
|
963
|
+
"name": "config",
|
|
964
|
+
"writable": true,
|
|
965
|
+
"pda": {
|
|
966
|
+
"seeds": [
|
|
967
|
+
{
|
|
968
|
+
"kind": "const",
|
|
969
|
+
"value": [
|
|
970
|
+
99,
|
|
971
|
+
111,
|
|
972
|
+
110,
|
|
973
|
+
102,
|
|
974
|
+
105,
|
|
975
|
+
103
|
|
976
|
+
]
|
|
977
|
+
}
|
|
978
|
+
]
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
],
|
|
982
|
+
"args": [
|
|
983
|
+
{
|
|
984
|
+
"name": "pointsSelf",
|
|
985
|
+
"type": "u64"
|
|
986
|
+
},
|
|
987
|
+
{
|
|
988
|
+
"name": "pointsReferral",
|
|
989
|
+
"type": "u64"
|
|
990
|
+
}
|
|
991
|
+
]
|
|
992
|
+
},
|
|
924
993
|
{
|
|
925
994
|
"name": "updateRegisterFee",
|
|
926
995
|
"discriminator": [
|
|
@@ -1174,11 +1243,16 @@ export type NaraAgentRegistry = {
|
|
|
1174
1243
|
},
|
|
1175
1244
|
{
|
|
1176
1245
|
"code": 6017,
|
|
1246
|
+
"name": "agentIdNotLowercase",
|
|
1247
|
+
"msg": "Agent ID must be lowercase"
|
|
1248
|
+
},
|
|
1249
|
+
{
|
|
1250
|
+
"code": 6018,
|
|
1177
1251
|
"name": "questIxNotFound",
|
|
1178
1252
|
"msg": "No valid submit_answer instruction found in transaction"
|
|
1179
1253
|
},
|
|
1180
1254
|
{
|
|
1181
|
-
"code":
|
|
1255
|
+
"code": 6019,
|
|
1182
1256
|
"name": "referralNotFound",
|
|
1183
1257
|
"msg": "Referral agent not found"
|
|
1184
1258
|
}
|
|
@@ -1359,6 +1433,14 @@ export type NaraAgentRegistry = {
|
|
|
1359
1433
|
"name": "registerFee",
|
|
1360
1434
|
"type": "u64"
|
|
1361
1435
|
},
|
|
1436
|
+
{
|
|
1437
|
+
"name": "pointsSelf",
|
|
1438
|
+
"type": "u64"
|
|
1439
|
+
},
|
|
1440
|
+
{
|
|
1441
|
+
"name": "pointsReferral",
|
|
1442
|
+
"type": "u64"
|
|
1443
|
+
},
|
|
1362
1444
|
{
|
|
1363
1445
|
"name": "reserved",
|
|
1364
1446
|
"type": {
|
package/src/skills.ts
CHANGED
|
@@ -183,6 +183,9 @@ export async function registerSkill(
|
|
|
183
183
|
author: string,
|
|
184
184
|
options?: SkillOptions
|
|
185
185
|
): Promise<{ signature: string; skillPubkey: PublicKey }> {
|
|
186
|
+
if (/[A-Z]/.test(name)) {
|
|
187
|
+
throw new Error(`Skill name must not contain uppercase letters: "${name}"`);
|
|
188
|
+
}
|
|
186
189
|
const program = createProgram(connection, wallet, options?.programId);
|
|
187
190
|
const configPda = getConfigPda(program.programId);
|
|
188
191
|
const config = await program.account.programConfig.fetch(configPda);
|
package/src/zkid.ts
CHANGED
|
@@ -621,6 +621,30 @@ export async function transferZkIdByCommitment(
|
|
|
621
621
|
* Initialize the program configuration (one-time setup).
|
|
622
622
|
* The caller becomes the admin.
|
|
623
623
|
*/
|
|
624
|
+
/**
|
|
625
|
+
* Query the ZK ID program config (admin, fee recipient, fee amount).
|
|
626
|
+
*/
|
|
627
|
+
export async function getConfig(
|
|
628
|
+
connection: Connection,
|
|
629
|
+
options?: ZkIdOptions
|
|
630
|
+
): Promise<{ admin: PublicKey; feeRecipient: PublicKey; feeAmount: number }> {
|
|
631
|
+
const programId = new PublicKey(options?.programId ?? DEFAULT_ZKID_PROGRAM_ID);
|
|
632
|
+
const [configPda] = PublicKey.findProgramAddressSync(
|
|
633
|
+
[Buffer.from("config")],
|
|
634
|
+
programId
|
|
635
|
+
);
|
|
636
|
+
const accountInfo = await connection.getAccountInfo(configPda);
|
|
637
|
+
if (!accountInfo) {
|
|
638
|
+
throw new Error("ZK ID config account not found");
|
|
639
|
+
}
|
|
640
|
+
const buf = Buffer.from(accountInfo.data);
|
|
641
|
+
let offset = 8; // skip discriminator
|
|
642
|
+
const admin = new PublicKey(buf.subarray(offset, offset + 32)); offset += 32;
|
|
643
|
+
const feeRecipient = new PublicKey(buf.subarray(offset, offset + 32)); offset += 32;
|
|
644
|
+
const feeAmount = Number(buf.readBigUInt64LE(offset));
|
|
645
|
+
return { admin, feeRecipient, feeAmount };
|
|
646
|
+
}
|
|
647
|
+
|
|
624
648
|
export async function initializeConfig(
|
|
625
649
|
connection: Connection,
|
|
626
650
|
wallet: Keypair,
|