agent0-sdk 1.0.3 → 1.1.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.
Files changed (53) hide show
  1. package/README.md +28 -6
  2. package/dist/browser/eip6963.d.ts +60 -0
  3. package/dist/browser/eip6963.d.ts.map +1 -0
  4. package/dist/browser/eip6963.js +87 -0
  5. package/dist/browser/eip6963.js.map +1 -0
  6. package/dist/browser/index.d.ts +2 -0
  7. package/dist/browser/index.d.ts.map +1 -0
  8. package/dist/browser/index.js +2 -0
  9. package/dist/browser/index.js.map +1 -0
  10. package/dist/browser/viem-chain-client.d.ts +2 -0
  11. package/dist/browser/viem-chain-client.d.ts.map +1 -0
  12. package/dist/browser/viem-chain-client.js +2 -0
  13. package/dist/browser/viem-chain-client.js.map +1 -0
  14. package/dist/core/agent.d.ts +5 -2
  15. package/dist/core/agent.d.ts.map +1 -1
  16. package/dist/core/agent.js +204 -125
  17. package/dist/core/agent.js.map +1 -1
  18. package/dist/core/chain-client.d.ts +129 -0
  19. package/dist/core/chain-client.d.ts.map +1 -0
  20. package/dist/core/chain-client.js +2 -0
  21. package/dist/core/chain-client.js.map +1 -0
  22. package/dist/core/feedback-manager.d.ts +7 -8
  23. package/dist/core/feedback-manager.d.ts.map +1 -1
  24. package/dist/core/feedback-manager.js +107 -60
  25. package/dist/core/feedback-manager.js.map +1 -1
  26. package/dist/core/indexer.d.ts +1 -3
  27. package/dist/core/indexer.d.ts.map +1 -1
  28. package/dist/core/indexer.js +1 -2
  29. package/dist/core/indexer.js.map +1 -1
  30. package/dist/core/sdk.d.ts +19 -20
  31. package/dist/core/sdk.d.ts.map +1 -1
  32. package/dist/core/sdk.js +61 -69
  33. package/dist/core/sdk.js.map +1 -1
  34. package/dist/core/subgraph-client.d.ts +30 -2
  35. package/dist/core/subgraph-client.d.ts.map +1 -1
  36. package/dist/core/subgraph-client.js.map +1 -1
  37. package/dist/core/viem-chain-client.d.ts +78 -0
  38. package/dist/core/viem-chain-client.d.ts.map +1 -0
  39. package/dist/core/viem-chain-client.js +255 -0
  40. package/dist/core/viem-chain-client.js.map +1 -0
  41. package/dist/index.d.ts +2 -2
  42. package/dist/index.d.ts.map +1 -1
  43. package/dist/index.js +1 -1
  44. package/dist/index.js.map +1 -1
  45. package/dist/utils/index.d.ts +1 -0
  46. package/dist/utils/index.d.ts.map +1 -1
  47. package/dist/utils/index.js +1 -0
  48. package/dist/utils/index.js.map +1 -1
  49. package/dist/utils/signatures.d.ts +22 -0
  50. package/dist/utils/signatures.d.ts.map +1 -0
  51. package/dist/utils/signatures.js +40 -0
  52. package/dist/utils/signatures.js.map +1 -0
  53. package/package.json +14 -4
@@ -1,12 +1,15 @@
1
1
  /**
2
2
  * Agent class for managing individual agents
3
3
  */
4
- import { ethers } from 'ethers';
4
+ import { decodeEventLog, getAddress, hashDomain } from 'viem';
5
+ import { privateKeyToAccount } from 'viem/accounts';
5
6
  import { EndpointType, TrustModel } from '../models/enums.js';
6
7
  import { EndpointCrawler } from './endpoint-crawler.js';
7
8
  import { parseAgentId } from '../utils/id-format.js';
8
9
  import { TIMEOUTS } from '../utils/constants.js';
9
10
  import { validateSkill, validateDomain } from './oasf-validator.js';
