@agether/sdk 2.8.0 → 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.mjs CHANGED
@@ -2,13 +2,13 @@
2
2
  import { ethers, Contract } from "ethers";
3
3
 
4
4
  // src/types/index.ts
5
- var ChainId = /* @__PURE__ */ ((ChainId4) => {
6
- ChainId4[ChainId4["Ethereum"] = 1] = "Ethereum";
7
- ChainId4[ChainId4["Base"] = 8453] = "Base";
8
- ChainId4[ChainId4["BaseSepolia"] = 84532] = "BaseSepolia";
9
- ChainId4[ChainId4["Sepolia"] = 11155111] = "Sepolia";
10
- ChainId4[ChainId4["Hardhat"] = 31337] = "Hardhat";
11
- return ChainId4;
5
+ var ChainId = /* @__PURE__ */ ((ChainId3) => {
6
+ ChainId3[ChainId3["Ethereum"] = 1] = "Ethereum";
7
+ ChainId3[ChainId3["Base"] = 8453] = "Base";
8
+ ChainId3[ChainId3["BaseSepolia"] = 84532] = "BaseSepolia";
9
+ ChainId3[ChainId3["Sepolia"] = 11155111] = "Sepolia";
10
+ ChainId3[ChainId3["Hardhat"] = 31337] = "Hardhat";
11
+ return ChainId3;
12
12
  })(ChainId || {});
13
13
  var AgetherError = class extends Error {
14
14
  constructor(message, code, details) {
@@ -292,93 +292,246 @@ function getContractAddresses(chainId) {
292
292
  }
293
293
 
294
294
  // src/clients/AgetherClient.ts
295
+ var MODE_SINGLE = "0x0000000000000000000000000000000000000000000000000000000000000000";
296
+ var erc20Iface = new ethers.Interface(ERC20_ABI);
297
+ var KNOWN_TOKENS = {
298
+ [8453 /* Base */]: {
299
+ WETH: { address: "0x4200000000000000000000000000000000000006", symbol: "WETH", decimals: 18 },
300
+ wstETH: { address: "0xc1CBa3fCea344f92D9239c08C0568f6F2F0ee452", symbol: "wstETH", decimals: 18 },
301
+ cbETH: { address: "0x2Ae3F1Ec7F1F5012CFEab0185bfc7aa3cf0DEc22", symbol: "cbETH", decimals: 18 }
302
+ },
303
+ [1 /* Ethereum */]: {
304
+ WETH: { address: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", symbol: "WETH", decimals: 18 },
305
+ wstETH: { address: "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0", symbol: "wstETH", decimals: 18 },
306
+ cbETH: { address: "0xBe9895146f7AF43049ca1c1AE358B0541Ea49704", symbol: "cbETH", decimals: 18 }
307
+ }
308
+ };
295
309
  var AgetherClient = class _AgetherClient {
296
310
  constructor(options) {
297
311
  this.config = options.config;
298
312
  this.signer = options.signer;
299
313
  this.agentId = options.agentId;
314
+ this._rpcUrl = options.config.rpcUrl;
315
+ if (options._privateKey) {
316
+ this._privateKey = options._privateKey;
317
+ this._useExternalSigner = false;
318
+ } else {
319
+ this._useExternalSigner = true;
320
+ }
300
321
  const provider = options.signer.provider;
301
322
  if (!provider) throw new AgetherError("Signer must have a provider", "NO_PROVIDER");
302
- this.agether4337Factory = new Contract(
303
- options.config.contracts.agether4337Factory,
304
- AGETHER_4337_FACTORY_ABI,
305
- options.signer
306
- );
307
- this.identityRegistry = new Contract(
308
- options.config.contracts.identityRegistry,
309
- IDENTITY_REGISTRY_ABI,
310
- provider
311
- );
312
- this.agether8004Scorer = new Contract(
313
- options.config.contracts.agether8004Scorer,
314
- AGETHER_8004_SCORER_ABI,
315
- provider
316
- );
317
- this.validationModule = new Contract(
318
- options.config.contracts.erc8004ValidationModule,
319
- AGETHER_8004_VALIDATION_MODULE_ABI,
320
- provider
321
- );
323
+ if ("address" in options.signer && typeof options.signer.address === "string") {
324
+ this._eoaAddress = options.signer.address;
325
+ }
326
+ const c = options.config.contracts;
327
+ this.agether4337Factory = new Contract(c.agether4337Factory, AGETHER_4337_FACTORY_ABI, options.signer);
328
+ this.identityRegistry = new Contract(c.identityRegistry, IDENTITY_REGISTRY_ABI, options.signer);
329
+ this.agether8004Scorer = new Contract(c.agether8004Scorer, AGETHER_8004_SCORER_ABI, provider);
330
+ this.validationModule = new Contract(c.erc8004ValidationModule, AGETHER_8004_VALIDATION_MODULE_ABI, provider);
331
+ this.entryPoint = new Contract(c.entryPoint, ENTRYPOINT_V07_ABI, options.signer);
322
332
  }
323
- // Static Factory
324
- static fromPrivateKey(privateKey, agentId, chainIdOrConfig) {
325
- const config = typeof chainIdOrConfig === "number" ? getDefaultConfig(chainIdOrConfig) : chainIdOrConfig;
333
+ static fromPrivateKey(privateKey, agentIdOrChain, chainIdOrConfig) {
334
+ let agentId;
335
+ let config;
336
+ if (typeof agentIdOrChain === "bigint") {
337
+ agentId = agentIdOrChain;
338
+ config = typeof chainIdOrConfig === "number" ? getDefaultConfig(chainIdOrConfig) : chainIdOrConfig;
339
+ } else {
340
+ config = typeof agentIdOrChain === "number" ? getDefaultConfig(agentIdOrChain) : agentIdOrChain;
341
+ }
326
342
  const provider = new ethers.JsonRpcProvider(config.rpcUrl);
327
343
  const signer = new ethers.Wallet(privateKey, provider);
328
- return new _AgetherClient({ config, signer, agentId });
344
+ return new _AgetherClient({ config, signer, agentId, _privateKey: privateKey });
345
+ }
346
+ // ════════════════════════════════════════════════════════
347
+ // Registration
348
+ // ════════════════════════════════════════════════════════
349
+ /**
350
+ * Register: create ERC-8004 identity + Safe account in one flow.
351
+ * If already registered, returns existing state.
352
+ *
353
+ * Sets `this.agentId` on success so subsequent operations work immediately.
354
+ */
355
+ async register() {
356
+ const eoaAddr = await this._getSignerAddress();
357
+ if (this.agentId !== void 0) {
358
+ const exists = await this.agether4337Factory.accountExists(this.agentId);
359
+ if (exists) {
360
+ const acct = await this.agether4337Factory.getAccount(this.agentId);
361
+ this.accountAddress = acct;
362
+ const kyaRequired2 = await this.isKyaRequired();
363
+ return {
364
+ agentId: this.agentId.toString(),
365
+ address: eoaAddr,
366
+ agentAccount: acct,
367
+ alreadyRegistered: true,
368
+ kyaRequired: kyaRequired2
369
+ };
370
+ }
371
+ }
372
+ let agentId;
373
+ if (this.agentId !== void 0) {
374
+ const balance = await this.identityRegistry.balanceOf(eoaAddr);
375
+ if (balance > 0n) {
376
+ agentId = this.agentId;
377
+ } else {
378
+ agentId = await this._mintNewIdentity();
379
+ }
380
+ } else {
381
+ agentId = await this._mintNewIdentity();
382
+ }
383
+ this.agentId = agentId;
384
+ const acctExists = await this.agether4337Factory.accountExists(agentId);
385
+ let txHash;
386
+ if (!acctExists) {
387
+ const tx = await this.agether4337Factory.createAccount(agentId);
388
+ const receipt = await tx.wait();
389
+ this._refreshSigner();
390
+ txHash = receipt.hash;
391
+ }
392
+ const acctAddr = await this.agether4337Factory.getAccount(agentId);
393
+ this.accountAddress = acctAddr;
394
+ const kyaRequired = await this.isKyaRequired();
395
+ return {
396
+ agentId: agentId.toString(),
397
+ address: eoaAddr,
398
+ agentAccount: acctAddr,
399
+ alreadyRegistered: acctExists,
400
+ kyaRequired,
401
+ tx: txHash
402
+ };
329
403
  }
330
- // Account Management
404
+ /** Mint a new ERC-8004 identity and return the agentId. */
405
+ async _mintNewIdentity() {
406
+ const regTx = await this.identityRegistry.register();
407
+ const regReceipt = await regTx.wait();
408
+ this._refreshSigner();
409
+ let agentId = 0n;
410
+ for (const log of regReceipt.logs) {
411
+ try {
412
+ const parsed = this.identityRegistry.interface.parseLog({
413
+ topics: log.topics,
414
+ data: log.data
415
+ });
416
+ if (parsed?.name === "Transfer") {
417
+ agentId = parsed.args[2];
418
+ break;
419
+ }
420
+ } catch (e) {
421
+ console.warn("[agether] parseLog skip:", e instanceof Error ? e.message : e);
422
+ continue;
423
+ }
424
+ }
425
+ if (agentId === 0n) {
426
+ throw new AgetherError("Failed to parse agentId from registration", "PARSE_ERROR");
427
+ }
428
+ return agentId;
429
+ }
430
+ // ════════════════════════════════════════════════════════
431
+ // Account Management
432
+ // ════════════════════════════════════════════════════════
433
+ /**
434
+ * Deploy a Safe account smart wallet for the agent.
435
+ * The caller must own the ERC-8004 NFT.
436
+ */
331
437
  async createAccount() {
332
- const tx = await this.agether4337Factory.createAccount(this.agentId);
438
+ const id = this._requireAgentId();
439
+ const tx = await this.agether4337Factory.createAccount(id);
333
440
  const receipt = await tx.wait();
441
+ this._refreshSigner();
334
442
  const event = receipt.logs.map((log) => {
335
443
  try {
336
444
  return this.agether4337Factory.interface.parseLog(log);
337
- } catch (e) {
338
- console.warn("[agether] createAccount parseLog skip:", e instanceof Error ? e.message : e);
445
+ } catch {
339
446
  return null;
340
447
  }
341
448
  }).find((e) => e?.name === "AccountCreated");
342
449
  if (event) {
343
450
  this.accountAddress = event.args.safeAccount;
344
451
  } else {
345
- this.accountAddress = await this.agether4337Factory.getAccount(this.agentId);
452
+ this.accountAddress = await this.agether4337Factory.getAccount(id);
346
453
  }
347
454
  return this.accountAddress;
348
455
  }
456
+ /** Get the Safe account address for the current agent. Cached after first call. */
349
457
  async getAccountAddress() {
350
458
  if (this.accountAddress) return this.accountAddress;
351
- const addr = await this.agether4337Factory.getAccount(this.agentId);
459
+ const id = this._requireAgentId();
460
+ const addr = await this.agether4337Factory.getAccount(id);
352
461
  if (addr === ethers.ZeroAddress) {
353
- throw new AgetherError("No account found. Create one with createAccount().", "NO_ACCOUNT");
462
+ throw new AgetherError(
463
+ "No account found. Create one with createAccount() or register().",
464
+ "NO_ACCOUNT"
465
+ );
354
466
  }
355
467
  this.accountAddress = addr;
356
468
  return addr;
357
469
  }
470
+ /** Check whether the Safe account has been deployed. */
358
471
  async accountExists() {
359
- return this.agether4337Factory.accountExists(this.agentId);
472
+ const id = this._requireAgentId();
473
+ return this.agether4337Factory.accountExists(id);
360
474
  }
361
- // Balances
475
+ // ════════════════════════════════════════════════════════
476
+ // Balances
477
+ // ════════════════════════════════════════════════════════
478
+ /**
479
+ * Get ETH, USDC, and collateral token balances for EOA and Safe account.
480
+ *
481
+ * Collateral tokens are resolved from a built-in registry of well-known
482
+ * tokens per chain (WETH, wstETH, cbETH).
483
+ */
362
484
  async getBalances() {
363
485
  const provider = this.signer.provider;
364
- const eoaAddr = await this.signer.getAddress();
486
+ const eoaAddr = await this._getSignerAddress();
365
487
  const usdc = new Contract(this.config.contracts.usdc, ERC20_ABI, provider);
366
488
  const ethBal = await provider.getBalance(eoaAddr);
367
489
  const usdcBal = await usdc.balanceOf(eoaAddr);
490
+ const knownTokens = KNOWN_TOKENS[this.config.chainId] ?? {};
491
+ const eoaCollateral = {};
492
+ for (const [symbol, info] of Object.entries(knownTokens)) {
493
+ try {
494
+ const token = new Contract(info.address, ERC20_ABI, provider);
495
+ const bal = await token.balanceOf(eoaAddr);
496
+ eoaCollateral[symbol] = ethers.formatUnits(bal, info.decimals);
497
+ } catch (e) {
498
+ console.warn(`[agether] EOA collateral fetch failed for ${symbol}:`, e instanceof Error ? e.message : e);
499
+ eoaCollateral[symbol] = "0";
500
+ }
501
+ }
368
502
  const result = {
369
- eoa: { eth: ethers.formatEther(ethBal), usdc: ethers.formatUnits(usdcBal, 6) }
503
+ agentId: this.agentId !== void 0 ? this.agentId.toString() : "?",
504
+ address: eoaAddr,
505
+ eth: ethers.formatEther(ethBal),
506
+ usdc: ethers.formatUnits(usdcBal, 6),
507
+ collateral: eoaCollateral
370
508
  };
371
509
  try {
372
510
  const acctAddr = await this.getAccountAddress();
373
511
  const acctEth = await provider.getBalance(acctAddr);
374
512
  const acctUsdc = await usdc.balanceOf(acctAddr);
375
- result.account = {
513
+ const acctCollateral = {};
514
+ for (const [symbol, info] of Object.entries(knownTokens)) {
515
+ try {
516
+ const token = new Contract(info.address, ERC20_ABI, provider);
517
+ const bal = await token.balanceOf(acctAddr);
518
+ acctCollateral[symbol] = ethers.formatUnits(bal, info.decimals);
519
+ } catch (e) {
520
+ console.warn(`[agether] Account collateral fetch failed for ${symbol}:`, e instanceof Error ? e.message : e);
521
+ acctCollateral[symbol] = "0";
522
+ }
523
+ }
524
+ result.agentAccount = {
376
525
  address: acctAddr,
377
526
  eth: ethers.formatEther(acctEth),
378
- usdc: ethers.formatUnits(acctUsdc, 6)
527
+ usdc: ethers.formatUnits(acctUsdc, 6),
528
+ collateral: acctCollateral
379
529
  };
380
530
  } catch (e) {
381
- console.warn("[agether] getBalances: no Safe account or fetch failed:", e instanceof Error ? e.message : e);
531
+ if (e instanceof AgetherError && (e.code === "NO_ACCOUNT" || e.code === "NO_AGENT_ID")) {
532
+ } else {
533
+ console.warn("[agether] getBalances: failed to fetch Safe account data:", e.message ?? e);
534
+ }
382
535
  }
383
536
  return result;
384
537
  }
@@ -392,6 +545,7 @@ var AgetherClient = class _AgetherClient {
392
545
  const amount = ethers.parseUnits(usdcAmount, 6);
393
546
  const tx = await usdc.transfer(acctAddr, amount);
394
547
  const receipt = await tx.wait();
548
+ this._refreshSigner();
395
549
  return {
396
550
  txHash: receipt.hash,
397
551
  blockNumber: receipt.blockNumber,
@@ -399,7 +553,89 @@ var AgetherClient = class _AgetherClient {
399
553
  gasUsed: receipt.gasUsed
400
554
  };
401
555
  }
402
- // Identity & Validation
556
+ // ════════════════════════════════════════════════════════
557
+ // Withdrawals (Safe → EOA via UserOps)
558
+ // ════════════════════════════════════════════════════════
559
+ /**
560
+ * Withdraw an ERC-20 token from Safe account to EOA.
561
+ * Executes a transfer via Safe UserOp.
562
+ *
563
+ * @param tokenSymbol - Token to withdraw (e.g. 'USDC', 'WETH', 'wstETH') or 0x address
564
+ * @param amount - Amount to withdraw (human-readable, e.g. '100', or 'all')
565
+ */
566
+ async withdrawToken(tokenSymbol, amount) {
567
+ const acctAddr = await this.getAccountAddress();
568
+ const eoaAddr = await this._getSignerAddress();
569
+ const tokenInfo = await this._resolveToken(tokenSymbol);
570
+ const tokenContract = new Contract(tokenInfo.address, ERC20_ABI, this.signer.provider);
571
+ let weiAmount;
572
+ if (amount === "all") {
573
+ weiAmount = await tokenContract.balanceOf(acctAddr);
574
+ if (weiAmount === 0n) {
575
+ throw new AgetherError(`No ${tokenInfo.symbol} in Safe account`, "INSUFFICIENT_BALANCE");
576
+ }
577
+ } else {
578
+ weiAmount = ethers.parseUnits(amount, tokenInfo.decimals);
579
+ }
580
+ const data = erc20Iface.encodeFunctionData("transfer", [eoaAddr, weiAmount]);
581
+ const receipt = await this._exec(tokenInfo.address, data);
582
+ const actualAmount = amount === "all" ? ethers.formatUnits(weiAmount, tokenInfo.decimals) : amount;
583
+ return { tx: receipt.hash, token: tokenInfo.symbol, amount: actualAmount, destination: eoaAddr };
584
+ }
585
+ /**
586
+ * Withdraw ETH from Safe account to EOA.
587
+ * Executes a native ETH transfer via Safe UserOp.
588
+ *
589
+ * @param amount - ETH amount (e.g. '0.01' or 'all')
590
+ */
591
+ async withdrawEth(amount) {
592
+ const acctAddr = await this.getAccountAddress();
593
+ const eoaAddr = await this._getSignerAddress();
594
+ let weiAmount;
595
+ if (amount === "all") {
596
+ weiAmount = await this.signer.provider.getBalance(acctAddr);
597
+ if (weiAmount === 0n) throw new AgetherError("No ETH in Safe account", "INSUFFICIENT_BALANCE");
598
+ } else {
599
+ weiAmount = ethers.parseEther(amount);
600
+ }
601
+ const receipt = await this._exec(eoaAddr, "0x", weiAmount);
602
+ const actualAmount = amount === "all" ? ethers.formatEther(weiAmount) : amount;
603
+ return { tx: receipt.hash, token: "ETH", amount: actualAmount, destination: eoaAddr };
604
+ }
605
+ // ════════════════════════════════════════════════════════
606
+ // Sponsorship
607
+ // ════════════════════════════════════════════════════════
608
+ /**
609
+ * Send tokens to another agent's Safe account (or any address).
610
+ * Transfers from EOA (does NOT require a UserOp).
611
+ *
612
+ * @param target - `{ agentId: '42' }` or `{ address: '0x...' }`
613
+ * @param tokenSymbol - Token to send (e.g. 'WETH', 'USDC') or 0x address
614
+ * @param amount - Amount to send (human-readable)
615
+ */
616
+ async sponsor(target, tokenSymbol, amount) {
617
+ const tokenInfo = await this._resolveToken(tokenSymbol);
618
+ let targetAddr;
619
+ if (target.address) {
620
+ targetAddr = target.address;
621
+ } else if (target.agentId) {
622
+ targetAddr = await this.agether4337Factory.getAccount(BigInt(target.agentId));
623
+ if (targetAddr === ethers.ZeroAddress) {
624
+ throw new AgetherError("Target agent has no account", "NO_ACCOUNT");
625
+ }
626
+ } else {
627
+ throw new AgetherError("Provide agentId or address", "INVALID_TARGET");
628
+ }
629
+ const weiAmount = ethers.parseUnits(amount, tokenInfo.decimals);
630
+ const tokenContract = new Contract(tokenInfo.address, ERC20_ABI, this.signer);
631
+ const tx = await tokenContract.transfer(targetAddr, weiAmount);
632
+ const receipt = await tx.wait();
633
+ this._refreshSigner();
634
+ return { tx: receipt.hash, targetAccount: targetAddr, targetAgentId: target.agentId };
635
+ }
636
+ // ════════════════════════════════════════════════════════
637
+ // Identity & Validation
638
+ // ════════════════════════════════════════════════════════
403
639
  /**
404
640
  * Check if the KYA gate is active on the validation module.
405
641
  * If validationRegistry is not set, all txs pass (KYA disabled).
@@ -424,31 +660,45 @@ var AgetherClient = class _AgetherClient {
424
660
  return false;
425
661
  }
426
662
  }
663
+ /** Check whether the agent's ERC-8004 NFT exists. */
427
664
  async identityExists() {
665
+ const id = this._requireAgentId();
428
666
  try {
429
- await this.identityRegistry.ownerOf(this.agentId);
667
+ await this.identityRegistry.ownerOf(id);
430
668
  return true;
431
669
  } catch (e) {
432
670
  console.warn("[agether] identityExists check failed:", e instanceof Error ? e.message : e);
433
671
  return false;
434
672
  }
435
673
  }
674
+ /** Get the owner address of the ERC-8004 NFT. */
436
675
  async getIdentityOwner() {
437
- return this.identityRegistry.ownerOf(this.agentId);
676
+ const id = this._requireAgentId();
677
+ return this.identityRegistry.ownerOf(id);
438
678
  }
439
- // Reputation
679
+ // ════════════════════════════════════════════════════════
680
+ // Reputation
681
+ // ════════════════════════════════════════════════════════
682
+ /** Read the agent's current credit score from the Agether8004Scorer contract. */
440
683
  async getCreditScore() {
441
- return this.agether8004Scorer.getCreditScore(this.agentId);
684
+ const id = this._requireAgentId();
685
+ return this.agether8004Scorer.getCreditScore(id);
442
686
  }
687
+ /** Check if the score is fresh (within MAX_ORACLE_AGE). */
443
688
  async isScoreFresh() {
444
- const [fresh, age] = await this.agether8004Scorer.isScoreFresh(this.agentId);
689
+ const id = this._requireAgentId();
690
+ const [fresh, age] = await this.agether8004Scorer.isScoreFresh(id);
445
691
  return { fresh, age };
446
692
  }
693
+ /** Check if the agent meets a minimum score threshold. */
447
694
  async isEligible(minScore = 500n) {
448
- const [eligible, currentScore] = await this.agether8004Scorer.isEligible(this.agentId, minScore);
695
+ const id = this._requireAgentId();
696
+ const [eligible, currentScore] = await this.agether8004Scorer.isEligible(id, minScore);
449
697
  return { eligible, currentScore };
450
698
  }
451
- // Getters
699
+ // ════════════════════════════════════════════════════════
700
+ // Getters
701
+ // ════════════════════════════════════════════════════════
452
702
  get chainId() {
453
703
  return this.config.chainId;
454
704
  }
@@ -462,24 +712,209 @@ var AgetherClient = class _AgetherClient {
462
712
  return this.signer;
463
713
  }
464
714
  getAgentId() {
715
+ return this._requireAgentId();
716
+ }
717
+ // ════════════════════════════════════════════════════════
718
+ // Private Helpers
719
+ // ════════════════════════════════════════════════════════
720
+ /** Require agentId to be set, throw a helpful error otherwise. */
721
+ _requireAgentId() {
722
+ if (this.agentId === void 0) {
723
+ throw new AgetherError("agentId not set. Call register() first.", "NO_AGENT_ID");
724
+ }
465
725
  return this.agentId;
466
726
  }
727
+ /** Resolve EOA signer address (async, cached). */
728
+ async _getSignerAddress() {
729
+ if (!this._eoaAddress) {
730
+ this._eoaAddress = await this.signer.getAddress();
731
+ }
732
+ return this._eoaAddress;
733
+ }
734
+ /**
735
+ * Resolve a token symbol or address to { address, symbol, decimals }.
736
+ *
737
+ * Supports:
738
+ * - `'USDC'` → from chain config
739
+ * - Well-known symbols (`'WETH'`, `'wstETH'`, `'cbETH'`) → built-in per-chain registry
740
+ * - `'0x...'` address → reads decimals and symbol onchain
741
+ */
742
+ async _resolveToken(symbolOrAddress) {
743
+ if (symbolOrAddress.toUpperCase() === "USDC") {
744
+ return { address: this.config.contracts.usdc, symbol: "USDC", decimals: 6 };
745
+ }
746
+ const chainTokens = KNOWN_TOKENS[this.config.chainId] ?? {};
747
+ const bySymbol = chainTokens[symbolOrAddress] || chainTokens[symbolOrAddress.toUpperCase()];
748
+ if (bySymbol) return bySymbol;
749
+ if (symbolOrAddress.startsWith("0x") && symbolOrAddress.length === 42) {
750
+ try {
751
+ const token = new Contract(
752
+ symbolOrAddress,
753
+ ["function decimals() view returns (uint8)", "function symbol() view returns (string)"],
754
+ this.signer.provider
755
+ );
756
+ const [decimals, symbol] = await Promise.all([token.decimals(), token.symbol()]);
757
+ return { address: symbolOrAddress, symbol, decimals: Number(decimals) };
758
+ } catch (e) {
759
+ throw new AgetherError(
760
+ `Failed to read token at ${symbolOrAddress}: ${e instanceof Error ? e.message : e}`,
761
+ "UNKNOWN_TOKEN"
762
+ );
763
+ }
764
+ }
765
+ throw new AgetherError(
766
+ `Unknown token: ${symbolOrAddress}. Use a known symbol (USDC, WETH, wstETH, cbETH) or a 0x address.`,
767
+ "UNKNOWN_TOKEN"
768
+ );
769
+ }
770
+ /**
771
+ * Refresh signer and rebind contracts for fresh nonce.
772
+ *
773
+ * For the privateKey path: recreates provider + wallet.
774
+ * For external signers: just rebinds contract instances.
775
+ */
776
+ _refreshSigner() {
777
+ if (!this._useExternalSigner && this._privateKey) {
778
+ const provider = new ethers.JsonRpcProvider(this._rpcUrl);
779
+ const wallet = new ethers.Wallet(this._privateKey, provider);
780
+ this.signer = wallet;
781
+ this._eoaAddress = wallet.address;
782
+ }
783
+ const c = this.config.contracts;
784
+ this.agether4337Factory = new Contract(c.agether4337Factory, AGETHER_4337_FACTORY_ABI, this.signer);
785
+ this.identityRegistry = new Contract(c.identityRegistry, IDENTITY_REGISTRY_ABI, this.signer);
786
+ this.agether8004Scorer = new Contract(c.agether8004Scorer, AGETHER_8004_SCORER_ABI, this.signer.provider);
787
+ this.validationModule = new Contract(c.erc8004ValidationModule, AGETHER_8004_VALIDATION_MODULE_ABI, this.signer.provider);
788
+ this.entryPoint = new Contract(c.entryPoint, ENTRYPOINT_V07_ABI, this.signer);
789
+ }
790
+ // ────────────────────────────────────────────────────────
791
+ // ERC-4337 UserOp helpers (Safe + Safe7579 + EntryPoint v0.7)
792
+ // ────────────────────────────────────────────────────────
793
+ /**
794
+ * Pack two uint128 values into a single bytes32:
795
+ * bytes32 = (hi << 128) | lo
796
+ */
797
+ _packUint128(hi, lo) {
798
+ return ethers.zeroPadValue(ethers.toBeHex(hi << 128n | lo), 32);
799
+ }
800
+ /**
801
+ * Build, sign and submit a PackedUserOperation through EntryPoint.handleOps.
802
+ */
803
+ async _submitUserOp(callData) {
804
+ const sender = await this.getAccountAddress();
805
+ const eoaAddr = await this._getSignerAddress();
806
+ const validatorAddr = this.config.contracts.erc8004ValidationModule;
807
+ const nonceKey = BigInt(validatorAddr) << 32n;
808
+ const nonce = await this.entryPoint.getNonce(sender, nonceKey);
809
+ const feeData = await this.signer.provider.getFeeData();
810
+ const maxFeePerGas = feeData.maxFeePerGas ?? ethers.parseUnits("0.5", "gwei");
811
+ const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas ?? ethers.parseUnits("0.1", "gwei");
812
+ const verificationGasLimit = 500000n;
813
+ const callGasLimit = 800000n;
814
+ const preVerificationGas = 100000n;
815
+ const accountGasLimits = this._packUint128(verificationGasLimit, callGasLimit);
816
+ const gasFees = this._packUint128(maxPriorityFeePerGas, maxFeePerGas);
817
+ const requiredPrefund = (verificationGasLimit + callGasLimit + preVerificationGas) * maxFeePerGas;
818
+ const accountBalance = await this.signer.provider.getBalance(sender);
819
+ if (accountBalance < requiredPrefund) {
820
+ const topUp = requiredPrefund - accountBalance;
821
+ const topUpWithBuffer = topUp * 120n / 100n;
822
+ const fundTx = await this.signer.sendTransaction({
823
+ to: sender,
824
+ value: topUpWithBuffer
825
+ });
826
+ await fundTx.wait();
827
+ this._refreshSigner();
828
+ }
829
+ const userOp = {
830
+ sender,
831
+ nonce,
832
+ initCode: "0x",
833
+ callData,
834
+ accountGasLimits,
835
+ preVerificationGas,
836
+ gasFees,
837
+ paymasterAndData: "0x",
838
+ signature: "0x"
839
+ };
840
+ const userOpHash = await this.entryPoint.getUserOpHash(userOp);
841
+ const signature = await this.signer.signMessage(ethers.getBytes(userOpHash));
842
+ userOp.signature = signature;
843
+ const tx = await this.entryPoint.handleOps([userOp], eoaAddr);
844
+ const receipt = await tx.wait();
845
+ this._refreshSigner();
846
+ const epIface = new ethers.Interface(ENTRYPOINT_V07_ABI);
847
+ for (const log of receipt.logs) {
848
+ try {
849
+ const parsed = epIface.parseLog({ topics: log.topics, data: log.data });
850
+ if (parsed?.name === "UserOperationEvent" && !parsed.args.success) {
851
+ let revertMsg = "UserOp inner execution reverted";
852
+ for (const rLog of receipt.logs) {
853
+ try {
854
+ const rParsed = epIface.parseLog({ topics: rLog.topics, data: rLog.data });
855
+ if (rParsed?.name === "UserOperationRevertReason") {
856
+ const reason = rParsed.args.revertReason;
857
+ try {
858
+ if (reason.length >= 10 && reason.slice(0, 10) === "0x08c379a0") {
859
+ const decoded = ethers.AbiCoder.defaultAbiCoder().decode(
860
+ ["string"],
861
+ "0x" + reason.slice(10)
862
+ );
863
+ revertMsg = `UserOp reverted: ${decoded[0]}`;
864
+ } else {
865
+ revertMsg = `UserOp reverted with data: ${reason}`;
866
+ }
867
+ } catch {
868
+ revertMsg = `UserOp reverted with data: ${reason}`;
869
+ }
870
+ break;
871
+ }
872
+ } catch {
873
+ continue;
874
+ }
875
+ }
876
+ throw new AgetherError(revertMsg, "USEROP_EXECUTION_FAILED");
877
+ }
878
+ } catch (e) {
879
+ if (e instanceof AgetherError) throw e;
880
+ continue;
881
+ }
882
+ }
883
+ return receipt;
884
+ }
885
+ /**
886
+ * Execute a single call via Safe7579 account (ERC-7579 single mode)
887
+ * through an ERC-4337 UserOperation.
888
+ */
889
+ async _exec(target, data, value = 0n) {
890
+ const valueHex = ethers.zeroPadValue(ethers.toBeHex(value), 32);
891
+ const executionCalldata = ethers.concat([target, valueHex, data]);
892
+ const safe7579Iface = new ethers.Interface(SAFE7579_ACCOUNT_ABI);
893
+ const callData = safe7579Iface.encodeFunctionData("execute", [MODE_SINGLE, executionCalldata]);
894
+ return this._submitUserOp(callData);
895
+ }
467
896
  };
468
897
 
469
898
  // src/clients/MorphoClient.ts
470
899
  import { ethers as ethers2, Contract as Contract2 } from "ethers";
471
900
  import axios from "axios";
472
901
  var MORPHO_API_URL = "https://api.morpho.org/graphql";
473
- var MODE_SINGLE = "0x0000000000000000000000000000000000000000000000000000000000000000";
902
+ var MODE_SINGLE2 = "0x0000000000000000000000000000000000000000000000000000000000000000";
474
903
  var MODE_BATCH = "0x0100000000000000000000000000000000000000000000000000000000000000";
475
904
  var morphoIface = new ethers2.Interface(MORPHO_BLUE_ABI);
476
- var erc20Iface = new ethers2.Interface(ERC20_ABI);
905
+ var erc20Iface2 = new ethers2.Interface(ERC20_ABI);
477
906
  var MorphoClient = class {
478
907
  constructor(config) {
479
908
  this._marketCache = /* @__PURE__ */ new Map();
480
909
  /** Dynamic token registry: symbol (uppercase) → { address, symbol, decimals } */
481
910
  this._tokenCache = /* @__PURE__ */ new Map();
482
911
  this._discoveredAt = 0;
912
+ if (!config.agentId) {
913
+ throw new AgetherError(
914
+ "agentId is required. Use AgetherClient.register() first to get an agentId.",
915
+ "NO_AGENT_ID"
916
+ );
917
+ }
483
918
  const chainId = config.chainId ?? 1 /* Ethereum */;
484
919
  const defaultCfg = getDefaultConfig(chainId);
485
920
  this.config = defaultCfg;
@@ -509,26 +944,7 @@ var MorphoClient = class {
509
944
  const addrs = { ...defaultCfg.contracts, ...config.contracts };
510
945
  this.agether4337Factory = new Contract2(addrs.agether4337Factory, ACCOUNT_FACTORY_ABI, this._signer);
511
946
  this.morphoBlue = new Contract2(addrs.morphoBlue, MORPHO_BLUE_ABI, this.provider);
512
- this.agether8004Scorer = new Contract2(addrs.agether8004Scorer, AGENT_REPUTATION_ABI, this._signer);
513
- this.identityRegistry = new Contract2(addrs.identityRegistry, IDENTITY_REGISTRY_ABI, this._signer);
514
947
  this.entryPoint = new Contract2(addrs.entryPoint, ENTRYPOINT_V07_ABI, this._signer);
515
- this.validationModule = new Contract2(addrs.erc8004ValidationModule, ERC8004_VALIDATION_MODULE_ABI, this.provider);
516
- }
517
- // ════════════════════════════════════════════════════════
518
- // KYA Gate Check
519
- // ════════════════════════════════════════════════════════
520
- /**
521
- * Check whether the KYA (Know Your Agent) code verification gate is active.
522
- * Reads the ERC8004ValidationModule's validationRegistry — when set to
523
- * a non-zero address, the module enforces KYA code approval.
524
- */
525
- async isKyaRequired() {
526
- try {
527
- const registryAddr = await this.validationModule.validationRegistry();
528
- return registryAddr !== ethers2.ZeroAddress;
529
- } catch {
530
- return false;
531
- }
532
948
  }
533
949
  // ════════════════════════════════════════════════════════
534
950
  // Account Management
@@ -536,7 +952,6 @@ var MorphoClient = class {
536
952
  /** Resolve the AgentAccount address (cached, with retry for flaky RPCs). */
537
953
  async getAccountAddress() {
538
954
  if (this._accountAddress) return this._accountAddress;
539
- if (!this.agentId) throw new AgetherError("agentId not set", "NO_AGENT_ID");
540
955
  const MAX_RETRIES = 3;
541
956
  let lastErr;
542
957
  for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
@@ -558,7 +973,6 @@ var MorphoClient = class {
558
973
  throw lastErr;
559
974
  }
560
975
  getAgentId() {
561
- if (!this.agentId) throw new AgetherError("agentId not set", "NO_AGENT_ID");
562
976
  return this.agentId;
563
977
  }
564
978
  /**
@@ -591,182 +1005,6 @@ var MorphoClient = class {
591
1005
  }
592
1006
  return this._eoaAddress;
593
1007
  }
594
- /** Mint a new ERC-8004 identity and return the agentId. */
595
- async _mintNewIdentity() {
596
- const regTx = await this.identityRegistry.register();
597
- const regReceipt = await regTx.wait();
598
- this._refreshSigner();
599
- let agentId = 0n;
600
- for (const log of regReceipt.logs) {
601
- try {
602
- const parsed = this.identityRegistry.interface.parseLog({ topics: log.topics, data: log.data });
603
- if (parsed?.name === "Transfer") {
604
- agentId = parsed.args[2];
605
- break;
606
- }
607
- } catch (e) {
608
- console.warn("[agether] parseLog skip:", e instanceof Error ? e.message : e);
609
- continue;
610
- }
611
- }
612
- if (agentId === 0n) throw new AgetherError("Failed to parse agentId from registration", "PARSE_ERROR");
613
- return agentId;
614
- }
615
- /**
616
- * Register: create ERC-8004 identity + AgentAccount in one flow.
617
- * If already registered, returns existing state.
618
- */
619
- async register(_name) {
620
- const eoaAddr = await this.getSignerAddress();
621
- if (this.agentId) {
622
- const exists = await this.agether4337Factory.accountExists(BigInt(this.agentId));
623
- if (exists) {
624
- const acct = await this.agether4337Factory.getAccount(BigInt(this.agentId));
625
- this._accountAddress = acct;
626
- const kyaRequired2 = await this.isKyaRequired();
627
- return { agentId: this.agentId, address: eoaAddr, agentAccount: acct, alreadyRegistered: true, kyaRequired: kyaRequired2 };
628
- }
629
- }
630
- let agentId;
631
- if (this.agentId) {
632
- const balance = await this.identityRegistry.balanceOf(eoaAddr);
633
- if (balance > 0n) {
634
- agentId = BigInt(this.agentId);
635
- } else {
636
- agentId = await this._mintNewIdentity();
637
- }
638
- } else {
639
- agentId = await this._mintNewIdentity();
640
- }
641
- this.agentId = agentId.toString();
642
- const acctExists = await this.agether4337Factory.accountExists(agentId);
643
- let txHash;
644
- if (!acctExists) {
645
- const tx = await this.agether4337Factory.createAccount(agentId);
646
- const receipt = await tx.wait();
647
- this._refreshSigner();
648
- txHash = receipt.hash;
649
- }
650
- const acctAddr = await this.agether4337Factory.getAccount(agentId);
651
- this._accountAddress = acctAddr;
652
- const kyaRequired = await this.isKyaRequired();
653
- return {
654
- agentId: this.agentId,
655
- address: eoaAddr,
656
- agentAccount: acctAddr,
657
- alreadyRegistered: acctExists,
658
- kyaRequired,
659
- tx: txHash
660
- };
661
- }
662
- /** Get ETH / USDC / collateral balances for EOA and AgentAccount. */
663
- async getBalances() {
664
- const eoaAddr = await this.getSignerAddress();
665
- const usdc = new Contract2(this.config.contracts.usdc, ERC20_ABI, this.provider);
666
- const ethBal = await this.provider.getBalance(eoaAddr);
667
- const usdcBal = await usdc.balanceOf(eoaAddr);
668
- const discoveredTokens = await this._getDiscoveredTokens();
669
- const eoaCollateral = {};
670
- for (const info of discoveredTokens) {
671
- try {
672
- const token = new Contract2(info.address, ERC20_ABI, this.provider);
673
- const bal = await token.balanceOf(eoaAddr);
674
- eoaCollateral[info.symbol] = ethers2.formatUnits(bal, info.decimals);
675
- } catch (e) {
676
- console.warn(`[agether] EOA collateral fetch failed for ${info.symbol}:`, e instanceof Error ? e.message : e);
677
- eoaCollateral[info.symbol] = "0";
678
- }
679
- }
680
- const result = {
681
- agentId: this.agentId || "?",
682
- address: eoaAddr,
683
- eth: ethers2.formatEther(ethBal),
684
- usdc: ethers2.formatUnits(usdcBal, 6),
685
- collateral: eoaCollateral
686
- };
687
- try {
688
- const acctAddr = await this.getAccountAddress();
689
- const acctEth = await this.provider.getBalance(acctAddr);
690
- const acctUsdc = await usdc.balanceOf(acctAddr);
691
- const acctCollateral = {};
692
- for (const info of discoveredTokens) {
693
- try {
694
- const token = new Contract2(info.address, ERC20_ABI, this.provider);
695
- const bal = await token.balanceOf(acctAddr);
696
- acctCollateral[info.symbol] = ethers2.formatUnits(bal, info.decimals);
697
- } catch (e) {
698
- console.warn(`[agether] AgentAccount collateral fetch failed for ${info.symbol}:`, e instanceof Error ? e.message : e);
699
- acctCollateral[info.symbol] = "0";
700
- }
701
- }
702
- result.agentAccount = {
703
- address: acctAddr,
704
- eth: ethers2.formatEther(acctEth),
705
- usdc: ethers2.formatUnits(acctUsdc, 6),
706
- collateral: acctCollateral
707
- };
708
- } catch (err) {
709
- if (err instanceof AgetherError && err.code === "NO_ACCOUNT") {
710
- } else {
711
- console.warn("[agether] getBalances: failed to fetch AgentAccount data:", err.message ?? err);
712
- }
713
- }
714
- return result;
715
- }
716
- /** Transfer USDC from EOA to AgentAccount. */
717
- async fundAccount(usdcAmount) {
718
- const acctAddr = await this.getAccountAddress();
719
- const usdc = new Contract2(this.config.contracts.usdc, ERC20_ABI, this._signer);
720
- const amount = ethers2.parseUnits(usdcAmount, 6);
721
- const tx = await usdc.transfer(acctAddr, amount);
722
- const receipt = await tx.wait();
723
- this._refreshSigner();
724
- return { tx: receipt.hash, amount: usdcAmount, agentAccount: acctAddr };
725
- }
726
- /**
727
- * Withdraw (transfer) a token from AgentAccount to EOA.
728
- * Executes an ERC-20 transfer via Safe UserOp.
729
- *
730
- * @param tokenSymbol - Token to withdraw (e.g. 'USDC', 'WETH', 'wstETH')
731
- * @param amount - Amount to withdraw (human-readable, e.g. '100' for 100 USDC, or 'all')
732
- */
733
- async withdrawToken(tokenSymbol, amount) {
734
- const acctAddr = await this.getAccountAddress();
735
- const eoaAddr = await this.getSignerAddress();
736
- const tokenInfo = await this._resolveToken(tokenSymbol);
737
- const tokenContract = new Contract2(tokenInfo.address, ERC20_ABI, this.provider);
738
- let weiAmount;
739
- if (amount === "all") {
740
- weiAmount = await tokenContract.balanceOf(acctAddr);
741
- if (weiAmount === 0n) throw new AgetherError(`No ${tokenSymbol} in AgentAccount`, "INSUFFICIENT_BALANCE");
742
- } else {
743
- weiAmount = ethers2.parseUnits(amount, tokenInfo.decimals);
744
- }
745
- const data = erc20Iface.encodeFunctionData("transfer", [eoaAddr, weiAmount]);
746
- const receipt = await this.exec(tokenInfo.address, data);
747
- const actualAmount = amount === "all" ? ethers2.formatUnits(weiAmount, tokenInfo.decimals) : amount;
748
- return { tx: receipt.hash, token: tokenSymbol, amount: actualAmount, destination: eoaAddr };
749
- }
750
- /**
751
- * Withdraw ETH from AgentAccount to EOA.
752
- * Executes a native ETH transfer via Safe UserOp.
753
- *
754
- * @param amount - ETH amount (e.g. '0.01' or 'all')
755
- */
756
- async withdrawEth(amount) {
757
- const acctAddr = await this.getAccountAddress();
758
- const eoaAddr = await this.getSignerAddress();
759
- let weiAmount;
760
- if (amount === "all") {
761
- weiAmount = await this.provider.getBalance(acctAddr);
762
- if (weiAmount === 0n) throw new AgetherError("No ETH in AgentAccount", "INSUFFICIENT_BALANCE");
763
- } else {
764
- weiAmount = ethers2.parseEther(amount);
765
- }
766
- const receipt = await this.exec(eoaAddr, "0x", weiAmount);
767
- const actualAmount = amount === "all" ? ethers2.formatEther(weiAmount) : amount;
768
- return { tx: receipt.hash, token: "ETH", amount: actualAmount, destination: eoaAddr };
769
- }
770
1008
  // ════════════════════════════════════════════════════════
771
1009
  // Market Discovery (Morpho GraphQL API)
772
1010
  // ════════════════════════════════════════════════════════
@@ -945,7 +1183,7 @@ var MorphoClient = class {
945
1183
  }
946
1184
  }
947
1185
  return {
948
- agentId: this.agentId || "?",
1186
+ agentId: this.agentId,
949
1187
  agentAccount: acctAddr,
950
1188
  totalDebt: ethers2.formatUnits(totalDebt, 6),
951
1189
  positions
@@ -1191,7 +1429,7 @@ var MorphoClient = class {
1191
1429
  const targets = [usdcAddr, morphoAddr];
1192
1430
  const values = [0n, 0n];
1193
1431
  const datas = [
1194
- erc20Iface.encodeFunctionData("approve", [morphoAddr, amount]),
1432
+ erc20Iface2.encodeFunctionData("approve", [morphoAddr, amount]),
1195
1433
  morphoIface.encodeFunctionData("supply", [
1196
1434
  this._toTuple(params),
1197
1435
  amount,
@@ -1423,7 +1661,7 @@ var MorphoClient = class {
1423
1661
  const targets = [colInfo.address, morphoAddr];
1424
1662
  const values = [0n, 0n];
1425
1663
  const datas = [
1426
- erc20Iface.encodeFunctionData("approve", [morphoAddr, weiAmount]),
1664
+ erc20Iface2.encodeFunctionData("approve", [morphoAddr, weiAmount]),
1427
1665
  morphoIface.encodeFunctionData("supplyCollateral", [
1428
1666
  this._toTuple(params),
1429
1667
  weiAmount,
@@ -1574,7 +1812,7 @@ var MorphoClient = class {
1574
1812
  const targets = [colInfo.address, morphoAddr, morphoAddr];
1575
1813
  const values = [0n, 0n, 0n];
1576
1814
  const datas = [
1577
- erc20Iface.encodeFunctionData("approve", [morphoAddr, colWei]),
1815
+ erc20Iface2.encodeFunctionData("approve", [morphoAddr, colWei]),
1578
1816
  morphoIface.encodeFunctionData("supplyCollateral", [
1579
1817
  this._toTuple(params),
1580
1818
  colWei,
@@ -1662,7 +1900,7 @@ var MorphoClient = class {
1662
1900
  const targets = [usdcAddr, morphoAddr];
1663
1901
  const values = [0n, 0n];
1664
1902
  const datas = [
1665
- erc20Iface.encodeFunctionData("approve", [morphoAddr, approveAmount]),
1903
+ erc20Iface2.encodeFunctionData("approve", [morphoAddr, approveAmount]),
1666
1904
  morphoIface.encodeFunctionData("repay", [
1667
1905
  this._toTuple(params),
1668
1906
  repayAssets,
@@ -1751,7 +1989,7 @@ var MorphoClient = class {
1751
1989
  const targets = [usdcAddr, morphoAddr, morphoAddr];
1752
1990
  const values = [0n, 0n, 0n];
1753
1991
  const datas = [
1754
- erc20Iface.encodeFunctionData("approve", [morphoAddr, dustApproveAmount]),
1992
+ erc20Iface2.encodeFunctionData("approve", [morphoAddr, dustApproveAmount]),
1755
1993
  morphoIface.encodeFunctionData("repay", [
1756
1994
  this._toTuple(params),
1757
1995
  0n,
@@ -1782,50 +2020,6 @@ var MorphoClient = class {
1782
2020
  destination: dest
1783
2021
  };
1784
2022
  }
1785
- /**
1786
- * Sponsor: transfer collateral to another agent's AgentAccount.
1787
- * (The agent must then supplyCollateral themselves via their own account.)
1788
- */
1789
- async sponsor(target, tokenSymbol, amount) {
1790
- const colInfo = await this._resolveToken(tokenSymbol);
1791
- let targetAddr;
1792
- if (target.address) {
1793
- targetAddr = target.address;
1794
- } else if (target.agentId) {
1795
- targetAddr = await this.agether4337Factory.getAccount(BigInt(target.agentId));
1796
- if (targetAddr === ethers2.ZeroAddress) throw new AgetherError("Target agent has no account", "NO_ACCOUNT");
1797
- } else {
1798
- throw new AgetherError("Provide agentId or address", "INVALID_TARGET");
1799
- }
1800
- const weiAmount = ethers2.parseUnits(amount, colInfo.decimals);
1801
- const colToken = new Contract2(colInfo.address, ERC20_ABI, this._signer);
1802
- const tx = await colToken.transfer(targetAddr, weiAmount);
1803
- const receipt = await tx.wait();
1804
- this._refreshSigner();
1805
- return { tx: receipt.hash, targetAccount: targetAddr, targetAgentId: target.agentId };
1806
- }
1807
- // ════════════════════════════════════════════════════════
1808
- // Reputation (Agether8004Scorer contract)
1809
- // ════════════════════════════════════════════════════════
1810
- async getCreditScore() {
1811
- if (!this.agentId) throw new AgetherError("agentId not set", "NO_AGENT_ID");
1812
- return this.agether8004Scorer.getCreditScore(BigInt(this.agentId));
1813
- }
1814
- async getAttestation() {
1815
- if (!this.agentId) throw new AgetherError("agentId not set", "NO_AGENT_ID");
1816
- const att = await this.agether8004Scorer.getAttestation(BigInt(this.agentId));
1817
- return { score: att.score, timestamp: att.timestamp, signer: att.signer };
1818
- }
1819
- async isEligible(minScore = 500n) {
1820
- if (!this.agentId) throw new AgetherError("agentId not set", "NO_AGENT_ID");
1821
- const [eligible, currentScore] = await this.agether8004Scorer.isEligible(BigInt(this.agentId), minScore);
1822
- return { eligible, currentScore };
1823
- }
1824
- async isScoreFresh() {
1825
- if (!this.agentId) throw new AgetherError("agentId not set", "NO_AGENT_ID");
1826
- const [fresh, age] = await this.agether8004Scorer.isScoreFresh(BigInt(this.agentId));
1827
- return { fresh, age };
1828
- }
1829
2023
  // ════════════════════════════════════════════════════════
1830
2024
  // Internal Helpers
1831
2025
  // ════════════════════════════════════════════════════════
@@ -1847,9 +2041,6 @@ var MorphoClient = class {
1847
2041
  const addrs = this.config.contracts;
1848
2042
  this.agether4337Factory = new Contract2(addrs.agether4337Factory, ACCOUNT_FACTORY_ABI, this._signer);
1849
2043
  this.entryPoint = new Contract2(addrs.entryPoint, ENTRYPOINT_V07_ABI, this._signer);
1850
- this.validationModule = new Contract2(addrs.erc8004ValidationModule, ERC8004_VALIDATION_MODULE_ABI, this.provider);
1851
- this.agether8004Scorer = new Contract2(addrs.agether8004Scorer, AGENT_REPUTATION_ABI, this._signer);
1852
- this.identityRegistry = new Contract2(addrs.identityRegistry, IDENTITY_REGISTRY_ABI, this._signer);
1853
2044
  } else {
1854
2045
  this.provider = new ethers2.JsonRpcProvider(this._rpcUrl);
1855
2046
  const wallet = new ethers2.Wallet(this._privateKey, this.provider);
@@ -1858,9 +2049,6 @@ var MorphoClient = class {
1858
2049
  const addrs = this.config.contracts;
1859
2050
  this.agether4337Factory = new Contract2(addrs.agether4337Factory, ACCOUNT_FACTORY_ABI, this._signer);
1860
2051
  this.entryPoint = new Contract2(addrs.entryPoint, ENTRYPOINT_V07_ABI, this._signer);
1861
- this.validationModule = new Contract2(addrs.erc8004ValidationModule, ERC8004_VALIDATION_MODULE_ABI, this.provider);
1862
- this.agether8004Scorer = new Contract2(addrs.agether8004Scorer, AGENT_REPUTATION_ABI, this._signer);
1863
- this.identityRegistry = new Contract2(addrs.identityRegistry, IDENTITY_REGISTRY_ABI, this._signer);
1864
2052
  }
1865
2053
  }
1866
2054
  // ────────────────────────────────────────────────────────────
@@ -1967,7 +2155,7 @@ var MorphoClient = class {
1967
2155
  const valueHex = ethers2.zeroPadValue(ethers2.toBeHex(value), 32);
1968
2156
  const executionCalldata = ethers2.concat([target, valueHex, data]);
1969
2157
  const safe7579Iface = new ethers2.Interface(SAFE7579_ACCOUNT_ABI);
1970
- const callData = safe7579Iface.encodeFunctionData("execute", [MODE_SINGLE, executionCalldata]);
2158
+ const callData = safe7579Iface.encodeFunctionData("execute", [MODE_SINGLE2, executionCalldata]);
1971
2159
  return this._submitUserOp(callData);
1972
2160
  }
1973
2161
  /**
@@ -2063,23 +2251,6 @@ var MorphoClient = class {
2063
2251
  "UNKNOWN_COLLATERAL"
2064
2252
  );
2065
2253
  }
2066
- /**
2067
- * Get all discovered collateral tokens (for balance iteration, etc.).
2068
- * Returns unique tokens from the Morpho API market discovery.
2069
- */
2070
- async _getDiscoveredTokens() {
2071
- await this.getMarkets();
2072
- const seen = /* @__PURE__ */ new Set();
2073
- const tokens = [];
2074
- for (const [key, info] of this._tokenCache) {
2075
- if (key.startsWith("0x")) continue;
2076
- if (seen.has(info.address.toLowerCase())) continue;
2077
- seen.add(info.address.toLowerCase());
2078
- if (info.symbol === "USDC" || info.symbol === "USDbC") continue;
2079
- tokens.push(info);
2080
- }
2081
- return tokens;
2082
- }
2083
2254
  /**
2084
2255
  * Compute net deposited amounts per market using Morpho GraphQL API.
2085
2256
  *