@agether/sdk 2.8.1 → 2.9.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.
package/dist/index.js CHANGED
@@ -77,13 +77,13 @@ module.exports = __toCommonJS(index_exports);
77
77
  var import_ethers = require("ethers");
78
78
 
79
79
  // src/types/index.ts
80
- var ChainId = /* @__PURE__ */ ((ChainId4) => {
81
- ChainId4[ChainId4["Ethereum"] = 1] = "Ethereum";
82
- ChainId4[ChainId4["Base"] = 8453] = "Base";
83
- ChainId4[ChainId4["BaseSepolia"] = 84532] = "BaseSepolia";
84
- ChainId4[ChainId4["Sepolia"] = 11155111] = "Sepolia";
85
- ChainId4[ChainId4["Hardhat"] = 31337] = "Hardhat";
86
- return ChainId4;
80
+ var ChainId = /* @__PURE__ */ ((ChainId3) => {
81
+ ChainId3[ChainId3["Ethereum"] = 1] = "Ethereum";
82
+ ChainId3[ChainId3["Base"] = 8453] = "Base";
83
+ ChainId3[ChainId3["BaseSepolia"] = 84532] = "BaseSepolia";
84
+ ChainId3[ChainId3["Sepolia"] = 11155111] = "Sepolia";
85
+ ChainId3[ChainId3["Hardhat"] = 31337] = "Hardhat";
86
+ return ChainId3;
87
87
  })(ChainId || {});
88
88
  var AgetherError = class extends Error {
89
89
  constructor(message, code, details) {
@@ -367,93 +367,246 @@ function getContractAddresses(chainId) {
367
367
  }
368
368
 
369
369
  // src/clients/AgetherClient.ts
370
+ var MODE_SINGLE = "0x0000000000000000000000000000000000000000000000000000000000000000";
371
+ var erc20Iface = new import_ethers.ethers.Interface(ERC20_ABI);
372
+ var KNOWN_TOKENS = {
373
+ [8453 /* Base */]: {
374
+ WETH: { address: "0x4200000000000000000000000000000000000006", symbol: "WETH", decimals: 18 },
375
+ wstETH: { address: "0xc1CBa3fCea344f92D9239c08C0568f6F2F0ee452", symbol: "wstETH", decimals: 18 },
376
+ cbETH: { address: "0x2Ae3F1Ec7F1F5012CFEab0185bfc7aa3cf0DEc22", symbol: "cbETH", decimals: 18 }
377
+ },
378
+ [1 /* Ethereum */]: {
379
+ WETH: { address: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", symbol: "WETH", decimals: 18 },
380
+ wstETH: { address: "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0", symbol: "wstETH", decimals: 18 },
381
+ cbETH: { address: "0xBe9895146f7AF43049ca1c1AE358B0541Ea49704", symbol: "cbETH", decimals: 18 }
382
+ }
383
+ };
370
384
  var AgetherClient = class _AgetherClient {
371
385
  constructor(options) {
372
386
  this.config = options.config;
373
387
  this.signer = options.signer;
374
388
  this.agentId = options.agentId;
389
+ this._rpcUrl = options.config.rpcUrl;
390
+ if (options._privateKey) {
391
+ this._privateKey = options._privateKey;
392
+ this._useExternalSigner = false;
393
+ } else {
394
+ this._useExternalSigner = true;
395
+ }
375
396
  const provider = options.signer.provider;
376
397
  if (!provider) throw new AgetherError("Signer must have a provider", "NO_PROVIDER");
377
- this.agether4337Factory = new import_ethers.Contract(
378
- options.config.contracts.agether4337Factory,
379
- AGETHER_4337_FACTORY_ABI,
380
- options.signer
381
- );
382
- this.identityRegistry = new import_ethers.Contract(
383
- options.config.contracts.identityRegistry,
384
- IDENTITY_REGISTRY_ABI,
385
- provider
386
- );
387
- this.agether8004Scorer = new import_ethers.Contract(
388
- options.config.contracts.agether8004Scorer,
389
- AGETHER_8004_SCORER_ABI,
390
- provider
391
- );
392
- this.validationModule = new import_ethers.Contract(
393
- options.config.contracts.erc8004ValidationModule,
394
- AGETHER_8004_VALIDATION_MODULE_ABI,
395
- provider
396
- );
398
+ if ("address" in options.signer && typeof options.signer.address === "string") {
399
+ this._eoaAddress = options.signer.address;
400
+ }
401
+ const c = options.config.contracts;
402
+ this.agether4337Factory = new import_ethers.Contract(c.agether4337Factory, AGETHER_4337_FACTORY_ABI, options.signer);
403
+ this.identityRegistry = new import_ethers.Contract(c.identityRegistry, IDENTITY_REGISTRY_ABI, options.signer);
404
+ this.agether8004Scorer = new import_ethers.Contract(c.agether8004Scorer, AGETHER_8004_SCORER_ABI, provider);
405
+ this.validationModule = new import_ethers.Contract(c.erc8004ValidationModule, AGETHER_8004_VALIDATION_MODULE_ABI, provider);
406
+ this.entryPoint = new import_ethers.Contract(c.entryPoint, ENTRYPOINT_V07_ABI, options.signer);
397
407
  }
398
- // Static Factory
399
- static fromPrivateKey(privateKey, agentId, chainIdOrConfig) {
400
- const config = typeof chainIdOrConfig === "number" ? getDefaultConfig(chainIdOrConfig) : chainIdOrConfig;
408
+ static fromPrivateKey(privateKey, agentIdOrChain, chainIdOrConfig) {
409
+ let agentId;
410
+ let config;
411
+ if (typeof agentIdOrChain === "bigint") {
412
+ agentId = agentIdOrChain;
413
+ config = typeof chainIdOrConfig === "number" ? getDefaultConfig(chainIdOrConfig) : chainIdOrConfig;
414
+ } else {
415
+ config = typeof agentIdOrChain === "number" ? getDefaultConfig(agentIdOrChain) : agentIdOrChain;
416
+ }
401
417
  const provider = new import_ethers.ethers.JsonRpcProvider(config.rpcUrl);
402
418
  const signer = new import_ethers.ethers.Wallet(privateKey, provider);
403
- return new _AgetherClient({ config, signer, agentId });
419
+ return new _AgetherClient({ config, signer, agentId, _privateKey: privateKey });
420
+ }
421
+ // ════════════════════════════════════════════════════════
422
+ // Registration
423
+ // ════════════════════════════════════════════════════════
424
+ /**
425
+ * Register: create ERC-8004 identity + Safe account in one flow.
426
+ * If already registered, returns existing state.
427
+ *
428
+ * Sets `this.agentId` on success so subsequent operations work immediately.
429
+ */
430
+ async register() {
431
+ const eoaAddr = await this._getSignerAddress();
432
+ if (this.agentId !== void 0) {
433
+ const exists = await this.agether4337Factory.accountExists(this.agentId);
434
+ if (exists) {
435
+ const acct = await this.agether4337Factory.getAccount(this.agentId);
436
+ this.accountAddress = acct;
437
+ const kyaRequired2 = await this.isKyaRequired();
438
+ return {
439
+ agentId: this.agentId.toString(),
440
+ address: eoaAddr,
441
+ agentAccount: acct,
442
+ alreadyRegistered: true,
443
+ kyaRequired: kyaRequired2
444
+ };
445
+ }
446
+ }
447
+ let agentId;
448
+ if (this.agentId !== void 0) {
449
+ const balance = await this.identityRegistry.balanceOf(eoaAddr);
450
+ if (balance > 0n) {
451
+ agentId = this.agentId;
452
+ } else {
453
+ agentId = await this._mintNewIdentity();
454
+ }
455
+ } else {
456
+ agentId = await this._mintNewIdentity();
457
+ }
458
+ this.agentId = agentId;
459
+ const acctExists = await this.agether4337Factory.accountExists(agentId);
460
+ let txHash;
461
+ if (!acctExists) {
462
+ const tx = await this.agether4337Factory.createAccount(agentId);
463
+ const receipt = await tx.wait();
464
+ this._refreshSigner();
465
+ txHash = receipt.hash;
466
+ }
467
+ const acctAddr = await this.agether4337Factory.getAccount(agentId);
468
+ this.accountAddress = acctAddr;
469
+ const kyaRequired = await this.isKyaRequired();
470
+ return {
471
+ agentId: agentId.toString(),
472
+ address: eoaAddr,
473
+ agentAccount: acctAddr,
474
+ alreadyRegistered: acctExists,
475
+ kyaRequired,
476
+ tx: txHash
477
+ };
404
478
  }
405
- // Account Management
479
+ /** Mint a new ERC-8004 identity and return the agentId. */
480
+ async _mintNewIdentity() {
481
+ const regTx = await this.identityRegistry.register();
482
+ const regReceipt = await regTx.wait();
483
+ this._refreshSigner();
484
+ let agentId = 0n;
485
+ for (const log of regReceipt.logs) {
486
+ try {
487
+ const parsed = this.identityRegistry.interface.parseLog({
488
+ topics: log.topics,
489
+ data: log.data
490
+ });
491
+ if (parsed?.name === "Transfer") {
492
+ agentId = parsed.args[2];
493
+ break;
494
+ }
495
+ } catch (e) {
496
+ console.warn("[agether] parseLog skip:", e instanceof Error ? e.message : e);
497
+ continue;
498
+ }
499
+ }
500
+ if (agentId === 0n) {
501
+ throw new AgetherError("Failed to parse agentId from registration", "PARSE_ERROR");
502
+ }
503
+ return agentId;
504
+ }
505
+ // ════════════════════════════════════════════════════════
506
+ // Account Management
507
+ // ════════════════════════════════════════════════════════
508
+ /**
509
+ * Deploy a Safe account smart wallet for the agent.
510
+ * The caller must own the ERC-8004 NFT.
511
+ */
406
512
  async createAccount() {
407
- const tx = await this.agether4337Factory.createAccount(this.agentId);
513
+ const id = this._requireAgentId();
514
+ const tx = await this.agether4337Factory.createAccount(id);
408
515
  const receipt = await tx.wait();
516
+ this._refreshSigner();
409
517
  const event = receipt.logs.map((log) => {
410
518
  try {
411
519
  return this.agether4337Factory.interface.parseLog(log);
412
- } catch (e) {
413
- console.warn("[agether] createAccount parseLog skip:", e instanceof Error ? e.message : e);
520
+ } catch {
414
521
  return null;
415
522
  }
416
523
  }).find((e) => e?.name === "AccountCreated");
417
524
  if (event) {
418
525
  this.accountAddress = event.args.safeAccount;
419
526
  } else {
420
- this.accountAddress = await this.agether4337Factory.getAccount(this.agentId);
527
+ this.accountAddress = await this.agether4337Factory.getAccount(id);
421
528
  }
422
529
  return this.accountAddress;
423
530
  }
531
+ /** Get the Safe account address for the current agent. Cached after first call. */
424
532
  async getAccountAddress() {
425
533
  if (this.accountAddress) return this.accountAddress;
426
- const addr = await this.agether4337Factory.getAccount(this.agentId);
534
+ const id = this._requireAgentId();
535
+ const addr = await this.agether4337Factory.getAccount(id);
427
536
  if (addr === import_ethers.ethers.ZeroAddress) {
428
- throw new AgetherError("No account found. Create one with createAccount().", "NO_ACCOUNT");
537
+ throw new AgetherError(
538
+ "No account found. Create one with createAccount() or register().",
539
+ "NO_ACCOUNT"
540
+ );
429
541
  }
430
542
  this.accountAddress = addr;
431
543
  return addr;
432
544
  }
545
+ /** Check whether the Safe account has been deployed. */
433
546
  async accountExists() {
434
- return this.agether4337Factory.accountExists(this.agentId);
547
+ const id = this._requireAgentId();
548
+ return this.agether4337Factory.accountExists(id);
435
549
  }
436
- // Balances
550
+ // ════════════════════════════════════════════════════════
551
+ // Balances
552
+ // ════════════════════════════════════════════════════════
553
+ /**
554
+ * Get ETH, USDC, and collateral token balances for EOA and Safe account.
555
+ *
556
+ * Collateral tokens are resolved from a built-in registry of well-known
557
+ * tokens per chain (WETH, wstETH, cbETH).
558
+ */
437
559
  async getBalances() {
438
560
  const provider = this.signer.provider;
439
- const eoaAddr = await this.signer.getAddress();
561
+ const eoaAddr = await this._getSignerAddress();
440
562
  const usdc = new import_ethers.Contract(this.config.contracts.usdc, ERC20_ABI, provider);
441
563
  const ethBal = await provider.getBalance(eoaAddr);
442
564
  const usdcBal = await usdc.balanceOf(eoaAddr);
565
+ const knownTokens = KNOWN_TOKENS[this.config.chainId] ?? {};
566
+ const eoaCollateral = {};
567
+ for (const [symbol, info] of Object.entries(knownTokens)) {
568
+ try {
569
+ const token = new import_ethers.Contract(info.address, ERC20_ABI, provider);
570
+ const bal = await token.balanceOf(eoaAddr);
571
+ eoaCollateral[symbol] = import_ethers.ethers.formatUnits(bal, info.decimals);
572
+ } catch (e) {
573
+ console.warn(`[agether] EOA collateral fetch failed for ${symbol}:`, e instanceof Error ? e.message : e);
574
+ eoaCollateral[symbol] = "0";
575
+ }
576
+ }
443
577
  const result = {
444
- eoa: { eth: import_ethers.ethers.formatEther(ethBal), usdc: import_ethers.ethers.formatUnits(usdcBal, 6) }
578
+ agentId: this.agentId !== void 0 ? this.agentId.toString() : "?",
579
+ address: eoaAddr,
580
+ eth: import_ethers.ethers.formatEther(ethBal),
581
+ usdc: import_ethers.ethers.formatUnits(usdcBal, 6),
582
+ collateral: eoaCollateral
445
583
  };
446
584
  try {
447
585
  const acctAddr = await this.getAccountAddress();
448
586
  const acctEth = await provider.getBalance(acctAddr);
449
587
  const acctUsdc = await usdc.balanceOf(acctAddr);
450
- result.account = {
588
+ const acctCollateral = {};
589
+ for (const [symbol, info] of Object.entries(knownTokens)) {
590
+ try {
591
+ const token = new import_ethers.Contract(info.address, ERC20_ABI, provider);
592
+ const bal = await token.balanceOf(acctAddr);
593
+ acctCollateral[symbol] = import_ethers.ethers.formatUnits(bal, info.decimals);
594
+ } catch (e) {
595
+ console.warn(`[agether] Account collateral fetch failed for ${symbol}:`, e instanceof Error ? e.message : e);
596
+ acctCollateral[symbol] = "0";
597
+ }
598
+ }
599
+ result.agentAccount = {
451
600
  address: acctAddr,
452
601
  eth: import_ethers.ethers.formatEther(acctEth),
453
- usdc: import_ethers.ethers.formatUnits(acctUsdc, 6)
602
+ usdc: import_ethers.ethers.formatUnits(acctUsdc, 6),
603
+ collateral: acctCollateral
454
604
  };
455
605
  } catch (e) {
456
- console.warn("[agether] getBalances: no Safe account or fetch failed:", e instanceof Error ? e.message : e);
606
+ if (e instanceof AgetherError && (e.code === "NO_ACCOUNT" || e.code === "NO_AGENT_ID")) {
607
+ } else {
608
+ console.warn("[agether] getBalances: failed to fetch Safe account data:", e.message ?? e);
609
+ }
457
610
  }
458
611
  return result;
459
612
  }
@@ -467,6 +620,7 @@ var AgetherClient = class _AgetherClient {
467
620
  const amount = import_ethers.ethers.parseUnits(usdcAmount, 6);
468
621
  const tx = await usdc.transfer(acctAddr, amount);
469
622
  const receipt = await tx.wait();
623
+ this._refreshSigner();
470
624
  return {
471
625
  txHash: receipt.hash,
472
626
  blockNumber: receipt.blockNumber,
@@ -474,7 +628,89 @@ var AgetherClient = class _AgetherClient {
474
628
  gasUsed: receipt.gasUsed
475
629
  };
476
630
  }
477
- // Identity & Validation
631
+ // ════════════════════════════════════════════════════════
632
+ // Withdrawals (Safe → EOA via UserOps)
633
+ // ════════════════════════════════════════════════════════
634
+ /**
635
+ * Withdraw an ERC-20 token from Safe account to EOA.
636
+ * Executes a transfer via Safe UserOp.
637
+ *
638
+ * @param tokenSymbol - Token to withdraw (e.g. 'USDC', 'WETH', 'wstETH') or 0x address
639
+ * @param amount - Amount to withdraw (human-readable, e.g. '100', or 'all')
640
+ */
641
+ async withdrawToken(tokenSymbol, amount) {
642
+ const acctAddr = await this.getAccountAddress();
643
+ const eoaAddr = await this._getSignerAddress();
644
+ const tokenInfo = await this._resolveToken(tokenSymbol);
645
+ const tokenContract = new import_ethers.Contract(tokenInfo.address, ERC20_ABI, this.signer.provider);
646
+ let weiAmount;
647
+ if (amount === "all") {
648
+ weiAmount = await tokenContract.balanceOf(acctAddr);
649
+ if (weiAmount === 0n) {
650
+ throw new AgetherError(`No ${tokenInfo.symbol} in Safe account`, "INSUFFICIENT_BALANCE");
651
+ }
652
+ } else {
653
+ weiAmount = import_ethers.ethers.parseUnits(amount, tokenInfo.decimals);
654
+ }
655
+ const data = erc20Iface.encodeFunctionData("transfer", [eoaAddr, weiAmount]);
656
+ const receipt = await this._exec(tokenInfo.address, data);
657
+ const actualAmount = amount === "all" ? import_ethers.ethers.formatUnits(weiAmount, tokenInfo.decimals) : amount;
658
+ return { tx: receipt.hash, token: tokenInfo.symbol, amount: actualAmount, destination: eoaAddr };
659
+ }
660
+ /**
661
+ * Withdraw ETH from Safe account to EOA.
662
+ * Executes a native ETH transfer via Safe UserOp.
663
+ *
664
+ * @param amount - ETH amount (e.g. '0.01' or 'all')
665
+ */
666
+ async withdrawEth(amount) {
667
+ const acctAddr = await this.getAccountAddress();
668
+ const eoaAddr = await this._getSignerAddress();
669
+ let weiAmount;
670
+ if (amount === "all") {
671
+ weiAmount = await this.signer.provider.getBalance(acctAddr);
672
+ if (weiAmount === 0n) throw new AgetherError("No ETH in Safe account", "INSUFFICIENT_BALANCE");
673
+ } else {
674
+ weiAmount = import_ethers.ethers.parseEther(amount);
675
+ }
676
+ const receipt = await this._exec(eoaAddr, "0x", weiAmount);
677
+ const actualAmount = amount === "all" ? import_ethers.ethers.formatEther(weiAmount) : amount;
678
+ return { tx: receipt.hash, token: "ETH", amount: actualAmount, destination: eoaAddr };
679
+ }
680
+ // ════════════════════════════════════════════════════════
681
+ // Sponsorship
682
+ // ════════════════════════════════════════════════════════
683
+ /**
684
+ * Send tokens to another agent's Safe account (or any address).
685
+ * Transfers from EOA (does NOT require a UserOp).
686
+ *
687
+ * @param target - `{ agentId: '42' }` or `{ address: '0x...' }`
688
+ * @param tokenSymbol - Token to send (e.g. 'WETH', 'USDC') or 0x address
689
+ * @param amount - Amount to send (human-readable)
690
+ */
691
+ async sponsor(target, tokenSymbol, amount) {
692
+ const tokenInfo = await this._resolveToken(tokenSymbol);
693
+ let targetAddr;
694
+ if (target.address) {
695
+ targetAddr = target.address;
696
+ } else if (target.agentId) {
697
+ targetAddr = await this.agether4337Factory.getAccount(BigInt(target.agentId));
698
+ if (targetAddr === import_ethers.ethers.ZeroAddress) {
699
+ throw new AgetherError("Target agent has no account", "NO_ACCOUNT");
700
+ }
701
+ } else {
702
+ throw new AgetherError("Provide agentId or address", "INVALID_TARGET");
703
+ }
704
+ const weiAmount = import_ethers.ethers.parseUnits(amount, tokenInfo.decimals);
705
+ const tokenContract = new import_ethers.Contract(tokenInfo.address, ERC20_ABI, this.signer);
706
+ const tx = await tokenContract.transfer(targetAddr, weiAmount);
707
+ const receipt = await tx.wait();
708
+ this._refreshSigner();
709
+ return { tx: receipt.hash, targetAccount: targetAddr, targetAgentId: target.agentId };
710
+ }
711
+ // ════════════════════════════════════════════════════════
712
+ // Identity & Validation
713
+ // ════════════════════════════════════════════════════════
478
714
  /**
479
715
  * Check if the KYA gate is active on the validation module.
480
716
  * If validationRegistry is not set, all txs pass (KYA disabled).
@@ -499,31 +735,45 @@ var AgetherClient = class _AgetherClient {
499
735
  return false;
500
736
  }
501
737
  }
738
+ /** Check whether the agent's ERC-8004 NFT exists. */
502
739
  async identityExists() {
740
+ const id = this._requireAgentId();
503
741
  try {
504
- await this.identityRegistry.ownerOf(this.agentId);
742
+ await this.identityRegistry.ownerOf(id);
505
743
  return true;
506
744
  } catch (e) {
507
745
  console.warn("[agether] identityExists check failed:", e instanceof Error ? e.message : e);
508
746
  return false;
509
747
  }
510
748
  }
749
+ /** Get the owner address of the ERC-8004 NFT. */
511
750
  async getIdentityOwner() {
512
- return this.identityRegistry.ownerOf(this.agentId);
751
+ const id = this._requireAgentId();
752
+ return this.identityRegistry.ownerOf(id);
513
753
  }
514
- // Reputation
754
+ // ════════════════════════════════════════════════════════
755
+ // Reputation
756
+ // ════════════════════════════════════════════════════════
757
+ /** Read the agent's current credit score from the Agether8004Scorer contract. */
515
758
  async getCreditScore() {
516
- return this.agether8004Scorer.getCreditScore(this.agentId);
759
+ const id = this._requireAgentId();
760
+ return this.agether8004Scorer.getCreditScore(id);
517
761
  }
762
+ /** Check if the score is fresh (within MAX_ORACLE_AGE). */
518
763
  async isScoreFresh() {
519
- const [fresh, age] = await this.agether8004Scorer.isScoreFresh(this.agentId);
764
+ const id = this._requireAgentId();
765
+ const [fresh, age] = await this.agether8004Scorer.isScoreFresh(id);
520
766
  return { fresh, age };
521
767
  }
768
+ /** Check if the agent meets a minimum score threshold. */
522
769
  async isEligible(minScore = 500n) {
523
- const [eligible, currentScore] = await this.agether8004Scorer.isEligible(this.agentId, minScore);
770
+ const id = this._requireAgentId();
771
+ const [eligible, currentScore] = await this.agether8004Scorer.isEligible(id, minScore);
524
772
  return { eligible, currentScore };
525
773
  }
526
- // Getters
774
+ // ════════════════════════════════════════════════════════
775
+ // Getters
776
+ // ════════════════════════════════════════════════════════
527
777
  get chainId() {
528
778
  return this.config.chainId;
529
779
  }
@@ -537,24 +787,209 @@ var AgetherClient = class _AgetherClient {
537
787
  return this.signer;
538
788
  }
539
789
  getAgentId() {
790
+ return this._requireAgentId();
791
+ }
792
+ // ════════════════════════════════════════════════════════
793
+ // Private Helpers
794
+ // ════════════════════════════════════════════════════════
795
+ /** Require agentId to be set, throw a helpful error otherwise. */
796
+ _requireAgentId() {
797
+ if (this.agentId === void 0) {
798
+ throw new AgetherError("agentId not set. Call register() first.", "NO_AGENT_ID");
799
+ }
540
800
  return this.agentId;
541
801
  }
802
+ /** Resolve EOA signer address (async, cached). */
803
+ async _getSignerAddress() {
804
+ if (!this._eoaAddress) {
805
+ this._eoaAddress = await this.signer.getAddress();
806
+ }
807
+ return this._eoaAddress;
808
+ }
809
+ /**
810
+ * Resolve a token symbol or address to { address, symbol, decimals }.
811
+ *
812
+ * Supports:
813
+ * - `'USDC'` → from chain config
814
+ * - Well-known symbols (`'WETH'`, `'wstETH'`, `'cbETH'`) → built-in per-chain registry
815
+ * - `'0x...'` address → reads decimals and symbol onchain
816
+ */
817
+ async _resolveToken(symbolOrAddress) {
818
+ if (symbolOrAddress.toUpperCase() === "USDC") {
819
+ return { address: this.config.contracts.usdc, symbol: "USDC", decimals: 6 };
820
+ }
821
+ const chainTokens = KNOWN_TOKENS[this.config.chainId] ?? {};
822
+ const bySymbol = chainTokens[symbolOrAddress] || chainTokens[symbolOrAddress.toUpperCase()];
823
+ if (bySymbol) return bySymbol;
824
+ if (symbolOrAddress.startsWith("0x") && symbolOrAddress.length === 42) {
825
+ try {
826
+ const token = new import_ethers.Contract(
827
+ symbolOrAddress,
828
+ ["function decimals() view returns (uint8)", "function symbol() view returns (string)"],
829
+ this.signer.provider
830
+ );
831
+ const [decimals, symbol] = await Promise.all([token.decimals(), token.symbol()]);
832
+ return { address: symbolOrAddress, symbol, decimals: Number(decimals) };
833
+ } catch (e) {
834
+ throw new AgetherError(
835
+ `Failed to read token at ${symbolOrAddress}: ${e instanceof Error ? e.message : e}`,
836
+ "UNKNOWN_TOKEN"
837
+ );
838
+ }
839
+ }
840
+ throw new AgetherError(
841
+ `Unknown token: ${symbolOrAddress}. Use a known symbol (USDC, WETH, wstETH, cbETH) or a 0x address.`,
842
+ "UNKNOWN_TOKEN"
843
+ );
844
+ }
845
+ /**
846
+ * Refresh signer and rebind contracts for fresh nonce.
847
+ *
848
+ * For the privateKey path: recreates provider + wallet.
849
+ * For external signers: just rebinds contract instances.
850
+ */
851
+ _refreshSigner() {
852
+ if (!this._useExternalSigner && this._privateKey) {
853
+ const provider = new import_ethers.ethers.JsonRpcProvider(this._rpcUrl);
854
+ const wallet = new import_ethers.ethers.Wallet(this._privateKey, provider);
855
+ this.signer = wallet;
856
+ this._eoaAddress = wallet.address;
857
+ }
858
+ const c = this.config.contracts;
859
+ this.agether4337Factory = new import_ethers.Contract(c.agether4337Factory, AGETHER_4337_FACTORY_ABI, this.signer);
860
+ this.identityRegistry = new import_ethers.Contract(c.identityRegistry, IDENTITY_REGISTRY_ABI, this.signer);
861
+ this.agether8004Scorer = new import_ethers.Contract(c.agether8004Scorer, AGETHER_8004_SCORER_ABI, this.signer.provider);
862
+ this.validationModule = new import_ethers.Contract(c.erc8004ValidationModule, AGETHER_8004_VALIDATION_MODULE_ABI, this.signer.provider);
863
+ this.entryPoint = new import_ethers.Contract(c.entryPoint, ENTRYPOINT_V07_ABI, this.signer);
864
+ }
865
+ // ────────────────────────────────────────────────────────
866
+ // ERC-4337 UserOp helpers (Safe + Safe7579 + EntryPoint v0.7)
867
+ // ────────────────────────────────────────────────────────
868
+ /**
869
+ * Pack two uint128 values into a single bytes32:
870
+ * bytes32 = (hi << 128) | lo
871
+ */
872
+ _packUint128(hi, lo) {
873
+ return import_ethers.ethers.zeroPadValue(import_ethers.ethers.toBeHex(hi << 128n | lo), 32);
874
+ }
875
+ /**
876
+ * Build, sign and submit a PackedUserOperation through EntryPoint.handleOps.
877
+ */
878
+ async _submitUserOp(callData) {
879
+ const sender = await this.getAccountAddress();
880
+ const eoaAddr = await this._getSignerAddress();
881
+ const validatorAddr = this.config.contracts.erc8004ValidationModule;
882
+ const nonceKey = BigInt(validatorAddr) << 32n;
883
+ const nonce = await this.entryPoint.getNonce(sender, nonceKey);
884
+ const feeData = await this.signer.provider.getFeeData();
885
+ const maxFeePerGas = feeData.maxFeePerGas ?? import_ethers.ethers.parseUnits("0.5", "gwei");
886
+ const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas ?? import_ethers.ethers.parseUnits("0.1", "gwei");
887
+ const verificationGasLimit = 500000n;
888
+ const callGasLimit = 800000n;
889
+ const preVerificationGas = 100000n;
890
+ const accountGasLimits = this._packUint128(verificationGasLimit, callGasLimit);
891
+ const gasFees = this._packUint128(maxPriorityFeePerGas, maxFeePerGas);
892
+ const requiredPrefund = (verificationGasLimit + callGasLimit + preVerificationGas) * maxFeePerGas;
893
+ const accountBalance = await this.signer.provider.getBalance(sender);
894
+ if (accountBalance < requiredPrefund) {
895
+ const topUp = requiredPrefund - accountBalance;
896
+ const topUpWithBuffer = topUp * 120n / 100n;
897
+ const fundTx = await this.signer.sendTransaction({
898
+ to: sender,
899
+ value: topUpWithBuffer
900
+ });
901
+ await fundTx.wait();
902
+ this._refreshSigner();
903
+ }
904
+ const userOp = {
905
+ sender,
906
+ nonce,
907
+ initCode: "0x",
908
+ callData,
909
+ accountGasLimits,
910
+ preVerificationGas,
911
+ gasFees,
912
+ paymasterAndData: "0x",
913
+ signature: "0x"
914
+ };
915
+ const userOpHash = await this.entryPoint.getUserOpHash(userOp);
916
+ const signature = await this.signer.signMessage(import_ethers.ethers.getBytes(userOpHash));
917
+ userOp.signature = signature;
918
+ const tx = await this.entryPoint.handleOps([userOp], eoaAddr);
919
+ const receipt = await tx.wait();
920
+ this._refreshSigner();
921
+ const epIface = new import_ethers.ethers.Interface(ENTRYPOINT_V07_ABI);
922
+ for (const log of receipt.logs) {
923
+ try {
924
+ const parsed = epIface.parseLog({ topics: log.topics, data: log.data });
925
+ if (parsed?.name === "UserOperationEvent" && !parsed.args.success) {
926
+ let revertMsg = "UserOp inner execution reverted";
927
+ for (const rLog of receipt.logs) {
928
+ try {
929
+ const rParsed = epIface.parseLog({ topics: rLog.topics, data: rLog.data });
930
+ if (rParsed?.name === "UserOperationRevertReason") {
931
+ const reason = rParsed.args.revertReason;
932
+ try {
933
+ if (reason.length >= 10 && reason.slice(0, 10) === "0x08c379a0") {
934
+ const decoded = import_ethers.ethers.AbiCoder.defaultAbiCoder().decode(
935
+ ["string"],
936
+ "0x" + reason.slice(10)
937
+ );
938
+ revertMsg = `UserOp reverted: ${decoded[0]}`;
939
+ } else {
940
+ revertMsg = `UserOp reverted with data: ${reason}`;
941
+ }
942
+ } catch {
943
+ revertMsg = `UserOp reverted with data: ${reason}`;
944
+ }
945
+ break;
946
+ }
947
+ } catch {
948
+ continue;
949
+ }
950
+ }
951
+ throw new AgetherError(revertMsg, "USEROP_EXECUTION_FAILED");
952
+ }
953
+ } catch (e) {
954
+ if (e instanceof AgetherError) throw e;
955
+ continue;
956
+ }
957
+ }
958
+ return receipt;
959
+ }
960
+ /**
961
+ * Execute a single call via Safe7579 account (ERC-7579 single mode)
962
+ * through an ERC-4337 UserOperation.
963
+ */
964
+ async _exec(target, data, value = 0n) {
965
+ const valueHex = import_ethers.ethers.zeroPadValue(import_ethers.ethers.toBeHex(value), 32);
966
+ const executionCalldata = import_ethers.ethers.concat([target, valueHex, data]);
967
+ const safe7579Iface = new import_ethers.ethers.Interface(SAFE7579_ACCOUNT_ABI);
968
+ const callData = safe7579Iface.encodeFunctionData("execute", [MODE_SINGLE, executionCalldata]);
969
+ return this._submitUserOp(callData);
970
+ }
542
971
  };
543
972
 
544
973
  // src/clients/MorphoClient.ts
545
974
  var import_ethers2 = require("ethers");
546
975
  var import_axios = __toESM(require("axios"));
547
976
  var MORPHO_API_URL = "https://api.morpho.org/graphql";
548
- var MODE_SINGLE = "0x0000000000000000000000000000000000000000000000000000000000000000";
977
+ var MODE_SINGLE2 = "0x0000000000000000000000000000000000000000000000000000000000000000";
549
978
  var MODE_BATCH = "0x0100000000000000000000000000000000000000000000000000000000000000";
550
979
  var morphoIface = new import_ethers2.ethers.Interface(MORPHO_BLUE_ABI);
551
- var erc20Iface = new import_ethers2.ethers.Interface(ERC20_ABI);
980
+ var erc20Iface2 = new import_ethers2.ethers.Interface(ERC20_ABI);
552
981
  var MorphoClient = class {
553
982
  constructor(config) {
554
983
  this._marketCache = /* @__PURE__ */ new Map();
555
984
  /** Dynamic token registry: symbol (uppercase) → { address, symbol, decimals } */
556
985
  this._tokenCache = /* @__PURE__ */ new Map();
557
986
  this._discoveredAt = 0;
987
+ if (!config.agentId) {
988
+ throw new AgetherError(
989
+ "agentId is required. Use AgetherClient.register() first to get an agentId.",
990
+ "NO_AGENT_ID"
991
+ );
992
+ }
558
993
  const chainId = config.chainId ?? 1 /* Ethereum */;
559
994
  const defaultCfg = getDefaultConfig(chainId);
560
995
  this.config = defaultCfg;
@@ -584,26 +1019,7 @@ var MorphoClient = class {
584
1019
  const addrs = { ...defaultCfg.contracts, ...config.contracts };
585
1020
  this.agether4337Factory = new import_ethers2.Contract(addrs.agether4337Factory, ACCOUNT_FACTORY_ABI, this._signer);
586
1021
  this.morphoBlue = new import_ethers2.Contract(addrs.morphoBlue, MORPHO_BLUE_ABI, this.provider);
587
- this.agether8004Scorer = new import_ethers2.Contract(addrs.agether8004Scorer, AGENT_REPUTATION_ABI, this._signer);
588
- this.identityRegistry = new import_ethers2.Contract(addrs.identityRegistry, IDENTITY_REGISTRY_ABI, this._signer);
589
1022
  this.entryPoint = new import_ethers2.Contract(addrs.entryPoint, ENTRYPOINT_V07_ABI, this._signer);
590
- this.validationModule = new import_ethers2.Contract(addrs.erc8004ValidationModule, ERC8004_VALIDATION_MODULE_ABI, this.provider);
591
- }
592
- // ════════════════════════════════════════════════════════
593
- // KYA Gate Check
594
- // ════════════════════════════════════════════════════════
595
- /**
596
- * Check whether the KYA (Know Your Agent) code verification gate is active.
597
- * Reads the ERC8004ValidationModule's validationRegistry — when set to
598
- * a non-zero address, the module enforces KYA code approval.
599
- */
600
- async isKyaRequired() {
601
- try {
602
- const registryAddr = await this.validationModule.validationRegistry();
603
- return registryAddr !== import_ethers2.ethers.ZeroAddress;
604
- } catch {
605
- return false;
606
- }
607
1023
  }
608
1024
  // ════════════════════════════════════════════════════════
609
1025
  // Account Management
@@ -611,7 +1027,6 @@ var MorphoClient = class {
611
1027
  /** Resolve the AgentAccount address (cached, with retry for flaky RPCs). */
612
1028
  async getAccountAddress() {
613
1029
  if (this._accountAddress) return this._accountAddress;
614
- if (!this.agentId) throw new AgetherError("agentId not set", "NO_AGENT_ID");
615
1030
  const MAX_RETRIES = 3;
616
1031
  let lastErr;
617
1032
  for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
@@ -633,7 +1048,6 @@ var MorphoClient = class {
633
1048
  throw lastErr;
634
1049
  }
635
1050
  getAgentId() {
636
- if (!this.agentId) throw new AgetherError("agentId not set", "NO_AGENT_ID");
637
1051
  return this.agentId;
638
1052
  }
639
1053
  /**
@@ -666,182 +1080,6 @@ var MorphoClient = class {
666
1080
  }
667
1081
  return this._eoaAddress;
668
1082
  }
669
- /** Mint a new ERC-8004 identity and return the agentId. */
670
- async _mintNewIdentity() {
671
- const regTx = await this.identityRegistry.register();
672
- const regReceipt = await regTx.wait();
673
- this._refreshSigner();
674
- let agentId = 0n;
675
- for (const log of regReceipt.logs) {
676
- try {
677
- const parsed = this.identityRegistry.interface.parseLog({ topics: log.topics, data: log.data });
678
- if (parsed?.name === "Transfer") {
679
- agentId = parsed.args[2];
680
- break;
681
- }
682
- } catch (e) {
683
- console.warn("[agether] parseLog skip:", e instanceof Error ? e.message : e);
684
- continue;
685
- }
686
- }
687
- if (agentId === 0n) throw new AgetherError("Failed to parse agentId from registration", "PARSE_ERROR");
688
- return agentId;
689
- }
690
- /**
691
- * Register: create ERC-8004 identity + AgentAccount in one flow.
692
- * If already registered, returns existing state.
693
- */
694
- async register(_name) {
695
- const eoaAddr = await this.getSignerAddress();
696
- if (this.agentId) {
697
- const exists = await this.agether4337Factory.accountExists(BigInt(this.agentId));
698
- if (exists) {
699
- const acct = await this.agether4337Factory.getAccount(BigInt(this.agentId));
700
- this._accountAddress = acct;
701
- const kyaRequired2 = await this.isKyaRequired();
702
- return { agentId: this.agentId, address: eoaAddr, agentAccount: acct, alreadyRegistered: true, kyaRequired: kyaRequired2 };
703
- }
704
- }
705
- let agentId;
706
- if (this.agentId) {
707
- const balance = await this.identityRegistry.balanceOf(eoaAddr);
708
- if (balance > 0n) {
709
- agentId = BigInt(this.agentId);
710
- } else {
711
- agentId = await this._mintNewIdentity();
712
- }
713
- } else {
714
- agentId = await this._mintNewIdentity();
715
- }
716
- this.agentId = agentId.toString();
717
- const acctExists = await this.agether4337Factory.accountExists(agentId);
718
- let txHash;
719
- if (!acctExists) {
720
- const tx = await this.agether4337Factory.createAccount(agentId);
721
- const receipt = await tx.wait();
722
- this._refreshSigner();
723
- txHash = receipt.hash;
724
- }
725
- const acctAddr = await this.agether4337Factory.getAccount(agentId);
726
- this._accountAddress = acctAddr;
727
- const kyaRequired = await this.isKyaRequired();
728
- return {
729
- agentId: this.agentId,
730
- address: eoaAddr,
731
- agentAccount: acctAddr,
732
- alreadyRegistered: acctExists,
733
- kyaRequired,
734
- tx: txHash
735
- };
736
- }
737
- /** Get ETH / USDC / collateral balances for EOA and AgentAccount. */
738
- async getBalances() {
739
- const eoaAddr = await this.getSignerAddress();
740
- const usdc = new import_ethers2.Contract(this.config.contracts.usdc, ERC20_ABI, this.provider);
741
- const ethBal = await this.provider.getBalance(eoaAddr);
742
- const usdcBal = await usdc.balanceOf(eoaAddr);
743
- const discoveredTokens = await this._getDiscoveredTokens();
744
- const eoaCollateral = {};
745
- for (const info of discoveredTokens) {
746
- try {
747
- const token = new import_ethers2.Contract(info.address, ERC20_ABI, this.provider);
748
- const bal = await token.balanceOf(eoaAddr);
749
- eoaCollateral[info.symbol] = import_ethers2.ethers.formatUnits(bal, info.decimals);
750
- } catch (e) {
751
- console.warn(`[agether] EOA collateral fetch failed for ${info.symbol}:`, e instanceof Error ? e.message : e);
752
- eoaCollateral[info.symbol] = "0";
753
- }
754
- }
755
- const result = {
756
- agentId: this.agentId || "?",
757
- address: eoaAddr,
758
- eth: import_ethers2.ethers.formatEther(ethBal),
759
- usdc: import_ethers2.ethers.formatUnits(usdcBal, 6),
760
- collateral: eoaCollateral
761
- };
762
- try {
763
- const acctAddr = await this.getAccountAddress();
764
- const acctEth = await this.provider.getBalance(acctAddr);
765
- const acctUsdc = await usdc.balanceOf(acctAddr);
766
- const acctCollateral = {};
767
- for (const info of discoveredTokens) {
768
- try {
769
- const token = new import_ethers2.Contract(info.address, ERC20_ABI, this.provider);
770
- const bal = await token.balanceOf(acctAddr);
771
- acctCollateral[info.symbol] = import_ethers2.ethers.formatUnits(bal, info.decimals);
772
- } catch (e) {
773
- console.warn(`[agether] AgentAccount collateral fetch failed for ${info.symbol}:`, e instanceof Error ? e.message : e);
774
- acctCollateral[info.symbol] = "0";
775
- }
776
- }
777
- result.agentAccount = {
778
- address: acctAddr,
779
- eth: import_ethers2.ethers.formatEther(acctEth),
780
- usdc: import_ethers2.ethers.formatUnits(acctUsdc, 6),
781
- collateral: acctCollateral
782
- };
783
- } catch (err) {
784
- if (err instanceof AgetherError && err.code === "NO_ACCOUNT") {
785
- } else {
786
- console.warn("[agether] getBalances: failed to fetch AgentAccount data:", err.message ?? err);
787
- }
788
- }
789
- return result;
790
- }
791
- /** Transfer USDC from EOA to AgentAccount. */
792
- async fundAccount(usdcAmount) {
793
- const acctAddr = await this.getAccountAddress();
794
- const usdc = new import_ethers2.Contract(this.config.contracts.usdc, ERC20_ABI, this._signer);
795
- const amount = import_ethers2.ethers.parseUnits(usdcAmount, 6);
796
- const tx = await usdc.transfer(acctAddr, amount);
797
- const receipt = await tx.wait();
798
- this._refreshSigner();
799
- return { tx: receipt.hash, amount: usdcAmount, agentAccount: acctAddr };
800
- }
801
- /**
802
- * Withdraw (transfer) a token from AgentAccount to EOA.
803
- * Executes an ERC-20 transfer via Safe UserOp.
804
- *
805
- * @param tokenSymbol - Token to withdraw (e.g. 'USDC', 'WETH', 'wstETH')
806
- * @param amount - Amount to withdraw (human-readable, e.g. '100' for 100 USDC, or 'all')
807
- */
808
- async withdrawToken(tokenSymbol, amount) {
809
- const acctAddr = await this.getAccountAddress();
810
- const eoaAddr = await this.getSignerAddress();
811
- const tokenInfo = await this._resolveToken(tokenSymbol);
812
- const tokenContract = new import_ethers2.Contract(tokenInfo.address, ERC20_ABI, this.provider);
813
- let weiAmount;
814
- if (amount === "all") {
815
- weiAmount = await tokenContract.balanceOf(acctAddr);
816
- if (weiAmount === 0n) throw new AgetherError(`No ${tokenSymbol} in AgentAccount`, "INSUFFICIENT_BALANCE");
817
- } else {
818
- weiAmount = import_ethers2.ethers.parseUnits(amount, tokenInfo.decimals);
819
- }
820
- const data = erc20Iface.encodeFunctionData("transfer", [eoaAddr, weiAmount]);
821
- const receipt = await this.exec(tokenInfo.address, data);
822
- const actualAmount = amount === "all" ? import_ethers2.ethers.formatUnits(weiAmount, tokenInfo.decimals) : amount;
823
- return { tx: receipt.hash, token: tokenSymbol, amount: actualAmount, destination: eoaAddr };
824
- }
825
- /**
826
- * Withdraw ETH from AgentAccount to EOA.
827
- * Executes a native ETH transfer via Safe UserOp.
828
- *
829
- * @param amount - ETH amount (e.g. '0.01' or 'all')
830
- */
831
- async withdrawEth(amount) {
832
- const acctAddr = await this.getAccountAddress();
833
- const eoaAddr = await this.getSignerAddress();
834
- let weiAmount;
835
- if (amount === "all") {
836
- weiAmount = await this.provider.getBalance(acctAddr);
837
- if (weiAmount === 0n) throw new AgetherError("No ETH in AgentAccount", "INSUFFICIENT_BALANCE");
838
- } else {
839
- weiAmount = import_ethers2.ethers.parseEther(amount);
840
- }
841
- const receipt = await this.exec(eoaAddr, "0x", weiAmount);
842
- const actualAmount = amount === "all" ? import_ethers2.ethers.formatEther(weiAmount) : amount;
843
- return { tx: receipt.hash, token: "ETH", amount: actualAmount, destination: eoaAddr };
844
- }
845
1083
  // ════════════════════════════════════════════════════════
846
1084
  // Market Discovery (Morpho GraphQL API)
847
1085
  // ════════════════════════════════════════════════════════
@@ -1020,7 +1258,7 @@ var MorphoClient = class {
1020
1258
  }
1021
1259
  }
1022
1260
  return {
1023
- agentId: this.agentId || "?",
1261
+ agentId: this.agentId,
1024
1262
  agentAccount: acctAddr,
1025
1263
  totalDebt: import_ethers2.ethers.formatUnits(totalDebt, 6),
1026
1264
  positions
@@ -1266,7 +1504,7 @@ var MorphoClient = class {
1266
1504
  const targets = [usdcAddr, morphoAddr];
1267
1505
  const values = [0n, 0n];
1268
1506
  const datas = [
1269
- erc20Iface.encodeFunctionData("approve", [morphoAddr, amount]),
1507
+ erc20Iface2.encodeFunctionData("approve", [morphoAddr, amount]),
1270
1508
  morphoIface.encodeFunctionData("supply", [
1271
1509
  this._toTuple(params),
1272
1510
  amount,
@@ -1498,7 +1736,7 @@ var MorphoClient = class {
1498
1736
  const targets = [colInfo.address, morphoAddr];
1499
1737
  const values = [0n, 0n];
1500
1738
  const datas = [
1501
- erc20Iface.encodeFunctionData("approve", [morphoAddr, weiAmount]),
1739
+ erc20Iface2.encodeFunctionData("approve", [morphoAddr, weiAmount]),
1502
1740
  morphoIface.encodeFunctionData("supplyCollateral", [
1503
1741
  this._toTuple(params),
1504
1742
  weiAmount,
@@ -1649,7 +1887,7 @@ var MorphoClient = class {
1649
1887
  const targets = [colInfo.address, morphoAddr, morphoAddr];
1650
1888
  const values = [0n, 0n, 0n];
1651
1889
  const datas = [
1652
- erc20Iface.encodeFunctionData("approve", [morphoAddr, colWei]),
1890
+ erc20Iface2.encodeFunctionData("approve", [morphoAddr, colWei]),
1653
1891
  morphoIface.encodeFunctionData("supplyCollateral", [
1654
1892
  this._toTuple(params),
1655
1893
  colWei,
@@ -1737,7 +1975,7 @@ var MorphoClient = class {
1737
1975
  const targets = [usdcAddr, morphoAddr];
1738
1976
  const values = [0n, 0n];
1739
1977
  const datas = [
1740
- erc20Iface.encodeFunctionData("approve", [morphoAddr, approveAmount]),
1978
+ erc20Iface2.encodeFunctionData("approve", [morphoAddr, approveAmount]),
1741
1979
  morphoIface.encodeFunctionData("repay", [
1742
1980
  this._toTuple(params),
1743
1981
  repayAssets,
@@ -1826,7 +2064,7 @@ var MorphoClient = class {
1826
2064
  const targets = [usdcAddr, morphoAddr, morphoAddr];
1827
2065
  const values = [0n, 0n, 0n];
1828
2066
  const datas = [
1829
- erc20Iface.encodeFunctionData("approve", [morphoAddr, dustApproveAmount]),
2067
+ erc20Iface2.encodeFunctionData("approve", [morphoAddr, dustApproveAmount]),
1830
2068
  morphoIface.encodeFunctionData("repay", [
1831
2069
  this._toTuple(params),
1832
2070
  0n,
@@ -1857,50 +2095,6 @@ var MorphoClient = class {
1857
2095
  destination: dest
1858
2096
  };
1859
2097
  }
1860
- /**
1861
- * Sponsor: transfer collateral to another agent's AgentAccount.
1862
- * (The agent must then supplyCollateral themselves via their own account.)
1863
- */
1864
- async sponsor(target, tokenSymbol, amount) {
1865
- const colInfo = await this._resolveToken(tokenSymbol);
1866
- let targetAddr;
1867
- if (target.address) {
1868
- targetAddr = target.address;
1869
- } else if (target.agentId) {
1870
- targetAddr = await this.agether4337Factory.getAccount(BigInt(target.agentId));
1871
- if (targetAddr === import_ethers2.ethers.ZeroAddress) throw new AgetherError("Target agent has no account", "NO_ACCOUNT");
1872
- } else {
1873
- throw new AgetherError("Provide agentId or address", "INVALID_TARGET");
1874
- }
1875
- const weiAmount = import_ethers2.ethers.parseUnits(amount, colInfo.decimals);
1876
- const colToken = new import_ethers2.Contract(colInfo.address, ERC20_ABI, this._signer);
1877
- const tx = await colToken.transfer(targetAddr, weiAmount);
1878
- const receipt = await tx.wait();
1879
- this._refreshSigner();
1880
- return { tx: receipt.hash, targetAccount: targetAddr, targetAgentId: target.agentId };
1881
- }
1882
- // ════════════════════════════════════════════════════════
1883
- // Reputation (Agether8004Scorer contract)
1884
- // ════════════════════════════════════════════════════════
1885
- async getCreditScore() {
1886
- if (!this.agentId) throw new AgetherError("agentId not set", "NO_AGENT_ID");
1887
- return this.agether8004Scorer.getCreditScore(BigInt(this.agentId));
1888
- }
1889
- async getAttestation() {
1890
- if (!this.agentId) throw new AgetherError("agentId not set", "NO_AGENT_ID");
1891
- const att = await this.agether8004Scorer.getAttestation(BigInt(this.agentId));
1892
- return { score: att.score, timestamp: att.timestamp, signer: att.signer };
1893
- }
1894
- async isEligible(minScore = 500n) {
1895
- if (!this.agentId) throw new AgetherError("agentId not set", "NO_AGENT_ID");
1896
- const [eligible, currentScore] = await this.agether8004Scorer.isEligible(BigInt(this.agentId), minScore);
1897
- return { eligible, currentScore };
1898
- }
1899
- async isScoreFresh() {
1900
- if (!this.agentId) throw new AgetherError("agentId not set", "NO_AGENT_ID");
1901
- const [fresh, age] = await this.agether8004Scorer.isScoreFresh(BigInt(this.agentId));
1902
- return { fresh, age };
1903
- }
1904
2098
  // ════════════════════════════════════════════════════════
1905
2099
  // Internal Helpers
1906
2100
  // ════════════════════════════════════════════════════════
@@ -1922,9 +2116,6 @@ var MorphoClient = class {
1922
2116
  const addrs = this.config.contracts;
1923
2117
  this.agether4337Factory = new import_ethers2.Contract(addrs.agether4337Factory, ACCOUNT_FACTORY_ABI, this._signer);
1924
2118
  this.entryPoint = new import_ethers2.Contract(addrs.entryPoint, ENTRYPOINT_V07_ABI, this._signer);
1925
- this.validationModule = new import_ethers2.Contract(addrs.erc8004ValidationModule, ERC8004_VALIDATION_MODULE_ABI, this.provider);
1926
- this.agether8004Scorer = new import_ethers2.Contract(addrs.agether8004Scorer, AGENT_REPUTATION_ABI, this._signer);
1927
- this.identityRegistry = new import_ethers2.Contract(addrs.identityRegistry, IDENTITY_REGISTRY_ABI, this._signer);
1928
2119
  } else {
1929
2120
  this.provider = new import_ethers2.ethers.JsonRpcProvider(this._rpcUrl);
1930
2121
  const wallet = new import_ethers2.ethers.Wallet(this._privateKey, this.provider);
@@ -1933,9 +2124,6 @@ var MorphoClient = class {
1933
2124
  const addrs = this.config.contracts;
1934
2125
  this.agether4337Factory = new import_ethers2.Contract(addrs.agether4337Factory, ACCOUNT_FACTORY_ABI, this._signer);
1935
2126
  this.entryPoint = new import_ethers2.Contract(addrs.entryPoint, ENTRYPOINT_V07_ABI, this._signer);
1936
- this.validationModule = new import_ethers2.Contract(addrs.erc8004ValidationModule, ERC8004_VALIDATION_MODULE_ABI, this.provider);
1937
- this.agether8004Scorer = new import_ethers2.Contract(addrs.agether8004Scorer, AGENT_REPUTATION_ABI, this._signer);
1938
- this.identityRegistry = new import_ethers2.Contract(addrs.identityRegistry, IDENTITY_REGISTRY_ABI, this._signer);
1939
2127
  }
1940
2128
  }
1941
2129
  // ────────────────────────────────────────────────────────────
@@ -2042,7 +2230,7 @@ var MorphoClient = class {
2042
2230
  const valueHex = import_ethers2.ethers.zeroPadValue(import_ethers2.ethers.toBeHex(value), 32);
2043
2231
  const executionCalldata = import_ethers2.ethers.concat([target, valueHex, data]);
2044
2232
  const safe7579Iface = new import_ethers2.ethers.Interface(SAFE7579_ACCOUNT_ABI);
2045
- const callData = safe7579Iface.encodeFunctionData("execute", [MODE_SINGLE, executionCalldata]);
2233
+ const callData = safe7579Iface.encodeFunctionData("execute", [MODE_SINGLE2, executionCalldata]);
2046
2234
  return this._submitUserOp(callData);
2047
2235
  }
2048
2236
  /**
@@ -2138,23 +2326,6 @@ var MorphoClient = class {
2138
2326
  "UNKNOWN_COLLATERAL"
2139
2327
  );
2140
2328
  }
2141
- /**
2142
- * Get all discovered collateral tokens (for balance iteration, etc.).
2143
- * Returns unique tokens from the Morpho API market discovery.
2144
- */
2145
- async _getDiscoveredTokens() {
2146
- await this.getMarkets();
2147
- const seen = /* @__PURE__ */ new Set();
2148
- const tokens = [];
2149
- for (const [key, info] of this._tokenCache) {
2150
- if (key.startsWith("0x")) continue;
2151
- if (seen.has(info.address.toLowerCase())) continue;
2152
- seen.add(info.address.toLowerCase());
2153
- if (info.symbol === "USDC" || info.symbol === "USDbC") continue;
2154
- tokens.push(info);
2155
- }
2156
- return tokens;
2157
- }
2158
2329
  /**
2159
2330
  * Compute net deposited amounts per market using Morpho GraphQL API.
2160
2331
  *