clawntenna 0.9.0 → 0.10.1
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/dist/cli/index.js +227 -102
- package/dist/index.cjs +252 -103
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +52 -9
- package/dist/index.d.ts +52 -9
- package/dist/index.js +246 -102
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -21,7 +21,8 @@ var CHAINS = {
|
|
|
21
21
|
keyManager: "0x5562B553a876CBdc8AA4B3fb0687f22760F4759e",
|
|
22
22
|
schemaRegistry: "0xB7eB50e9058198b99b5b2589E6D70b2d99d5440a",
|
|
23
23
|
identityRegistry: "0x8004AA63c570c570eBF15376c0dB199918BFe9Fb",
|
|
24
|
-
escrow: "0x74e376C53f4afd5Cd32a77dDc627f477FcFC2333"
|
|
24
|
+
escrow: "0x74e376C53f4afd5Cd32a77dDc627f477FcFC2333",
|
|
25
|
+
defaultLookback: 2e5
|
|
25
26
|
},
|
|
26
27
|
base: {
|
|
27
28
|
chainId: 8453,
|
|
@@ -32,7 +33,9 @@ var CHAINS = {
|
|
|
32
33
|
registry: "0x5fF6BF04F1B5A78ae884D977a3C80A0D8E2072bF",
|
|
33
34
|
keyManager: "0xdc302ff43a34F6aEa19426D60C9D150e0661E4f4",
|
|
34
35
|
schemaRegistry: "0x5c11d2eA4470eD9025D810A21a885FE16dC987Bd",
|
|
35
|
-
identityRegistry: "0x8004A169FB4a3325136EB29fA0ceB6D2e539a432"
|
|
36
|
+
identityRegistry: "0x8004A169FB4a3325136EB29fA0ceB6D2e539a432",
|
|
37
|
+
escrow: "0x04eC9a25C942192834F447eC9192831B56Ae2D7D",
|
|
38
|
+
defaultLookback: 2e5
|
|
36
39
|
},
|
|
37
40
|
avalanche: {
|
|
38
41
|
chainId: 43114,
|
|
@@ -43,7 +46,9 @@ var CHAINS = {
|
|
|
43
46
|
registry: "0x3Ca2FF0bD1b3633513299EB5d3e2d63e058b0713",
|
|
44
47
|
keyManager: "0x5a5ea9D408FBA984fFf6e243Dcc71ff6E00C73E4",
|
|
45
48
|
schemaRegistry: "0x23D96e610E8E3DA5341a75B77F1BFF7EA9c3A62B",
|
|
46
|
-
identityRegistry: "0x8004A169FB4a3325136EB29fA0ceB6D2e539a432"
|
|
49
|
+
identityRegistry: "0x8004A169FB4a3325136EB29fA0ceB6D2e539a432",
|
|
50
|
+
escrow: "0x4068245c35a498Da4336aD1Ab0Fb71ef534bfd03",
|
|
51
|
+
defaultLookback: 5e5
|
|
47
52
|
}
|
|
48
53
|
};
|
|
49
54
|
|
|
@@ -3355,16 +3360,93 @@ function getDepositDeadline(depositedAt, timeout) {
|
|
|
3355
3360
|
return Number(depositedAt + timeout);
|
|
3356
3361
|
}
|
|
3357
3362
|
|
|
3363
|
+
// src/rpc-errors.ts
|
|
3364
|
+
function classifyRpcError(err, ctx) {
|
|
3365
|
+
const msg = err.message ?? "";
|
|
3366
|
+
if (msg.includes("BAD_DATA") || msg.includes("could not decode result data")) {
|
|
3367
|
+
return `${ctx.method} failed: contract may not be deployed on ${ctx.chainName}, or the RPC returned an empty response. Check that the correct chain and RPC URL are configured.`;
|
|
3368
|
+
}
|
|
3369
|
+
if (msg.includes("NETWORK_ERROR") || msg.includes("ECONNREFUSED") || msg.includes("fetch failed") || msg.includes("getaddrinfo")) {
|
|
3370
|
+
return `${ctx.method} failed: network error connecting to ${ctx.chainName} RPC. Check your RPC URL and network connectivity.`;
|
|
3371
|
+
}
|
|
3372
|
+
if (msg.includes("429") || msg.includes("rate limit") || msg.includes("too many requests") || msg.includes("exceeded") || msg.includes("throttl")) {
|
|
3373
|
+
return `${ctx.method} failed: RPC rate limit hit on ${ctx.chainName}. The request was retried but the limit persists. Try again later or use a different RPC endpoint.`;
|
|
3374
|
+
}
|
|
3375
|
+
return null;
|
|
3376
|
+
}
|
|
3377
|
+
|
|
3378
|
+
// src/retry.ts
|
|
3379
|
+
var DEFAULT_RETRY = {
|
|
3380
|
+
maxRetries: 3,
|
|
3381
|
+
baseDelayMs: 1e3,
|
|
3382
|
+
maxDelayMs: 1e4
|
|
3383
|
+
};
|
|
3384
|
+
var RETRYABLE_PATTERNS = [
|
|
3385
|
+
"429",
|
|
3386
|
+
"rate limit",
|
|
3387
|
+
"too many requests",
|
|
3388
|
+
"timeout",
|
|
3389
|
+
"econnreset",
|
|
3390
|
+
"502",
|
|
3391
|
+
"503",
|
|
3392
|
+
"504",
|
|
3393
|
+
"server error"
|
|
3394
|
+
];
|
|
3395
|
+
function isRetryableError(err) {
|
|
3396
|
+
const msg = (err.message ?? "").toLowerCase();
|
|
3397
|
+
return RETRYABLE_PATTERNS.some((p) => msg.includes(p));
|
|
3398
|
+
}
|
|
3399
|
+
async function withRetry(fn, options) {
|
|
3400
|
+
const opts = { ...DEFAULT_RETRY, ...options };
|
|
3401
|
+
let lastError;
|
|
3402
|
+
for (let attempt = 0; attempt <= opts.maxRetries; attempt++) {
|
|
3403
|
+
try {
|
|
3404
|
+
return await fn();
|
|
3405
|
+
} catch (err) {
|
|
3406
|
+
lastError = err;
|
|
3407
|
+
if (attempt === opts.maxRetries) break;
|
|
3408
|
+
if (!(err instanceof Error) || !isRetryableError(err)) break;
|
|
3409
|
+
const delay = Math.min(opts.baseDelayMs * 2 ** attempt, opts.maxDelayMs);
|
|
3410
|
+
const jitter = Math.random() * 0.25 * delay;
|
|
3411
|
+
await new Promise((r) => setTimeout(r, delay + jitter));
|
|
3412
|
+
}
|
|
3413
|
+
}
|
|
3414
|
+
throw lastError;
|
|
3415
|
+
}
|
|
3416
|
+
|
|
3358
3417
|
// src/client.ts
|
|
3359
3418
|
var Clawntenna = class _Clawntenna {
|
|
3360
3419
|
provider;
|
|
3361
|
-
wallet;
|
|
3362
|
-
registry;
|
|
3363
|
-
keyManager;
|
|
3364
|
-
schemaRegistry;
|
|
3365
|
-
identityRegistry;
|
|
3366
|
-
escrow;
|
|
3367
3420
|
chainName;
|
|
3421
|
+
_signer;
|
|
3422
|
+
_address;
|
|
3423
|
+
_registry;
|
|
3424
|
+
_keyManager;
|
|
3425
|
+
_schemaRegistry;
|
|
3426
|
+
_identityRegistry;
|
|
3427
|
+
_escrow;
|
|
3428
|
+
/** @deprecated Use `signer` instead. */
|
|
3429
|
+
get wallet() {
|
|
3430
|
+
return this._signer;
|
|
3431
|
+
}
|
|
3432
|
+
get signer() {
|
|
3433
|
+
return this._signer;
|
|
3434
|
+
}
|
|
3435
|
+
get registry() {
|
|
3436
|
+
return this._registry;
|
|
3437
|
+
}
|
|
3438
|
+
get keyManager() {
|
|
3439
|
+
return this._keyManager;
|
|
3440
|
+
}
|
|
3441
|
+
get schemaRegistry() {
|
|
3442
|
+
return this._schemaRegistry;
|
|
3443
|
+
}
|
|
3444
|
+
get identityRegistry() {
|
|
3445
|
+
return this._identityRegistry;
|
|
3446
|
+
}
|
|
3447
|
+
get escrow() {
|
|
3448
|
+
return this._escrow;
|
|
3449
|
+
}
|
|
3368
3450
|
// In-memory ECDH state
|
|
3369
3451
|
ecdhPrivateKey = null;
|
|
3370
3452
|
ecdhPublicKey = null;
|
|
@@ -3383,25 +3465,59 @@ var Clawntenna = class _Clawntenna {
|
|
|
3383
3465
|
const keyManagerAddr = options.keyManagerAddress ?? chain.keyManager;
|
|
3384
3466
|
const schemaRegistryAddr = options.schemaRegistryAddress ?? chain.schemaRegistry;
|
|
3385
3467
|
const escrowAddr = options.escrowAddress ?? chain.escrow;
|
|
3386
|
-
const
|
|
3468
|
+
const wallet = options.privateKey ? new ethers.Wallet(options.privateKey, this.provider) : null;
|
|
3469
|
+
const signer = wallet ? new ethers.NonceManager(wallet) : null;
|
|
3387
3470
|
const runner = signer ?? this.provider;
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3471
|
+
this._signer = signer;
|
|
3472
|
+
this._address = wallet?.address ?? null;
|
|
3473
|
+
this._registry = new ethers.Contract(registryAddr, REGISTRY_ABI, runner);
|
|
3474
|
+
this._keyManager = new ethers.Contract(keyManagerAddr, KEY_MANAGER_ABI, runner);
|
|
3475
|
+
this._schemaRegistry = new ethers.Contract(schemaRegistryAddr, SCHEMA_REGISTRY_ABI, runner);
|
|
3476
|
+
this._identityRegistry = chain.identityRegistry ? new ethers.Contract(chain.identityRegistry, IDENTITY_REGISTRY_ABI, runner) : null;
|
|
3477
|
+
this._escrow = escrowAddr ? new ethers.Contract(escrowAddr, ESCROW_ABI, runner) : null;
|
|
3478
|
+
}
|
|
3479
|
+
/**
|
|
3480
|
+
* Connect an external signer (e.g. from BrowserProvider).
|
|
3481
|
+
* Reconnects all contract instances to the new signer.
|
|
3482
|
+
*/
|
|
3483
|
+
async connectSigner(signer) {
|
|
3484
|
+
this._address = await signer.getAddress();
|
|
3485
|
+
this._signer = signer;
|
|
3486
|
+
this._registry = this._registry.connect(signer);
|
|
3487
|
+
this._keyManager = this._keyManager.connect(signer);
|
|
3488
|
+
this._schemaRegistry = this._schemaRegistry.connect(signer);
|
|
3489
|
+
if (this._identityRegistry) {
|
|
3490
|
+
this._identityRegistry = this._identityRegistry.connect(signer);
|
|
3491
|
+
}
|
|
3492
|
+
if (this._escrow) {
|
|
3493
|
+
this._escrow = this._escrow.connect(signer);
|
|
3494
|
+
}
|
|
3495
|
+
}
|
|
3496
|
+
requireSigner() {
|
|
3497
|
+
if (!this._signer) {
|
|
3498
|
+
throw new Error("Signer required. Pass privateKey in constructor or call connectSigner().");
|
|
3499
|
+
}
|
|
3500
|
+
return this._signer;
|
|
3501
|
+
}
|
|
3502
|
+
requireAddress() {
|
|
3503
|
+
if (!this._address) {
|
|
3504
|
+
throw new Error("Signer required. Pass privateKey in constructor or call connectSigner().");
|
|
3505
|
+
}
|
|
3506
|
+
return this._address;
|
|
3507
|
+
}
|
|
3508
|
+
async _wrapRpcError(fn, method) {
|
|
3509
|
+
try {
|
|
3510
|
+
return await withRetry(fn);
|
|
3511
|
+
} catch (err) {
|
|
3512
|
+
if (err instanceof Error) {
|
|
3513
|
+
const hint = classifyRpcError(err, { method, chainName: this.chainName });
|
|
3514
|
+
if (hint) throw new Error(hint, { cause: err });
|
|
3515
|
+
}
|
|
3516
|
+
throw err;
|
|
3400
3517
|
}
|
|
3401
|
-
this.escrow = escrowAddr ? new ethers.Contract(escrowAddr, ESCROW_ABI, runner) : null;
|
|
3402
3518
|
}
|
|
3403
3519
|
get address() {
|
|
3404
|
-
return this.
|
|
3520
|
+
return this._address;
|
|
3405
3521
|
}
|
|
3406
3522
|
// ===== MESSAGING =====
|
|
3407
3523
|
/**
|
|
@@ -3409,7 +3525,7 @@ var Clawntenna = class _Clawntenna {
|
|
|
3409
3525
|
* Automatically determines encryption key based on topic access level.
|
|
3410
3526
|
*/
|
|
3411
3527
|
async sendMessage(topicId, text, options) {
|
|
3412
|
-
|
|
3528
|
+
this.requireSigner();
|
|
3413
3529
|
if (options?.replyTo && this.escrow && !options?.skipRefundCheck) {
|
|
3414
3530
|
const refunded = await this.isMessageRefunded(options.replyTo);
|
|
3415
3531
|
if (refunded) {
|
|
@@ -3447,13 +3563,17 @@ var Clawntenna = class _Clawntenna {
|
|
|
3447
3563
|
const filter = this.registry.filters.MessageSent(topicId);
|
|
3448
3564
|
const CHUNK_SIZE = 2e3;
|
|
3449
3565
|
const currentBlock = await this.provider.getBlockNumber();
|
|
3450
|
-
const
|
|
3566
|
+
const chain = CHAINS[this.chainName];
|
|
3567
|
+
const maxRange = options?.fromBlock != null ? currentBlock - options.fromBlock : chain.defaultLookback;
|
|
3451
3568
|
const startBlock = currentBlock - maxRange;
|
|
3452
3569
|
const allEvents = [];
|
|
3453
3570
|
let toBlock = currentBlock;
|
|
3454
3571
|
while (toBlock > startBlock && allEvents.length < limit) {
|
|
3455
3572
|
const chunkFrom = Math.max(toBlock - CHUNK_SIZE + 1, startBlock);
|
|
3456
|
-
const events = await this.
|
|
3573
|
+
const events = await this._wrapRpcError(
|
|
3574
|
+
() => this.registry.queryFilter(filter, chunkFrom, toBlock),
|
|
3575
|
+
"readMessages"
|
|
3576
|
+
);
|
|
3457
3577
|
allEvents.unshift(...events);
|
|
3458
3578
|
toBlock = chunkFrom - 1;
|
|
3459
3579
|
}
|
|
@@ -3463,12 +3583,12 @@ var Clawntenna = class _Clawntenna {
|
|
|
3463
3583
|
const payloadStr = ethers.toUtf8String(log.args.payload);
|
|
3464
3584
|
const parsed = decryptMessage(payloadStr, key);
|
|
3465
3585
|
messages.push({
|
|
3466
|
-
topicId
|
|
3586
|
+
topicId,
|
|
3467
3587
|
sender: log.args.sender,
|
|
3468
3588
|
text: parsed?.text ?? "[decryption failed]",
|
|
3469
3589
|
replyTo: parsed?.replyTo ?? null,
|
|
3470
3590
|
mentions: parsed?.mentions ?? null,
|
|
3471
|
-
timestamp: log.args.timestamp,
|
|
3591
|
+
timestamp: Number(log.args.timestamp),
|
|
3472
3592
|
txHash: log.transactionHash,
|
|
3473
3593
|
blockNumber: log.blockNumber
|
|
3474
3594
|
});
|
|
@@ -3489,12 +3609,12 @@ var Clawntenna = class _Clawntenna {
|
|
|
3489
3609
|
const payloadStr = ethers.toUtf8String(payload);
|
|
3490
3610
|
const parsed = decryptMessage(payloadStr, key);
|
|
3491
3611
|
callback({
|
|
3492
|
-
topicId: tId,
|
|
3612
|
+
topicId: Number(tId),
|
|
3493
3613
|
sender,
|
|
3494
3614
|
text: parsed?.text ?? "[decryption failed]",
|
|
3495
3615
|
replyTo: parsed?.replyTo ?? null,
|
|
3496
3616
|
mentions: parsed?.mentions ?? null,
|
|
3497
|
-
timestamp,
|
|
3617
|
+
timestamp: Number(timestamp),
|
|
3498
3618
|
txHash: event.transactionHash,
|
|
3499
3619
|
blockNumber: event.blockNumber
|
|
3500
3620
|
});
|
|
@@ -3506,7 +3626,7 @@ var Clawntenna = class _Clawntenna {
|
|
|
3506
3626
|
}
|
|
3507
3627
|
// ===== NICKNAMES =====
|
|
3508
3628
|
async setNickname(appId, nickname) {
|
|
3509
|
-
|
|
3629
|
+
this.requireSigner();
|
|
3510
3630
|
return this.registry.setNickname(appId, nickname);
|
|
3511
3631
|
}
|
|
3512
3632
|
async getNickname(appId, address) {
|
|
@@ -3520,11 +3640,11 @@ var Clawntenna = class _Clawntenna {
|
|
|
3520
3640
|
return { canChange, timeRemaining };
|
|
3521
3641
|
}
|
|
3522
3642
|
async clearNickname(appId) {
|
|
3523
|
-
|
|
3643
|
+
this.requireSigner();
|
|
3524
3644
|
return this.registry.clearNickname(appId);
|
|
3525
3645
|
}
|
|
3526
3646
|
async setNicknameCooldown(appId, cooldownSeconds) {
|
|
3527
|
-
|
|
3647
|
+
this.requireSigner();
|
|
3528
3648
|
return this.registry.setNicknameCooldown(appId, cooldownSeconds);
|
|
3529
3649
|
}
|
|
3530
3650
|
async getNicknameCooldown(appId) {
|
|
@@ -3532,24 +3652,26 @@ var Clawntenna = class _Clawntenna {
|
|
|
3532
3652
|
}
|
|
3533
3653
|
// ===== TOPICS =====
|
|
3534
3654
|
async createTopic(appId, name, description, accessLevel) {
|
|
3535
|
-
|
|
3655
|
+
this.requireSigner();
|
|
3536
3656
|
return this.registry.createTopic(appId, name, description, accessLevel);
|
|
3537
3657
|
}
|
|
3538
3658
|
async getTopic(topicId) {
|
|
3539
|
-
|
|
3540
|
-
|
|
3541
|
-
|
|
3542
|
-
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
|
|
3659
|
+
return this._wrapRpcError(async () => {
|
|
3660
|
+
const t = await this.registry.getTopic(topicId);
|
|
3661
|
+
return {
|
|
3662
|
+
id: t.id,
|
|
3663
|
+
applicationId: t.applicationId,
|
|
3664
|
+
name: t.name,
|
|
3665
|
+
description: t.description,
|
|
3666
|
+
owner: t.owner,
|
|
3667
|
+
creator: t.creator,
|
|
3668
|
+
createdAt: t.createdAt,
|
|
3669
|
+
lastMessageAt: t.lastMessageAt,
|
|
3670
|
+
messageCount: t.messageCount,
|
|
3671
|
+
accessLevel: Number(t.accessLevel),
|
|
3672
|
+
active: t.active
|
|
3673
|
+
};
|
|
3674
|
+
}, "getTopic");
|
|
3553
3675
|
}
|
|
3554
3676
|
async getApplicationTopics(appId) {
|
|
3555
3677
|
return this.registry.getApplicationTopics(appId);
|
|
@@ -3559,7 +3681,7 @@ var Clawntenna = class _Clawntenna {
|
|
|
3559
3681
|
return Number(count);
|
|
3560
3682
|
}
|
|
3561
3683
|
async setTopicPermission(topicId, user, permission) {
|
|
3562
|
-
|
|
3684
|
+
this.requireSigner();
|
|
3563
3685
|
return this.registry.setTopicPermission(topicId, user, permission);
|
|
3564
3686
|
}
|
|
3565
3687
|
async getTopicPermission(topicId, user) {
|
|
@@ -3568,15 +3690,15 @@ var Clawntenna = class _Clawntenna {
|
|
|
3568
3690
|
}
|
|
3569
3691
|
// ===== MEMBERS =====
|
|
3570
3692
|
async addMember(appId, address, nickname, roles) {
|
|
3571
|
-
|
|
3693
|
+
this.requireSigner();
|
|
3572
3694
|
return this.registry.addMember(appId, address, nickname, roles);
|
|
3573
3695
|
}
|
|
3574
3696
|
async removeMember(appId, address) {
|
|
3575
|
-
|
|
3697
|
+
this.requireSigner();
|
|
3576
3698
|
return this.registry.removeMember(appId, address);
|
|
3577
3699
|
}
|
|
3578
3700
|
async updateMemberRoles(appId, address, roles) {
|
|
3579
|
-
|
|
3701
|
+
this.requireSigner();
|
|
3580
3702
|
return this.registry.updateMemberRoles(appId, address, roles);
|
|
3581
3703
|
}
|
|
3582
3704
|
async getMember(appId, address) {
|
|
@@ -3603,7 +3725,7 @@ var Clawntenna = class _Clawntenna {
|
|
|
3603
3725
|
}
|
|
3604
3726
|
// ===== APPLICATIONS =====
|
|
3605
3727
|
async createApplication(name, description, frontendUrl, allowPublicTopicCreation) {
|
|
3606
|
-
|
|
3728
|
+
this.requireSigner();
|
|
3607
3729
|
return this.registry.createApplication(name, description, frontendUrl, allowPublicTopicCreation);
|
|
3608
3730
|
}
|
|
3609
3731
|
async getApplicationCount() {
|
|
@@ -3611,25 +3733,27 @@ var Clawntenna = class _Clawntenna {
|
|
|
3611
3733
|
return Number(count);
|
|
3612
3734
|
}
|
|
3613
3735
|
async updateFrontendUrl(appId, frontendUrl) {
|
|
3614
|
-
|
|
3736
|
+
this.requireSigner();
|
|
3615
3737
|
return this.registry.updateApplicationFrontendUrl(appId, frontendUrl);
|
|
3616
3738
|
}
|
|
3617
3739
|
async getApplication(appId) {
|
|
3618
|
-
|
|
3619
|
-
|
|
3620
|
-
|
|
3621
|
-
|
|
3622
|
-
|
|
3623
|
-
|
|
3624
|
-
|
|
3625
|
-
|
|
3626
|
-
|
|
3627
|
-
|
|
3628
|
-
|
|
3629
|
-
|
|
3630
|
-
|
|
3631
|
-
|
|
3632
|
-
|
|
3740
|
+
return this._wrapRpcError(async () => {
|
|
3741
|
+
const a = await this.registry.getApplication(appId);
|
|
3742
|
+
return {
|
|
3743
|
+
id: a.id,
|
|
3744
|
+
name: a.name,
|
|
3745
|
+
description: a.description,
|
|
3746
|
+
frontendUrl: a.frontendUrl,
|
|
3747
|
+
owner: a.owner,
|
|
3748
|
+
createdAt: a.createdAt,
|
|
3749
|
+
memberCount: Number(a.memberCount),
|
|
3750
|
+
topicCount: Number(a.topicCount),
|
|
3751
|
+
active: a.active,
|
|
3752
|
+
allowPublicTopicCreation: a.allowPublicTopicCreation,
|
|
3753
|
+
topicCreationFeeToken: a.topicCreationFeeToken,
|
|
3754
|
+
topicCreationFeeAmount: a.topicCreationFeeAmount
|
|
3755
|
+
};
|
|
3756
|
+
}, "getApplication");
|
|
3633
3757
|
}
|
|
3634
3758
|
// ===== FEES =====
|
|
3635
3759
|
async getTopicMessageFee(topicId) {
|
|
@@ -3644,7 +3768,7 @@ var Clawntenna = class _Clawntenna {
|
|
|
3644
3768
|
* (e.g. '0.15' or 0.15 with USDC → 150000n, '0.01' with native ETH → 10000000000000000n)
|
|
3645
3769
|
*/
|
|
3646
3770
|
async setTopicCreationFee(appId, feeToken, feeAmount) {
|
|
3647
|
-
|
|
3771
|
+
this.requireSigner();
|
|
3648
3772
|
const rawAmount = typeof feeAmount === "bigint" ? feeAmount : await this.parseTokenAmount(feeToken, feeAmount);
|
|
3649
3773
|
return this.registry.setTopicCreationFee(appId, feeToken, rawAmount);
|
|
3650
3774
|
}
|
|
@@ -3656,7 +3780,7 @@ var Clawntenna = class _Clawntenna {
|
|
|
3656
3780
|
* (e.g. '0.15' or 0.15 with USDC → 150000n, '0.01' with native ETH → 10000000000000000n)
|
|
3657
3781
|
*/
|
|
3658
3782
|
async setTopicMessageFee(topicId, feeToken, feeAmount) {
|
|
3659
|
-
|
|
3783
|
+
this.requireSigner();
|
|
3660
3784
|
const rawAmount = typeof feeAmount === "bigint" ? feeAmount : await this.parseTokenAmount(feeToken, feeAmount);
|
|
3661
3785
|
return this.registry.setTopicMessageFee(topicId, feeToken, rawAmount);
|
|
3662
3786
|
}
|
|
@@ -3712,14 +3836,14 @@ var Clawntenna = class _Clawntenna {
|
|
|
3712
3836
|
* Enable escrow for a topic (topic owner only).
|
|
3713
3837
|
*/
|
|
3714
3838
|
async enableEscrow(topicId, timeout) {
|
|
3715
|
-
|
|
3839
|
+
this.requireSigner();
|
|
3716
3840
|
return this.requireEscrow().enableEscrow(topicId, timeout);
|
|
3717
3841
|
}
|
|
3718
3842
|
/**
|
|
3719
3843
|
* Disable escrow for a topic (topic owner only).
|
|
3720
3844
|
*/
|
|
3721
3845
|
async disableEscrow(topicId) {
|
|
3722
|
-
|
|
3846
|
+
this.requireSigner();
|
|
3723
3847
|
return this.requireEscrow().disableEscrow(topicId);
|
|
3724
3848
|
}
|
|
3725
3849
|
/**
|
|
@@ -3780,14 +3904,14 @@ var Clawntenna = class _Clawntenna {
|
|
|
3780
3904
|
* Claim a refund for a single deposit.
|
|
3781
3905
|
*/
|
|
3782
3906
|
async claimRefund(depositId) {
|
|
3783
|
-
|
|
3907
|
+
this.requireSigner();
|
|
3784
3908
|
return this.requireEscrow().claimRefund(depositId);
|
|
3785
3909
|
}
|
|
3786
3910
|
/**
|
|
3787
3911
|
* Batch claim refunds for multiple deposits.
|
|
3788
3912
|
*/
|
|
3789
3913
|
async batchClaimRefunds(depositIds) {
|
|
3790
|
-
|
|
3914
|
+
this.requireSigner();
|
|
3791
3915
|
return this.requireEscrow().batchClaimRefunds(depositIds);
|
|
3792
3916
|
}
|
|
3793
3917
|
/**
|
|
@@ -3852,10 +3976,11 @@ var Clawntenna = class _Clawntenna {
|
|
|
3852
3976
|
* Requires a signer capable of signing messages.
|
|
3853
3977
|
*/
|
|
3854
3978
|
async deriveECDHFromWallet(appId = 1) {
|
|
3855
|
-
|
|
3979
|
+
this.requireSigner();
|
|
3980
|
+
const signer = this._signer;
|
|
3856
3981
|
const { privateKey, publicKey } = await deriveKeypairFromSignature(
|
|
3857
|
-
this.
|
|
3858
|
-
(msg) =>
|
|
3982
|
+
this.requireAddress(),
|
|
3983
|
+
(msg) => signer.signMessage(msg),
|
|
3859
3984
|
appId
|
|
3860
3985
|
);
|
|
3861
3986
|
this.ecdhPrivateKey = privateKey;
|
|
@@ -3874,9 +3999,9 @@ var Clawntenna = class _Clawntenna {
|
|
|
3874
3999
|
* Register ECDH public key on-chain.
|
|
3875
4000
|
*/
|
|
3876
4001
|
async registerPublicKey() {
|
|
3877
|
-
|
|
4002
|
+
this.requireSigner();
|
|
3878
4003
|
if (!this.ecdhPublicKey) throw new Error("ECDH key not derived yet");
|
|
3879
|
-
const hasKey = await this.keyManager.hasPublicKey(this.
|
|
4004
|
+
const hasKey = await this.keyManager.hasPublicKey(this.requireAddress());
|
|
3880
4005
|
if (hasKey) {
|
|
3881
4006
|
throw new Error("Public key already registered on-chain");
|
|
3882
4007
|
}
|
|
@@ -3903,13 +4028,13 @@ var Clawntenna = class _Clawntenna {
|
|
|
3903
4028
|
* Returns the generated topic key.
|
|
3904
4029
|
*/
|
|
3905
4030
|
async initializeTopicKey(topicId) {
|
|
3906
|
-
|
|
4031
|
+
this.requireSigner();
|
|
3907
4032
|
if (!this.ecdhPrivateKey || !this.ecdhPublicKey) {
|
|
3908
4033
|
throw new Error("ECDH key not derived yet");
|
|
3909
4034
|
}
|
|
3910
4035
|
const topicKey = randomBytes(32);
|
|
3911
4036
|
const encrypted = encryptTopicKeyForUser(topicKey, this.ecdhPrivateKey, this.ecdhPublicKey);
|
|
3912
|
-
const tx = await this.keyManager.grantKeyAccess(topicId, this.
|
|
4037
|
+
const tx = await this.keyManager.grantKeyAccess(topicId, this.requireAddress(), encrypted);
|
|
3913
4038
|
await tx.wait();
|
|
3914
4039
|
this.topicKeys.set(topicId, topicKey);
|
|
3915
4040
|
return topicKey;
|
|
@@ -3926,9 +4051,9 @@ var Clawntenna = class _Clawntenna {
|
|
|
3926
4051
|
const isNoGrant = err instanceof Error && err.message.includes("No key grant found");
|
|
3927
4052
|
if (!isNoGrant) throw err;
|
|
3928
4053
|
const topic = await this.getTopic(topicId);
|
|
3929
|
-
if (!this.
|
|
4054
|
+
if (!this._signer || topic.owner.toLowerCase() !== this._address.toLowerCase()) {
|
|
3930
4055
|
throw new Error(
|
|
3931
|
-
`No key grant found for topic ${topicId}. Ask the topic owner to grant you access with: keys grant ${topicId} ${this.
|
|
4056
|
+
`No key grant found for topic ${topicId}. Ask the topic owner to grant you access with: keys grant ${topicId} ${this._address ?? "<your-address>"}`
|
|
3932
4057
|
);
|
|
3933
4058
|
}
|
|
3934
4059
|
return this.initializeTopicKey(topicId);
|
|
@@ -3938,7 +4063,7 @@ var Clawntenna = class _Clawntenna {
|
|
|
3938
4063
|
* Grant a user access to a private topic's symmetric key.
|
|
3939
4064
|
*/
|
|
3940
4065
|
async grantKeyAccess(topicId, userAddress, topicKey) {
|
|
3941
|
-
|
|
4066
|
+
this.requireSigner();
|
|
3942
4067
|
if (!this.ecdhPrivateKey) throw new Error("ECDH key not derived yet");
|
|
3943
4068
|
const hasKey = await this.keyManager.hasPublicKey(userAddress);
|
|
3944
4069
|
if (!hasKey) {
|
|
@@ -4023,7 +4148,7 @@ var Clawntenna = class _Clawntenna {
|
|
|
4023
4148
|
* Batch grant key access to multiple users at once (max 50).
|
|
4024
4149
|
*/
|
|
4025
4150
|
async batchGrantKeyAccess(topicId, users, topicKey) {
|
|
4026
|
-
|
|
4151
|
+
this.requireSigner();
|
|
4027
4152
|
if (!this.ecdhPrivateKey) throw new Error("ECDH key not derived yet");
|
|
4028
4153
|
const encryptedKeys = [];
|
|
4029
4154
|
for (const user of users) {
|
|
@@ -4037,14 +4162,14 @@ var Clawntenna = class _Clawntenna {
|
|
|
4037
4162
|
* Revoke a user's key access for a topic.
|
|
4038
4163
|
*/
|
|
4039
4164
|
async revokeKeyAccess(topicId, address) {
|
|
4040
|
-
|
|
4165
|
+
this.requireSigner();
|
|
4041
4166
|
return this.keyManager.revokeKeyAccess(topicId, address);
|
|
4042
4167
|
}
|
|
4043
4168
|
/**
|
|
4044
4169
|
* Rotate the key version for a topic. Existing grants become stale.
|
|
4045
4170
|
*/
|
|
4046
4171
|
async rotateKey(topicId) {
|
|
4047
|
-
|
|
4172
|
+
this.requireSigner();
|
|
4048
4173
|
return this.keyManager.rotateKey(topicId);
|
|
4049
4174
|
}
|
|
4050
4175
|
// ===== SCHEMAS =====
|
|
@@ -4052,21 +4177,21 @@ var Clawntenna = class _Clawntenna {
|
|
|
4052
4177
|
* Create a schema scoped to an application. Requires app admin role.
|
|
4053
4178
|
*/
|
|
4054
4179
|
async createAppSchema(appId, name, description, body) {
|
|
4055
|
-
|
|
4180
|
+
this.requireSigner();
|
|
4056
4181
|
return this.schemaRegistry.createAppSchema(appId, name, description, body);
|
|
4057
4182
|
}
|
|
4058
4183
|
/**
|
|
4059
4184
|
* Publish a new version of an existing schema.
|
|
4060
4185
|
*/
|
|
4061
4186
|
async publishSchemaVersion(schemaId, body) {
|
|
4062
|
-
|
|
4187
|
+
this.requireSigner();
|
|
4063
4188
|
return this.schemaRegistry.publishSchemaVersion(schemaId, body);
|
|
4064
4189
|
}
|
|
4065
4190
|
/**
|
|
4066
4191
|
* Deactivate a schema.
|
|
4067
4192
|
*/
|
|
4068
4193
|
async deactivateSchema(schemaId) {
|
|
4069
|
-
|
|
4194
|
+
this.requireSigner();
|
|
4070
4195
|
return this.schemaRegistry.deactivateSchema(schemaId);
|
|
4071
4196
|
}
|
|
4072
4197
|
/**
|
|
@@ -4118,14 +4243,14 @@ var Clawntenna = class _Clawntenna {
|
|
|
4118
4243
|
* Bind a schema version to a topic. Requires topic admin.
|
|
4119
4244
|
*/
|
|
4120
4245
|
async setTopicSchema(topicId, schemaId, version) {
|
|
4121
|
-
|
|
4246
|
+
this.requireSigner();
|
|
4122
4247
|
return this.schemaRegistry.setTopicSchema(topicId, schemaId, version);
|
|
4123
4248
|
}
|
|
4124
4249
|
/**
|
|
4125
4250
|
* Remove schema binding from a topic.
|
|
4126
4251
|
*/
|
|
4127
4252
|
async clearTopicSchema(topicId) {
|
|
4128
|
-
|
|
4253
|
+
this.requireSigner();
|
|
4129
4254
|
return this.schemaRegistry.clearTopicSchema(topicId);
|
|
4130
4255
|
}
|
|
4131
4256
|
// ===== AGENT IDENTITY (V5) =====
|
|
@@ -4134,14 +4259,14 @@ var Clawntenna = class _Clawntenna {
|
|
|
4134
4259
|
* Verifies ownership via ownerOf on the identity registry.
|
|
4135
4260
|
*/
|
|
4136
4261
|
async registerAgentIdentity(appId, tokenId) {
|
|
4137
|
-
|
|
4262
|
+
this.requireSigner();
|
|
4138
4263
|
return this.registry.registerAgentIdentity(appId, tokenId);
|
|
4139
4264
|
}
|
|
4140
4265
|
/**
|
|
4141
4266
|
* Clear your agent identity registration for an application (V5).
|
|
4142
4267
|
*/
|
|
4143
4268
|
async clearAgentIdentity(appId) {
|
|
4144
|
-
|
|
4269
|
+
this.requireSigner();
|
|
4145
4270
|
return this.registry.clearAgentIdentity(appId);
|
|
4146
4271
|
}
|
|
4147
4272
|
/**
|
|
@@ -4170,7 +4295,7 @@ var Clawntenna = class _Clawntenna {
|
|
|
4170
4295
|
* Optionally provide a URI for the agent's metadata.
|
|
4171
4296
|
*/
|
|
4172
4297
|
async registerAgent(agentURI) {
|
|
4173
|
-
|
|
4298
|
+
this.requireSigner();
|
|
4174
4299
|
const registry = this.requireIdentityRegistry();
|
|
4175
4300
|
const tx = agentURI ? await registry["register(string)"](agentURI) : await registry["register()"]();
|
|
4176
4301
|
const receipt = await tx.wait();
|
|
@@ -4193,7 +4318,7 @@ var Clawntenna = class _Clawntenna {
|
|
|
4193
4318
|
* Register as an agent with metadata entries.
|
|
4194
4319
|
*/
|
|
4195
4320
|
async registerAgentWithMetadata(agentURI, metadata) {
|
|
4196
|
-
|
|
4321
|
+
this.requireSigner();
|
|
4197
4322
|
const registry = this.requireIdentityRegistry();
|
|
4198
4323
|
const tx = await registry["register(string,(string,bytes)[])"](agentURI, metadata);
|
|
4199
4324
|
const receipt = await tx.wait();
|
|
@@ -4218,7 +4343,7 @@ var Clawntenna = class _Clawntenna {
|
|
|
4218
4343
|
*/
|
|
4219
4344
|
async isRegisteredAgent(address) {
|
|
4220
4345
|
const registry = this.requireIdentityRegistry();
|
|
4221
|
-
const addr = address ?? this.
|
|
4346
|
+
const addr = address ?? this._address;
|
|
4222
4347
|
if (!addr) throw new Error("Address required");
|
|
4223
4348
|
const balance = await registry.balanceOf(addr);
|
|
4224
4349
|
return balance > 0n;
|
|
@@ -4239,7 +4364,7 @@ var Clawntenna = class _Clawntenna {
|
|
|
4239
4364
|
* Set metadata for an agent.
|
|
4240
4365
|
*/
|
|
4241
4366
|
async setAgentMetadata(agentId, key, value) {
|
|
4242
|
-
|
|
4367
|
+
this.requireSigner();
|
|
4243
4368
|
const registry = this.requireIdentityRegistry();
|
|
4244
4369
|
return registry.setMetadata(agentId, key, value);
|
|
4245
4370
|
}
|
|
@@ -4255,7 +4380,7 @@ var Clawntenna = class _Clawntenna {
|
|
|
4255
4380
|
* Update the URI for an agent registration.
|
|
4256
4381
|
*/
|
|
4257
4382
|
async setAgentURI(agentId, newURI) {
|
|
4258
|
-
|
|
4383
|
+
this.requireSigner();
|
|
4259
4384
|
const registry = this.requireIdentityRegistry();
|
|
4260
4385
|
return registry.setAgentURI(agentId, newURI);
|
|
4261
4386
|
}
|
|
@@ -5594,7 +5719,7 @@ function decodeContractError(err) {
|
|
|
5594
5719
|
}
|
|
5595
5720
|
|
|
5596
5721
|
// src/cli/index.ts
|
|
5597
|
-
var VERSION = "0.
|
|
5722
|
+
var VERSION = "0.10.1";
|
|
5598
5723
|
var HELP = `
|
|
5599
5724
|
clawntenna v${VERSION}
|
|
5600
5725
|
On-chain encrypted messaging for AI agents
|