@obelyzk/sdk 1.4.0 → 1.6.0

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.
@@ -0,0 +1,566 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __commonJS = (cb, mod) => function __require() {
8
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
9
+ };
10
+ var __export = (target, all) => {
11
+ for (var name in all)
12
+ __defProp(target, name, { get: all[name], enumerable: true });
13
+ };
14
+ var __copyProps = (to, from, except, desc) => {
15
+ if (from && typeof from === "object" || typeof from === "function") {
16
+ for (let key of __getOwnPropNames(from))
17
+ if (!__hasOwnProp.call(to, key) && key !== except)
18
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
19
+ }
20
+ return to;
21
+ };
22
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
23
+ // If the importer is in node compatibility mode or this is not an ESM
24
+ // file that has been converted to a CommonJS file using a Babel-
25
+ // compatible transform (i.e. "__esModule" has not been set), then set
26
+ // "default" to the CommonJS "module.exports" for node compatibility.
27
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
28
+ mod
29
+ ));
30
+
31
+ // src/firewall/client.ts
32
+ import { RpcProvider, Contract, CallData } from "starknet";
33
+ var AgentFirewallSDK = class {
34
+ config;
35
+ provider;
36
+ constructor(config) {
37
+ this.config = config;
38
+ this.provider = new RpcProvider({ nodeUrl: config.rpcUrl });
39
+ }
40
+ // ── Classification ─────────────────────────────────────────────────
41
+ /**
42
+ * Classify a transaction through the ZKML classifier.
43
+ *
44
+ * Sends the transaction features to the prove-server, which runs
45
+ * the MLP classifier and generates a GKR+STARK proof. Returns the
46
+ * proven threat score and decision.
47
+ *
48
+ * Does NOT submit anything on-chain — use `evaluateAction()` for
49
+ * the full flow including on-chain submission.
50
+ */
51
+ async classify(tx) {
52
+ const headers = {
53
+ "Content-Type": "application/json"
54
+ };
55
+ if (this.config.apiKey) {
56
+ headers["Authorization"] = `Bearer ${this.config.apiKey}`;
57
+ }
58
+ const body = {
59
+ target: tx.target,
60
+ value: tx.value || "0",
61
+ selector: tx.selector || "0x0",
62
+ calldata: tx.calldata || "0x",
63
+ agent_trust_score: tx.agentTrustScore || 0,
64
+ agent_strikes: tx.agentStrikes || 0,
65
+ agent_age_blocks: tx.agentAgeBlocks || 0,
66
+ target_verified: tx.targetVerified || false,
67
+ target_is_proxy: tx.targetIsProxy || false,
68
+ target_has_source: tx.targetHasSource || false,
69
+ target_interaction_count: tx.targetInteractionCount || 0,
70
+ tx_frequency: tx.txFrequency || 0,
71
+ unique_targets_24h: tx.uniqueTargets24h || 0,
72
+ avg_value_24h: tx.avgValue24h || 0,
73
+ max_value_24h: tx.maxValue24h || 0
74
+ };
75
+ const response = await fetch(`${this.config.proverUrl}/api/v1/classify`, {
76
+ method: "POST",
77
+ headers,
78
+ body: JSON.stringify(body)
79
+ });
80
+ if (!response.ok) {
81
+ const error = await response.json().catch(() => ({ error: response.statusText }));
82
+ throw new Error(`Classification failed (${response.status}): ${error.error || response.statusText}`);
83
+ }
84
+ const data = await response.json();
85
+ return {
86
+ requestId: data.request_id,
87
+ decision: data.decision,
88
+ threatScore: data.threat_score,
89
+ scores: data.scores,
90
+ ioCommitment: data.io_commitment,
91
+ policyCommitment: data.policy_commitment,
92
+ proveTimeMs: data.prove_time_ms
93
+ };
94
+ }
95
+ // ── Agent Management ───────────────────────────────────────────────
96
+ /**
97
+ * Register a new agent on the firewall contract.
98
+ * The calling account becomes the agent owner.
99
+ */
100
+ async registerAgent(agentId) {
101
+ this.requireAccount();
102
+ const tx = await this.config.account.execute({
103
+ contractAddress: this.config.firewallContract,
104
+ entrypoint: "register_agent",
105
+ calldata: CallData.compile({ agent_id: agentId })
106
+ });
107
+ await this.provider.waitForTransaction(tx.transaction_hash);
108
+ return tx.transaction_hash;
109
+ }
110
+ /** Deactivate an agent (owner or contract admin). */
111
+ async deactivateAgent(agentId) {
112
+ this.requireAccount();
113
+ const tx = await this.config.account.execute({
114
+ contractAddress: this.config.firewallContract,
115
+ entrypoint: "deactivate_agent",
116
+ calldata: CallData.compile({ agent_id: agentId })
117
+ });
118
+ await this.provider.waitForTransaction(tx.transaction_hash);
119
+ return tx.transaction_hash;
120
+ }
121
+ /** Reactivate an agent and reset strikes (agent owner only). */
122
+ async reactivateAgent(agentId) {
123
+ this.requireAccount();
124
+ const tx = await this.config.account.execute({
125
+ contractAddress: this.config.firewallContract,
126
+ entrypoint: "reactivate_agent",
127
+ calldata: CallData.compile({ agent_id: agentId })
128
+ });
129
+ await this.provider.waitForTransaction(tx.transaction_hash);
130
+ return tx.transaction_hash;
131
+ }
132
+ // ── Queries ────────────────────────────────────────────────────────
133
+ /** Get the full status of an agent. */
134
+ async getAgentStatus(agentId) {
135
+ const contract = new Contract(
136
+ FIREWALL_ABI,
137
+ this.config.firewallContract,
138
+ this.provider
139
+ );
140
+ const [registered, active, trustScore, strikes, trusted] = await Promise.all([
141
+ contract.is_agent_registered(agentId),
142
+ contract.is_agent_active(agentId),
143
+ contract.get_trust_score(agentId),
144
+ contract.get_strikes(agentId),
145
+ contract.is_trusted(agentId)
146
+ ]);
147
+ return {
148
+ registered,
149
+ active,
150
+ trustScore: Number(trustScore),
151
+ strikes: Number(strikes),
152
+ trusted
153
+ };
154
+ }
155
+ /** Check if a specific action has been approved. */
156
+ async isActionApproved(actionId) {
157
+ const contract = new Contract(
158
+ FIREWALL_ABI,
159
+ this.config.firewallContract,
160
+ this.provider
161
+ );
162
+ return contract.is_action_approved(actionId);
163
+ }
164
+ /** Check if an agent is trusted. */
165
+ async isAgentTrusted(agentId) {
166
+ const contract = new Contract(
167
+ FIREWALL_ABI,
168
+ this.config.firewallContract,
169
+ this.provider
170
+ );
171
+ return contract.is_trusted(agentId);
172
+ }
173
+ /** Get the decision for an action (0=pending, 1=approved, 2=escalated, 3=blocked). */
174
+ async getActionDecision(actionId) {
175
+ const contract = new Contract(
176
+ FIREWALL_ABI,
177
+ this.config.firewallContract,
178
+ this.provider
179
+ );
180
+ return Number(await contract.get_action_decision(actionId));
181
+ }
182
+ /** Get the threat score for a resolved action. */
183
+ async getActionThreatScore(actionId) {
184
+ const contract = new Contract(
185
+ FIREWALL_ABI,
186
+ this.config.firewallContract,
187
+ this.provider
188
+ );
189
+ return Number(await contract.get_action_threat_score(actionId));
190
+ }
191
+ /** Get the IO commitment for an action. */
192
+ async getActionIoCommitment(actionId) {
193
+ const contract = new Contract(
194
+ FIREWALL_ABI,
195
+ this.config.firewallContract,
196
+ this.provider
197
+ );
198
+ const result = await contract.get_action_io_commitment(actionId);
199
+ return `0x${BigInt(result).toString(16)}`;
200
+ }
201
+ // ── On-Chain Actions ────────────────────────────────────────────────
202
+ /**
203
+ * Submit a pending action to the firewall contract.
204
+ * Returns the action_id assigned by the contract.
205
+ */
206
+ async submitAction(agentId, target, value, selector, ioCommitment) {
207
+ this.requireAccount();
208
+ const tx = await this.config.account.execute({
209
+ contractAddress: this.config.firewallContract,
210
+ entrypoint: "submit_action",
211
+ calldata: CallData.compile({
212
+ agent_id: agentId,
213
+ target,
214
+ value,
215
+ selector,
216
+ io_commitment: ioCommitment
217
+ })
218
+ });
219
+ const receipt = await this.provider.waitForTransaction(tx.transaction_hash);
220
+ let actionId = 0;
221
+ const events = receipt.events;
222
+ if (Array.isArray(events)) {
223
+ for (const event of events) {
224
+ if (event.data && event.data.length >= 2) {
225
+ const candidateId = Number(BigInt(event.data[0]));
226
+ if (candidateId > 0) {
227
+ actionId = candidateId;
228
+ break;
229
+ }
230
+ }
231
+ }
232
+ }
233
+ return { actionId, txHash: tx.transaction_hash };
234
+ }
235
+ /**
236
+ * Resolve a pending action with a verified ZKML proof.
237
+ * The proof must already be verified on the ObelyskVerifier contract.
238
+ */
239
+ async resolveAction(actionId, proofHash, originalIoLen, packedRawIo) {
240
+ this.requireAccount();
241
+ const tx = await this.config.account.execute({
242
+ contractAddress: this.config.firewallContract,
243
+ entrypoint: "resolve_action_with_proof",
244
+ calldata: CallData.compile({
245
+ action_id: actionId,
246
+ proof_hash: proofHash,
247
+ original_io_len: originalIoLen,
248
+ packed_raw_io: packedRawIo
249
+ })
250
+ });
251
+ const receipt = await this.provider.waitForTransaction(tx.transaction_hash);
252
+ let decision = "approve";
253
+ let threatScore = 0;
254
+ const resolveEvents = receipt.events;
255
+ if (Array.isArray(resolveEvents)) {
256
+ for (const event of resolveEvents) {
257
+ if (event.data && event.data.length >= 4) {
258
+ const decisionCode = Number(BigInt(event.data[2]));
259
+ threatScore = Number(BigInt(event.data[3]));
260
+ if (decisionCode === 1) decision = "approve";
261
+ else if (decisionCode === 2) decision = "escalate";
262
+ else if (decisionCode === 3) decision = "block";
263
+ break;
264
+ }
265
+ }
266
+ }
267
+ return { decision, threatScore, txHash: tx.transaction_hash };
268
+ }
269
+ /** Approve an escalated action (human-in-the-loop). */
270
+ async approveEscalated(actionId) {
271
+ this.requireAccount();
272
+ const tx = await this.config.account.execute({
273
+ contractAddress: this.config.firewallContract,
274
+ entrypoint: "approve_escalated",
275
+ calldata: CallData.compile({ action_id: actionId })
276
+ });
277
+ await this.provider.waitForTransaction(tx.transaction_hash);
278
+ return tx.transaction_hash;
279
+ }
280
+ /** Reject an escalated action and add a strike. */
281
+ async rejectEscalated(actionId) {
282
+ this.requireAccount();
283
+ const tx = await this.config.account.execute({
284
+ contractAddress: this.config.firewallContract,
285
+ entrypoint: "reject_escalated",
286
+ calldata: CallData.compile({ action_id: actionId })
287
+ });
288
+ await this.provider.waitForTransaction(tx.transaction_hash);
289
+ return tx.transaction_hash;
290
+ }
291
+ // ── Helpers ────────────────────────────────────────────────────────
292
+ requireAccount() {
293
+ if (!this.config.account) {
294
+ throw new Error(
295
+ "Account required for write operations. Pass `account` in FirewallConfig."
296
+ );
297
+ }
298
+ }
299
+ };
300
+ var FIREWALL_ABI = [
301
+ {
302
+ name: "is_agent_registered",
303
+ type: "function",
304
+ inputs: [{ name: "agent_id", type: "felt" }],
305
+ outputs: [{ type: "felt" }],
306
+ state_mutability: "view"
307
+ },
308
+ {
309
+ name: "is_agent_active",
310
+ type: "function",
311
+ inputs: [{ name: "agent_id", type: "felt" }],
312
+ outputs: [{ type: "felt" }],
313
+ state_mutability: "view"
314
+ },
315
+ {
316
+ name: "get_trust_score",
317
+ type: "function",
318
+ inputs: [{ name: "agent_id", type: "felt" }],
319
+ outputs: [{ type: "felt" }],
320
+ state_mutability: "view"
321
+ },
322
+ {
323
+ name: "get_strikes",
324
+ type: "function",
325
+ inputs: [{ name: "agent_id", type: "felt" }],
326
+ outputs: [{ type: "felt" }],
327
+ state_mutability: "view"
328
+ },
329
+ {
330
+ name: "is_trusted",
331
+ type: "function",
332
+ inputs: [{ name: "agent_id", type: "felt" }],
333
+ outputs: [{ type: "felt" }],
334
+ state_mutability: "view"
335
+ },
336
+ {
337
+ name: "is_action_approved",
338
+ type: "function",
339
+ inputs: [{ name: "action_id", type: "felt" }],
340
+ outputs: [{ type: "felt" }],
341
+ state_mutability: "view"
342
+ },
343
+ {
344
+ name: "get_action_decision",
345
+ type: "function",
346
+ inputs: [{ name: "action_id", type: "felt" }],
347
+ outputs: [{ type: "felt" }],
348
+ state_mutability: "view"
349
+ },
350
+ {
351
+ name: "get_action_threat_score",
352
+ type: "function",
353
+ inputs: [{ name: "action_id", type: "felt" }],
354
+ outputs: [{ type: "felt" }],
355
+ state_mutability: "view"
356
+ },
357
+ {
358
+ name: "get_action_io_commitment",
359
+ type: "function",
360
+ inputs: [{ name: "action_id", type: "felt" }],
361
+ outputs: [{ type: "felt" }],
362
+ state_mutability: "view"
363
+ },
364
+ {
365
+ name: "get_owner",
366
+ type: "function",
367
+ inputs: [],
368
+ outputs: [{ type: "felt" }],
369
+ state_mutability: "view"
370
+ },
371
+ {
372
+ name: "get_verifier",
373
+ type: "function",
374
+ inputs: [],
375
+ outputs: [{ type: "felt" }],
376
+ state_mutability: "view"
377
+ },
378
+ {
379
+ name: "get_classifier_model_id",
380
+ type: "function",
381
+ inputs: [],
382
+ outputs: [{ type: "felt" }],
383
+ state_mutability: "view"
384
+ },
385
+ {
386
+ name: "get_thresholds",
387
+ type: "function",
388
+ inputs: [],
389
+ outputs: [{ type: "felt" }, { type: "felt" }, { type: "felt" }],
390
+ state_mutability: "view"
391
+ },
392
+ {
393
+ name: "get_agent_owner",
394
+ type: "function",
395
+ inputs: [{ name: "agent_id", type: "felt" }],
396
+ outputs: [{ type: "felt" }],
397
+ state_mutability: "view"
398
+ },
399
+ {
400
+ name: "get_action_agent",
401
+ type: "function",
402
+ inputs: [{ name: "action_id", type: "felt" }],
403
+ outputs: [{ type: "felt" }],
404
+ state_mutability: "view"
405
+ },
406
+ {
407
+ name: "is_paused",
408
+ type: "function",
409
+ inputs: [],
410
+ outputs: [{ type: "felt" }],
411
+ state_mutability: "view"
412
+ }
413
+ ];
414
+
415
+ // src/firewall/ciro.ts
416
+ var CiroClient = class {
417
+ baseUrl;
418
+ apiKey;
419
+ org;
420
+ timeout;
421
+ constructor(config) {
422
+ this.baseUrl = config.baseUrl.replace(/\/+$/, "");
423
+ this.apiKey = config.apiKey;
424
+ this.org = config.org ?? "obelyzk";
425
+ this.timeout = config.timeout ?? 1e4;
426
+ }
427
+ get apiBase() {
428
+ return `${this.baseUrl}/api/singularity/${this.org}/blockchain`;
429
+ }
430
+ async request(method, path, body) {
431
+ const url = `${this.apiBase}${path}`;
432
+ const headers = {
433
+ Authorization: `Bearer ${this.apiKey}`,
434
+ "Content-Type": "application/json",
435
+ "X-Client": "obelyzk-sdk/1.0"
436
+ };
437
+ const controller = new AbortController();
438
+ const timer = setTimeout(() => controller.abort(), this.timeout);
439
+ try {
440
+ const response = await fetch(url, {
441
+ method,
442
+ headers,
443
+ body: body ? JSON.stringify(body) : void 0,
444
+ signal: controller.signal
445
+ });
446
+ if (!response.ok) {
447
+ const error = await response.json().catch(() => ({ error: response.statusText }));
448
+ throw new Error(
449
+ `CIRO API error (${response.status}): ${error.error || response.statusText}`
450
+ );
451
+ }
452
+ return await response.json();
453
+ } finally {
454
+ clearTimeout(timer);
455
+ }
456
+ }
457
+ /**
458
+ * Enrich a transaction with CIRO intelligence.
459
+ * Returns target risk, sanctions status, Forta alerts, and behavioral context.
460
+ */
461
+ async enrichTransaction(params) {
462
+ const raw = await this.request(
463
+ "POST",
464
+ "/transactions/enrich",
465
+ {
466
+ target: params.target,
467
+ sender: params.sender,
468
+ value: params.value ?? "0",
469
+ selector: params.selector ?? "0x0",
470
+ chain: "starknet"
471
+ }
472
+ );
473
+ return {
474
+ targetRisk: raw.target_risk ?? "unknown",
475
+ targetRiskScore: raw.target_risk_score ?? 0,
476
+ targetVerified: raw.target_verified ?? false,
477
+ targetIsProxy: raw.target_is_proxy ?? false,
478
+ targetHasSource: raw.target_has_source ?? false,
479
+ targetInteractionCount: raw.target_interaction_count ?? 0,
480
+ targetUniqueCallers: raw.target_unique_callers ?? 0,
481
+ targetFirstSeenBlocksAgo: raw.target_first_seen_blocks_ago ?? 0,
482
+ isSanctioned: raw.is_sanctioned ?? false,
483
+ sanctionLists: raw.sanction_lists ?? [],
484
+ fortaAlerts24h: raw.forta_alerts_24h ?? 0,
485
+ fortaSeverityMax: raw.forta_severity_max ?? null,
486
+ senderTxFrequency: raw.sender_tx_frequency ?? 0,
487
+ senderUniqueTargets24h: raw.sender_unique_targets_24h ?? 0,
488
+ senderAvgValue24h: raw.sender_avg_value_24h ?? 0,
489
+ senderMaxValue24h: raw.sender_max_value_24h ?? 0,
490
+ senderAgeBlocks: raw.sender_age_blocks ?? 0,
491
+ dataFreshnessS: raw.data_freshness_s ?? 0,
492
+ enrichmentTimeMs: raw.enrichment_time_ms ?? 0
493
+ };
494
+ }
495
+ /**
496
+ * Get risk assessment for a specific address.
497
+ */
498
+ async getAddressRisk(address) {
499
+ const raw = await this.request(
500
+ "GET",
501
+ `/addresses/${address}/risk`
502
+ );
503
+ return {
504
+ address: raw.address ?? address,
505
+ chain: raw.chain ?? "starknet",
506
+ riskLevel: raw.risk ?? "unknown",
507
+ riskScore: raw.risk_score ?? 0,
508
+ isContract: raw.is_contract ?? false,
509
+ isVerified: raw.is_verified ?? false,
510
+ isProxy: raw.is_proxy ?? false,
511
+ isSanctioned: raw.is_sanctioned ?? false,
512
+ sanctionLists: raw.sanction_lists ?? [],
513
+ fortaAlertsCount: raw.forta_alerts_count ?? 0,
514
+ knownExploitInvolvement: raw.known_exploit_involvement ?? false,
515
+ exploitNames: raw.exploit_names ?? [],
516
+ totalTxCount: raw.total_tx_count ?? 0,
517
+ clusterSize: raw.cluster_size ?? 0
518
+ };
519
+ }
520
+ /**
521
+ * Get recent alerts from CIRO's detection pipeline.
522
+ */
523
+ async getRecentAlerts(params) {
524
+ const query = new URLSearchParams();
525
+ if (params?.severity) query.set("severity", params.severity);
526
+ if (params?.limit) query.set("limit", String(params.limit));
527
+ const queryStr = query.toString();
528
+ const path = `/alerts/recent${queryStr ? `?${queryStr}` : ""}`;
529
+ const raw = await this.request("GET", path);
530
+ const alerts = raw.alerts ?? [];
531
+ return alerts.map((a) => ({
532
+ alertId: a.alert_id ?? "",
533
+ source: a.source ?? "",
534
+ severity: a.severity ?? "INFO",
535
+ chain: a.chain ?? "starknet",
536
+ timestamp: a.timestamp ?? "",
537
+ addresses: a.addresses ?? [],
538
+ txHash: a.tx_hash ?? null,
539
+ name: a.name ?? "",
540
+ description: a.description ?? ""
541
+ }));
542
+ }
543
+ /**
544
+ * Get data lake statistics.
545
+ */
546
+ async getStats() {
547
+ const raw = await this.request("GET", "/stats");
548
+ return {
549
+ totalTransactions: raw.total_transactions ?? 0,
550
+ labeledTransactions: raw.labeled_transactions ?? 0,
551
+ labelDistribution: raw.label_distribution ?? {},
552
+ lastUpdated: raw.last_updated ?? "",
553
+ fortaBotsActive: raw.forta_bots_active ?? 0,
554
+ addressesIndexed: raw.addresses_indexed ?? 0,
555
+ sanctionedAddresses: raw.sanctioned_addresses ?? 0
556
+ };
557
+ }
558
+ };
559
+
560
+ export {
561
+ __commonJS,
562
+ __export,
563
+ __toESM,
564
+ AgentFirewallSDK,
565
+ CiroClient
566
+ };
File without changes