11
+ import { IDENTITY_REGISTRY_ABI } from './contracts.js';
12
+ import { normalizeEcdsaSignature, recoverTypedDataSigner } from '../utils/signatures.js';
10
13
  /**
11
14
  * Agent class for managing individual agents
12
15
  */
@@ -291,18 +294,23 @@ export class Agent {
291
294
  throw new Error('Agent must be registered before setting agentWallet on-chain. ' +
292
295
  'Register the agent first, then call setAgentWallet().');
293
296
  }
294
- if (!this.sdk.web3Client.signer) {
295
- throw new Error('No SDK signer available to submit setAgentWallet transaction');
297
+ if (this.sdk.isReadOnly) {
298
+ throw new Error('No signer configured to submit setAgentWallet transaction');
296
299
  }
297
300
  // Validate newWallet address
298
- if (!this.sdk.web3Client.isAddress(newWallet)) {
301
+ if (!this.sdk.chainClient.isAddress(newWallet)) {
299
302
  throw new Error(`Invalid newWallet address: ${newWallet}`);
300
303
  }
301
304
  const { tokenId } = parseAgentId(this.registrationFile.agentId);
302
- const identityRegistry = this.sdk.getIdentityRegistry();
305
+ const identityRegistryAddress = this.sdk.identityRegistryAddress();
303
306
  // Optional short-circuit if already set
304
307
  try {
305
- const currentWallet = await this.sdk.web3Client.callContract(identityRegistry, 'getAgentWallet', BigInt(tokenId));
308
+ const currentWallet = await this.sdk.chainClient.readContract({
309
+ address: identityRegistryAddress,
310
+ abi: IDENTITY_REGISTRY_ABI,
311
+ functionName: 'getAgentWallet',
312
+ args: [BigInt(tokenId)],
313
+ });
306
314
  if (typeof currentWallet === 'string' &&
307
315
  currentWallet.toLowerCase() === newWallet.toLowerCase()) {
308
316
  const chainId = await this.sdk.chainId();
@@ -317,8 +325,7 @@ export class Agent {
317
325
  }
318
326
  // Deadline: contract enforces a short window. Use chain time (latest block timestamp)
319
327
  // rather than local system time to avoid clock skew causing reverts.
320
- const latestBlock = await this.sdk.web3Client.provider.getBlock('latest');
321
- const chainNow = latestBlock?.timestamp ?? Math.floor(Date.now() / 1000);
328
+ const chainNow = Number(await this.sdk.chainClient.getBlockTimestamp('latest'));
322
329
  const deadlineValue = opts?.deadline ?? chainNow + 60;
323
330
  if (deadlineValue < chainNow) {
324
331
  throw new Error(`Invalid deadline: ${deadlineValue} is in the past (chain time: ${chainNow})`);
@@ -329,16 +336,25 @@ export class Agent {
329
336
  `(chain time: ${chainNow})`);
330
337
  }
331
338
  const chainId = await this.sdk.chainId();
332
- const verifyingContract = await identityRegistry.getAddress();
333
- const owner = await this.sdk.web3Client.callContract(identityRegistry, 'ownerOf', BigInt(tokenId));
339
+ const verifyingContract = identityRegistryAddress;
340
+ const owner = await this.sdk.chainClient.readContract({
341
+ address: identityRegistryAddress,
342
+ abi: IDENTITY_REGISTRY_ABI,
343
+ functionName: 'ownerOf',
344
+ args: [BigInt(tokenId)],
345
+ });
334
346
  // Prefer reading the actual EIP-712 domain from the contract (if supported)
335
347
  // to avoid any future divergence in name/version.
336
348
  let domainName;
337
349
  let domainVersion;
338
350
  try {
339
- const domainInfo = await this.sdk.web3Client.callContract(identityRegistry, 'eip712Domain');
351
+ const domainInfo = await this.sdk.chainClient.readContract({
352
+ address: identityRegistryAddress,
353
+ abi: IDENTITY_REGISTRY_ABI,
354
+ functionName: 'eip712Domain',
355
+ args: [],
356
+ });
340
357
  // eip712Domain() returns: (fields, name, version, chainId, verifyingContract, salt, extensions)
341
- // In ethers v6 this is typically a Result array-like object.
342
358
  domainName = domainInfo?.name ?? domainInfo?.[1];
343
359
  domainVersion = domainInfo?.version ?? domainInfo?.[2];
344
360
  }
@@ -349,50 +365,41 @@ export class Agent {
349
365
  // deterministically from common candidates.
350
366
  let domainSeparatorOnChain;
351
367
  try {
352
- domainSeparatorOnChain = await this.sdk.web3Client.callContract(identityRegistry, 'DOMAIN_SEPARATOR');
368
+ domainSeparatorOnChain = await this.sdk.chainClient.readContract({
369
+ address: identityRegistryAddress,
370
+ abi: IDENTITY_REGISTRY_ABI,
371
+ functionName: 'DOMAIN_SEPARATOR',
372
+ args: [],
373
+ });
353
374
  }
354
375
  catch {
355
376
  // ignore
356
377
  }
357
- // Preflight estimateGas to catch signature/domain/type mismatches early.
358
- const estimateSetAgentWallet = async (sig) => {
359
- const fn = identityRegistry.getFunction
360
- ? identityRegistry.getFunction('setAgentWallet')
361
- : null;
362
- if (fn?.estimateGas) {
363
- await fn.estimateGas(BigInt(tokenId), newWallet, BigInt(deadlineValue), sig);
364
- }
365
- else if (identityRegistry.estimateGas?.setAgentWallet) {
366
- await identityRegistry.estimateGas.setAgentWallet(BigInt(tokenId), newWallet, BigInt(deadlineValue), sig);
367
- }
368
- };
369
378
  // Determine signature
370
379
  let signature;
371
380
  if (opts?.signature) {
372
- signature =
373
- typeof opts.signature === 'string' ? opts.signature : ethers.hexlify(opts.signature);
374
- if (!signature.startsWith('0x')) {
375
- signature = `0x${signature}`;
376
- }
381
+ const sig = typeof opts.signature === 'string'
382
+ ? (opts.signature.startsWith('0x') ? opts.signature : `0x${opts.signature}`)
383
+ : (() => {
384
+ let hex = '0x';
385
+ for (const b of opts.signature) {
386
+ hex += b.toString(16).padStart(2, '0');
387
+ }
388
+ return hex;
389
+ })();
390
+ signature = normalizeEcdsaSignature(sig);
377
391
  }
378
392
  else {
379
393
  // The new wallet MUST sign (EOA path). Support a few domain/type variants to match deployed registries.
380
- const signerForNewWallet = opts?.newWalletSigner;
381
- const sdkSignerAddress = await this.sdk.web3Client.getAddress();
394
+ const sdkSignerAddress = await this.sdk.chainClient.getAddress();
382
395
  // If no explicit signer was provided, allow the one-wallet case (SDK signer == newWallet)
383
- if (!signerForNewWallet) {
396
+ if (!opts?.newWalletPrivateKey) {
384
397
  if (!sdkSignerAddress || sdkSignerAddress.toLowerCase() !== newWallet.toLowerCase()) {
385
398
  throw new Error(`The new wallet must sign the EIP-712 message. ` +
386
- `Pass opts.newWalletSigner (private key or Signer) or opts.signature. ` +
399
+ `Pass opts.newWalletPrivateKey or opts.signature. ` +
387
400
  `SDK signer is ${sdkSignerAddress || 'unknown'}, newWallet is ${newWallet}.`);
388
401
  }
389
402
  }
390
- else {
391
- const signerAddress = await this.sdk.web3Client.addressOf(signerForNewWallet);
392
- if (signerAddress.toLowerCase() !== newWallet.toLowerCase()) {
393
- throw new Error(`newWalletSigner address (${signerAddress}) does not match newWallet (${newWallet}).`);
394
- }
395
- }
396
403
  const domainNames = [];
397
404
  if (domainName)
398
405
  domainNames.push(domainName);
@@ -403,11 +410,11 @@ export class Agent {
403
410
  if (domainSeparatorOnChain) {
404
411
  const match = domainNames.flatMap((dn) => domainVersions.map((dv) => ({ dn, dv }))).find(({ dn, dv }) => {
405
412
  try {
406
- const computed = ethers.TypedDataEncoder.hashDomain({
413
+ const computed = hashDomain({
407
414
  name: dn,
408
415
  version: dv,
409
416
  chainId,
410
- verifyingContract,
417
+ verifyingContract: verifyingContract,
411
418
  });
412
419
  return computed.toLowerCase() === String(domainSeparatorOnChain).toLowerCase();
413
420
  }
@@ -424,55 +431,87 @@ export class Agent {
424
431
  const variants = [];
425
432
  for (const dn of domainNames) {
426
433
  for (const dv of domainVersions) {
427
- variants.push(this.sdk.web3Client.buildAgentWalletSetTypedData({
428
- agentId: BigInt(tokenId),
429
- newWallet,
430
- owner,
431
- deadline: BigInt(deadlineValue),
432
- chainId,
433
- verifyingContract,
434
- domainName: dn,
435
- domainVersion: dv,
436
- }));
437
- variants.push(this.sdk.web3Client.buildAgentWalletSetTypedDataNoOwner({
438
- agentId: BigInt(tokenId),
439
- newWallet,
440
- deadline: BigInt(deadlineValue),
434
+ const domain = {
435
+ name: dn,
436
+ version: dv,
441
437
  chainId,
442
438
  verifyingContract,
443
- domainName: dn,
444
- domainVersion: dv,
445
- }));
439
+ };
440
+ variants.push({
441
+ domain,
442
+ primaryType: 'AgentWalletSet',
443
+ types: {
444
+ AgentWalletSet: [
445
+ { name: 'agentId', type: 'uint256' },
446
+ { name: 'newWallet', type: 'address' },
447
+ { name: 'owner', type: 'address' },
448
+ { name: 'deadline', type: 'uint256' },
449
+ ],
450
+ },
451
+ message: {
452
+ agentId: BigInt(tokenId),
453
+ newWallet,
454
+ owner,
455
+ deadline: BigInt(deadlineValue),
456
+ },
457
+ });
458
+ variants.push({
459
+ domain,
460
+ primaryType: 'AgentWalletSet',
461
+ types: {
462
+ AgentWalletSet: [
463
+ { name: 'agentId', type: 'uint256' },
464
+ { name: 'newWallet', type: 'address' },
465
+ { name: 'deadline', type: 'uint256' },
466
+ ],
467
+ },
468
+ message: {
469
+ agentId: BigInt(tokenId),
470
+ newWallet,
471
+ deadline: BigInt(deadlineValue),
472
+ },
473
+ });
446
474
  }
447
475
  }
448
476
  let lastError;
449
- const trySignAndEstimate = async (signerMode) => {
450
- for (const v of variants) {
451
- try {
452
- const sig = signerMode === 'newWallet'
453
- ? signerForNewWallet
454
- ? await this.sdk.web3Client.signTypedDataWith(signerForNewWallet, v.domain, v.types, v.message)
455
- : await this.sdk.web3Client.signTypedData(v.domain, v.types, v.message)
456
- : await this.sdk.web3Client.signTypedData(v.domain, v.types, v.message);
457
- const recovered = this.sdk.web3Client.recoverTypedDataSigner(v.domain, v.types, v.message, sig);
458
- const expected = signerMode === 'newWallet' ? newWallet.toLowerCase() : (sdkSignerAddress || '').toLowerCase();
459
- if (!expected || recovered.toLowerCase() !== expected) {
460
- throw new Error(`EIP-712 signature recovery mismatch (${signerMode} signing): recovered ${recovered} but expected ${expected || 'unknown'}`);
461
- }
462
- await estimateSetAgentWallet(sig);
463
- signature = sig;
464
- return;
477
+ for (const v of variants) {
478
+ try {
479
+ let sig;
480
+ if (opts?.newWalletPrivateKey) {
481
+ const acc = privateKeyToAccount((opts.newWalletPrivateKey.startsWith('0x')
482
+ ? opts.newWalletPrivateKey
483
+ : `0x${opts.newWalletPrivateKey}`));
484
+ sig = normalizeEcdsaSignature((await acc.signTypedData({
485
+ domain: v.domain,
486
+ types: v.types,
487
+ primaryType: v.primaryType,
488
+ message: v.message,
489
+ })));
465
490
  }
466
- catch (e) {
467
- lastError = e;
491
+ else {
492
+ sig = await this.sdk.chainClient.signTypedData({
493
+ domain: v.domain,
494
+ types: v.types,
495
+ primaryType: v.primaryType,
496
+ message: v.message,
497
+ });
468
498
  }
499
+ const recovered = await recoverTypedDataSigner({
500
+ domain: v.domain,
501
+ types: v.types,
502
+ primaryType: v.primaryType,
503
+ message: v.message,
504
+ signature: sig,
505
+ });
506
+ if (recovered.toLowerCase() !== getAddress(newWallet).toLowerCase()) {
507
+ throw new Error(`EIP-712 recovery mismatch: recovered ${recovered}, expected ${newWallet}`);
508
+ }
509
+ signature = sig;
510
+ break;
511
+ }
512
+ catch (e) {
513
+ lastError = e;
469
514
  }
470
- };
471
- // Preferred: newWallet signs (spec-aligned)
472
- await trySignAndEstimate('newWallet');
473
- // Fallback: some legacy deployments may require the agent owner (tx sender) to sign instead.
474
- if (!signature && sdkSignerAddress) {
475
- await trySignAndEstimate('owner');
476
515
  }
477
516
  if (!signature) {
478
517
  const msg = lastError instanceof Error ? lastError.message : String(lastError);
@@ -480,7 +519,12 @@ export class Agent {
480
519
  }
481
520
  }
482
521
  // Call contract function (tx sender is SDK signer: owner/operator)
483
- const txHash = await this.sdk.web3Client.transactContract(identityRegistry, 'setAgentWallet', {}, BigInt(tokenId), newWallet, BigInt(deadlineValue), signature);
522
+ const txHash = await this.sdk.chainClient.writeContract({
523
+ address: identityRegistryAddress,
524
+ abi: IDENTITY_REGISTRY_ABI,
525
+ functionName: 'setAgentWallet',
526
+ args: [BigInt(tokenId), newWallet, BigInt(deadlineValue), signature],
527
+ });
484
528
  // Update local registration file
485
529
  this.registrationFile.walletAddress = newWallet;
486
530
  this.registrationFile.walletChainId = chainId;
@@ -560,7 +604,7 @@ export class Agent {
560
604
  // Agent already registered - update registration file and redeploy
561
605
  // Option 2D: Add logging and timeout handling
562
606
  const chainId = await this.sdk.chainId();
563
- const identityRegistryAddress = await this.sdk.getIdentityRegistry().getAddress();
607
+ const identityRegistryAddress = this.sdk.identityRegistryAddress();
564
608
  const ipfsCid = await this.sdk.ipfsClient.addRegistrationFile(this.registrationFile, chainId, identityRegistryAddress);
565
609
  // Update metadata on-chain if changed
566
610
  // Only send transactions for dirty (changed) metadata to save gas
@@ -574,11 +618,16 @@ export class Agent {
574
618
  }
575
619
  // Update agent URI on-chain
576
620
  const { tokenId } = parseAgentId(this.registrationFile.agentId);
577
- const txHash = await this.sdk.web3Client.transactContract(this.sdk.getIdentityRegistry(), 'setAgentURI', {}, BigInt(tokenId), `ipfs://${ipfsCid}`);
621
+ const txHash = await this.sdk.chainClient.writeContract({
622
+ address: identityRegistryAddress,
623
+ abi: IDENTITY_REGISTRY_ABI,
624
+ functionName: 'setAgentURI',
625
+ args: [BigInt(tokenId), `ipfs://${ipfsCid}`],
626
+ });
578
627
  // Wait for transaction to be confirmed (30 second timeout like Python)
579
628
  // If timeout, continue - transaction was sent and will eventually confirm
580
629
  try {
581
- await this.sdk.web3Client.waitForTransaction(txHash, TIMEOUTS.TRANSACTION_WAIT);
630
+ await this.sdk.chainClient.waitForTransaction({ hash: txHash, timeoutMs: TIMEOUTS.TRANSACTION_WAIT });
582
631
  }
583
632
  catch {
584
633
  // Transaction was sent and will eventually confirm - continue silently
@@ -596,13 +645,18 @@ export class Agent {
596
645
  await this._registerWithoutUri();
597
646
  // Step 2: Upload to IPFS
598
647
  const chainId = await this.sdk.chainId();
599
- const identityRegistryAddress = await this.sdk.getIdentityRegistry().getAddress();
648
+ const identityRegistryAddress = this.sdk.identityRegistryAddress();
600
649
  const ipfsCid = await this.sdk.ipfsClient.addRegistrationFile(this.registrationFile, chainId, identityRegistryAddress);
601
650
  // Step 3: Set agent URI on-chain
602
651
  const { tokenId } = parseAgentId(this.registrationFile.agentId);
603
- const txHash = await this.sdk.web3Client.transactContract(this.sdk.getIdentityRegistry(), 'setAgentURI', {}, BigInt(tokenId), `ipfs://${ipfsCid}`);
652
+ const txHash = await this.sdk.chainClient.writeContract({
653
+ address: identityRegistryAddress,
654
+ abi: IDENTITY_REGISTRY_ABI,
655
+ functionName: 'setAgentURI',
656
+ args: [BigInt(tokenId), `ipfs://${ipfsCid}`],
657
+ });
604
658
  // Wait for transaction to be confirmed
605
- await this.sdk.web3Client.waitForTransaction(txHash);
659
+ await this.sdk.chainClient.waitForTransaction({ hash: txHash });
606
660
  // Clear dirty flags
607
661
  this._lastRegisteredWallet = this.walletAddress;
608
662
  this._lastRegisteredEns = this.ensEndpoint;
@@ -637,7 +691,13 @@ export class Agent {
637
691
  throw new Error('Agent must be registered before setting URI');
638
692
  }
639
693
  const { tokenId } = parseAgentId(this.registrationFile.agentId);
640
- await this.sdk.web3Client.transactContract(this.sdk.getIdentityRegistry(), 'setAgentURI', {}, BigInt(tokenId), agentURI);
694
+ const identityRegistryAddress = this.sdk.identityRegistryAddress();
695
+ await this.sdk.chainClient.writeContract({
696
+ address: identityRegistryAddress,
697
+ abi: IDENTITY_REGISTRY_ABI,
698
+ functionName: 'setAgentURI',
699
+ args: [BigInt(tokenId), agentURI],
700
+ });
641
701
  this.registrationFile.agentURI = agentURI;
642
702
  this.registrationFile.updatedAt = Math.floor(Date.now() / 1000);
643
703
  }
@@ -649,13 +709,10 @@ export class Agent {
649
709
  throw new Error('Agent must be registered before transfer');
650
710
  }
651
711
  const { tokenId } = parseAgentId(this.registrationFile.agentId);
652
- const currentOwner = this.sdk.web3Client.address;
653
- if (!currentOwner) {
654
- throw new Error('No signer available');
655
- }
712
+ const currentOwner = await this.sdk.chainClient.ensureAddress();
656
713
  // Validate address - normalize to lowercase first
657
714
  const normalizedAddress = newOwner.toLowerCase();
658
- if (!this.sdk.web3Client.isAddress(normalizedAddress)) {
715
+ if (!this.sdk.chainClient.isAddress(normalizedAddress)) {
659
716
  throw new Error(`Invalid address: ${newOwner}`);
660
717
  }
661
718
  // Validate not zero address (check before expensive operations)
@@ -663,13 +720,18 @@ export class Agent {
663
720
  throw new Error('Cannot transfer agent to zero address');
664
721
  }
665
722
  // Convert to checksum format
666
- const checksumAddress = this.sdk.web3Client.toChecksumAddress(normalizedAddress);
723
+ const checksumAddress = this.sdk.chainClient.toChecksumAddress(normalizedAddress);
667
724
  // Validate not transferring to self
668
725
  if (checksumAddress.toLowerCase() === currentOwner.toLowerCase()) {
669
726
  throw new Error('Cannot transfer agent to yourself');
670
727
  }
671
- const identityRegistry = this.sdk.getIdentityRegistry();
672
- const txHash = await this.sdk.web3Client.transactContract(identityRegistry, 'transferFrom', {}, currentOwner, checksumAddress, BigInt(tokenId));
728
+ const identityRegistryAddress = this.sdk.identityRegistryAddress();
729
+ const txHash = await this.sdk.chainClient.writeContract({
730
+ address: identityRegistryAddress,
731
+ abi: IDENTITY_REGISTRY_ABI,
732
+ functionName: 'transferFrom',
733
+ args: [currentOwner, checksumAddress, BigInt(tokenId)],
734
+ });
673
735
  return {
674
736
  txHash,
675
737
  from: currentOwner,
@@ -683,23 +745,28 @@ export class Agent {
683
745
  async _registerWithoutUri() {
684
746
  // Collect metadata for registration
685
747
  const metadataEntries = this._collectMetadataForRegistration();
686
- // Mint agent with metadata
687
- const identityRegistry = this.sdk.getIdentityRegistry();
748
+ const identityRegistryAddress = this.sdk.identityRegistryAddress();
688
749
  // If we have metadata, use register(string, tuple[])
689
750
  // Otherwise use register() with no args
690
751
  let txHash;
691
752
  if (metadataEntries.length > 0) {
692
- txHash = await this.sdk.web3Client.transactContract(identityRegistry, 'register', {}, // Transaction options
693
- '', // Empty tokenUri
694
- metadataEntries);
753
+ txHash = await this.sdk.chainClient.writeContract({
754
+ address: identityRegistryAddress,
755
+ abi: IDENTITY_REGISTRY_ABI,
756
+ functionName: 'register',
757
+ args: ['', metadataEntries],
758
+ });
695
759
  }
696
760
  else {
697
- txHash = await this.sdk.web3Client.transactContract(identityRegistry, 'register', {} // Transaction options
698
- // No arguments - calls register()
699
- );
761
+ txHash = await this.sdk.chainClient.writeContract({
762
+ address: identityRegistryAddress,
763
+ abi: IDENTITY_REGISTRY_ABI,
764
+ functionName: 'register',
765
+ args: [],
766
+ });
700
767
  }
701
768
  // Wait for transaction
702
- const receipt = await this.sdk.web3Client.waitForTransaction(txHash);
769
+ const receipt = await this.sdk.chainClient.waitForTransaction({ hash: txHash });
703
770
  // Extract agent ID from events
704
771
  const agentId = this._extractAgentIdFromReceipt(receipt);
705
772
  // Update registration file
@@ -710,11 +777,15 @@ export class Agent {
710
777
  async _registerWithUri(agentUri) {
711
778
  // Collect metadata for registration
712
779
  const metadataEntries = this._collectMetadataForRegistration();
713
- // Register with URI and metadata
714
- const identityRegistry = this.sdk.getIdentityRegistry();
715
- const txHash = await this.sdk.web3Client.transactContract(identityRegistry, 'register', {}, agentUri, metadataEntries);
780
+ const identityRegistryAddress = this.sdk.identityRegistryAddress();
781
+ const txHash = await this.sdk.chainClient.writeContract({
782
+ address: identityRegistryAddress,
783
+ abi: IDENTITY_REGISTRY_ABI,
784
+ functionName: 'register',
785
+ args: [agentUri, metadataEntries],
786
+ });
716
787
  // Wait for transaction
717
- const receipt = await this.sdk.web3Client.waitForTransaction(txHash);
788
+ const receipt = await this.sdk.chainClient.waitForTransaction({ hash: txHash });
718
789
  // Extract agent ID from events
719
790
  const agentId = this._extractAgentIdFromReceipt(receipt);
720
791
  // Update registration file
@@ -727,16 +798,21 @@ export class Agent {
727
798
  async _updateMetadataOnChain() {
728
799
  const metadataEntries = this._collectMetadataForRegistration();
729
800
  const { tokenId } = parseAgentId(this.registrationFile.agentId);
730
- const identityRegistry = this.sdk.getIdentityRegistry();
801
+ const identityRegistryAddress = this.sdk.identityRegistryAddress();
731
802
  // Update metadata one by one (like Python SDK)
732
803
  // Only send transactions for dirty (changed) metadata keys
733
804
  for (const entry of metadataEntries) {
734
805
  if (this._dirtyMetadata.has(entry.metadataKey)) {
735
- const txHash = await this.sdk.web3Client.transactContract(identityRegistry, 'setMetadata', {}, BigInt(tokenId), entry.metadataKey, entry.metadataValue);
806
+ const txHash = await this.sdk.chainClient.writeContract({
807
+ address: identityRegistryAddress,
808
+ abi: IDENTITY_REGISTRY_ABI,
809
+ functionName: 'setMetadata',
810
+ args: [BigInt(tokenId), entry.metadataKey, entry.metadataValue],
811
+ });
736
812
  // Wait with 30 second timeout (like Python SDK)
737
813
  // If timeout, log warning but continue - transaction was sent and will eventually confirm
738
814
  try {
739
- await this.sdk.web3Client.waitForTransaction(txHash, TIMEOUTS.TRANSACTION_WAIT);
815
+ await this.sdk.chainClient.waitForTransaction({ hash: txHash, timeoutMs: TIMEOUTS.TRANSACTION_WAIT });
740
816
  }
741
817
  catch (error) {
742
818
  // Transaction was sent and will eventually confirm - continue silently
@@ -770,19 +846,22 @@ export class Agent {
770
846
  return entries;
771
847
  }
772
848
  _extractAgentIdFromReceipt(receipt) {
773
- // Parse events from receipt to find Registered event
774
- const identityRegistry = this.sdk.getIdentityRegistry();
775
849
  const transferEventTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'; // Transfer(address,address,uint256)
776
850
  // Find the event in the logs
777
851
  for (const log of receipt.logs || []) {
778
852
  try {
779
- // Try parsing as Registered event
780
- const parsed = identityRegistry.interface.parseLog({
781
- topics: Array.isArray(log.topics) ? log.topics.map((t) => typeof t === 'string' ? t : ethers.hexlify(t)) : log.topics || [],
782
- data: typeof log.data === 'string' ? log.data : ethers.hexlify(log.data || '0x'),
853
+ if (!log.topics || log.topics.length === 0) {
854
+ continue;
855
+ }
856
+ const parsed = decodeEventLog({
857
+ abi: IDENTITY_REGISTRY_ABI,
858
+ data: log.data,
859
+ topics: log.topics,
783
860
  });
784
- if (parsed && parsed.name === 'Registered') {
785
- return BigInt(parsed.args.agentId.toString());
861
+ if (parsed && parsed.eventName === 'Registered') {
862
+ const agentId = parsed.args?.agentId;
863
+ if (agentId !== undefined)
864
+ return BigInt(agentId);
786
865
  }
787
866
  }
788
867
  catch {
@@ -791,10 +870,10 @@ export class Agent {
791
870
  const topics = Array.isArray(log.topics) ? log.topics : [];
792
871
  // Transfer event has topic[0] = Transfer signature, topic[3] = tokenId (if 4 topics)
793
872
  if (topics.length >= 4) {
794
- const topic0 = typeof topics[0] === 'string' ? topics[0] : topics[0].toString();
873
+ const topic0 = String(topics[0]);
795
874
  if (topic0 === transferEventTopic || topic0.toLowerCase() === transferEventTopic.toLowerCase()) {
796
875
  // Extract tokenId from topic[3]
797
- const tokenIdHex = typeof topics[3] === 'string' ? topics[3] : topics[3].toString();
876
+ const tokenIdHex = String(topics[3]);
798
877
  // Remove 0x prefix if present and convert
799
878
  const tokenIdStr = tokenIdHex.startsWith('0x') ? tokenIdHex.slice(2) : tokenIdHex;
800
879
  return BigInt('0x' + tokenIdStr);