@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/cli.js CHANGED
@@ -47,7 +47,7 @@ var init_types = __esm({
47
47
  });
48
48
 
49
49
  // src/utils/abis.ts
50
- var IDENTITY_REGISTRY_ABI, AGETHER_4337_FACTORY_ABI, ACCOUNT_FACTORY_ABI, AGETHER_8004_VALIDATION_MODULE_ABI, ERC8004_VALIDATION_MODULE_ABI, AGETHER_8004_SCORER_ABI, AGENT_REPUTATION_ABI, MORPHO_BLUE_ABI, ERC20_ABI, ENTRYPOINT_V07_ABI, SAFE7579_ACCOUNT_ABI;
50
+ var IDENTITY_REGISTRY_ABI, AGETHER_4337_FACTORY_ABI, ACCOUNT_FACTORY_ABI, AGETHER_8004_VALIDATION_MODULE_ABI, AGETHER_8004_SCORER_ABI, MORPHO_BLUE_ABI, ERC20_ABI, ENTRYPOINT_V07_ABI, SAFE7579_ACCOUNT_ABI;
51
51
  var init_abis = __esm({
52
52
  "src/utils/abis.ts"() {
53
53
  "use strict";
@@ -87,7 +87,6 @@ var init_abis = __esm({
87
87
  // Admin (via TimelockController)
88
88
  "function setValidationRegistry(address registry_)"
89
89
  ];
90
- ERC8004_VALIDATION_MODULE_ABI = AGETHER_8004_VALIDATION_MODULE_ABI;
91
90
  AGETHER_8004_SCORER_ABI = [
92
91
  "function getCreditScore(uint256 agentId) view returns (uint256)",
93
92
  "function getAttestation(uint256 agentId) view returns (tuple(uint256 score, uint256 timestamp, address signer))",
@@ -98,7 +97,6 @@ var init_abis = __esm({
98
97
  "function setOracleSigner(address signer_)",
99
98
  "event ScoreUpdated(uint256 indexed agentId, uint256 score, uint256 timestamp, address signer)"
100
99
  ];
101
- AGENT_REPUTATION_ABI = AGETHER_8004_SCORER_ABI;
102
100
  MORPHO_BLUE_ABI = [
103
101
  // Supply & Withdraw (lending side)
104
102
  "function supply(tuple(address loanToken, address collateralToken, address oracle, address irm, uint256 lltv) marketParams, uint256 assets, uint256 shares, address onBehalf, bytes data) returns (uint256 assetsSupplied, uint256 sharesSupplied)",
@@ -294,6 +292,12 @@ var init_MorphoClient = __esm({
294
292
  /** Dynamic token registry: symbol (uppercase) → { address, symbol, decimals } */
295
293
  this._tokenCache = /* @__PURE__ */ new Map();
296
294
  this._discoveredAt = 0;
295
+ if (!config.agentId) {
296
+ throw new AgetherError(
297
+ "agentId is required. Use AgetherClient.register() first to get an agentId.",
298
+ "NO_AGENT_ID"
299
+ );
300
+ }
297
301
  const chainId = config.chainId ?? 1 /* Ethereum */;
298
302
  const defaultCfg = getDefaultConfig(chainId);
299
303
  this.config = defaultCfg;
@@ -323,26 +327,7 @@ var init_MorphoClient = __esm({
323
327
  const addrs = { ...defaultCfg.contracts, ...config.contracts };
324
328
  this.agether4337Factory = new import_ethers.Contract(addrs.agether4337Factory, ACCOUNT_FACTORY_ABI, this._signer);
325
329
  this.morphoBlue = new import_ethers.Contract(addrs.morphoBlue, MORPHO_BLUE_ABI, this.provider);
326
- this.agether8004Scorer = new import_ethers.Contract(addrs.agether8004Scorer, AGENT_REPUTATION_ABI, this._signer);
327
- this.identityRegistry = new import_ethers.Contract(addrs.identityRegistry, IDENTITY_REGISTRY_ABI, this._signer);
328
330
  this.entryPoint = new import_ethers.Contract(addrs.entryPoint, ENTRYPOINT_V07_ABI, this._signer);
329
- this.validationModule = new import_ethers.Contract(addrs.erc8004ValidationModule, ERC8004_VALIDATION_MODULE_ABI, this.provider);
330
- }
331
- // ════════════════════════════════════════════════════════
332
- // KYA Gate Check
333
- // ════════════════════════════════════════════════════════
334
- /**
335
- * Check whether the KYA (Know Your Agent) code verification gate is active.
336
- * Reads the ERC8004ValidationModule's validationRegistry — when set to
337
- * a non-zero address, the module enforces KYA code approval.
338
- */
339
- async isKyaRequired() {
340
- try {
341
- const registryAddr = await this.validationModule.validationRegistry();
342
- return registryAddr !== import_ethers.ethers.ZeroAddress;
343
- } catch {
344
- return false;
345
- }
346
331
  }
347
332
  // ════════════════════════════════════════════════════════
348
333
  // Account Management
@@ -350,7 +335,6 @@ var init_MorphoClient = __esm({
350
335
  /** Resolve the AgentAccount address (cached, with retry for flaky RPCs). */
351
336
  async getAccountAddress() {
352
337
  if (this._accountAddress) return this._accountAddress;
353
- if (!this.agentId) throw new AgetherError("agentId not set", "NO_AGENT_ID");
354
338
  const MAX_RETRIES = 3;
355
339
  let lastErr;
356
340
  for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
@@ -372,7 +356,6 @@ var init_MorphoClient = __esm({
372
356
  throw lastErr;
373
357
  }
374
358
  getAgentId() {
375
- if (!this.agentId) throw new AgetherError("agentId not set", "NO_AGENT_ID");
376
359
  return this.agentId;
377
360
  }
378
361
  /**
@@ -405,182 +388,6 @@ var init_MorphoClient = __esm({
405
388
  }
406
389
  return this._eoaAddress;
407
390
  }
408
- /** Mint a new ERC-8004 identity and return the agentId. */
409
- async _mintNewIdentity() {
410
- const regTx = await this.identityRegistry.register();
411
- const regReceipt = await regTx.wait();
412
- this._refreshSigner();
413
- let agentId = 0n;
414
- for (const log of regReceipt.logs) {
415
- try {
416
- const parsed = this.identityRegistry.interface.parseLog({ topics: log.topics, data: log.data });
417
- if (parsed?.name === "Transfer") {
418
- agentId = parsed.args[2];
419
- break;
420
- }
421
- } catch (e) {
422
- console.warn("[agether] parseLog skip:", e instanceof Error ? e.message : e);
423
- continue;
424
- }
425
- }
426
- if (agentId === 0n) throw new AgetherError("Failed to parse agentId from registration", "PARSE_ERROR");
427
- return agentId;
428
- }
429
- /**
430
- * Register: create ERC-8004 identity + AgentAccount in one flow.
431
- * If already registered, returns existing state.
432
- */
433
- async register(_name) {
434
- const eoaAddr = await this.getSignerAddress();
435
- if (this.agentId) {
436
- const exists = await this.agether4337Factory.accountExists(BigInt(this.agentId));
437
- if (exists) {
438
- const acct = await this.agether4337Factory.getAccount(BigInt(this.agentId));
439
- this._accountAddress = acct;
440
- const kyaRequired2 = await this.isKyaRequired();
441
- return { agentId: this.agentId, address: eoaAddr, agentAccount: acct, alreadyRegistered: true, kyaRequired: kyaRequired2 };
442
- }
443
- }
444
- let agentId;
445
- if (this.agentId) {
446
- const balance = await this.identityRegistry.balanceOf(eoaAddr);
447
- if (balance > 0n) {
448
- agentId = BigInt(this.agentId);
449
- } else {
450
- agentId = await this._mintNewIdentity();
451
- }
452
- } else {
453
- agentId = await this._mintNewIdentity();
454
- }
455
- this.agentId = agentId.toString();
456
- const acctExists = await this.agether4337Factory.accountExists(agentId);
457
- let txHash;
458
- if (!acctExists) {
459
- const tx = await this.agether4337Factory.createAccount(agentId);
460
- const receipt = await tx.wait();
461
- this._refreshSigner();
462
- txHash = receipt.hash;
463
- }
464
- const acctAddr = await this.agether4337Factory.getAccount(agentId);
465
- this._accountAddress = acctAddr;
466
- const kyaRequired = await this.isKyaRequired();
467
- return {
468
- agentId: this.agentId,
469
- address: eoaAddr,
470
- agentAccount: acctAddr,
471
- alreadyRegistered: acctExists,
472
- kyaRequired,
473
- tx: txHash
474
- };
475
- }
476
- /** Get ETH / USDC / collateral balances for EOA and AgentAccount. */
477
- async getBalances() {
478
- const eoaAddr = await this.getSignerAddress();
479
- const usdc = new import_ethers.Contract(this.config.contracts.usdc, ERC20_ABI, this.provider);
480
- const ethBal = await this.provider.getBalance(eoaAddr);
481
- const usdcBal = await usdc.balanceOf(eoaAddr);
482
- const discoveredTokens = await this._getDiscoveredTokens();
483
- const eoaCollateral = {};
484
- for (const info of discoveredTokens) {
485
- try {
486
- const token = new import_ethers.Contract(info.address, ERC20_ABI, this.provider);
487
- const bal = await token.balanceOf(eoaAddr);
488
- eoaCollateral[info.symbol] = import_ethers.ethers.formatUnits(bal, info.decimals);
489
- } catch (e) {
490
- console.warn(`[agether] EOA collateral fetch failed for ${info.symbol}:`, e instanceof Error ? e.message : e);
491
- eoaCollateral[info.symbol] = "0";
492
- }
493
- }
494
- const result = {
495
- agentId: this.agentId || "?",
496
- address: eoaAddr,
497
- eth: import_ethers.ethers.formatEther(ethBal),
498
- usdc: import_ethers.ethers.formatUnits(usdcBal, 6),
499
- collateral: eoaCollateral
500
- };
501
- try {
502
- const acctAddr = await this.getAccountAddress();
503
- const acctEth = await this.provider.getBalance(acctAddr);
504
- const acctUsdc = await usdc.balanceOf(acctAddr);
505
- const acctCollateral = {};
506
- for (const info of discoveredTokens) {
507
- try {
508
- const token = new import_ethers.Contract(info.address, ERC20_ABI, this.provider);
509
- const bal = await token.balanceOf(acctAddr);
510
- acctCollateral[info.symbol] = import_ethers.ethers.formatUnits(bal, info.decimals);
511
- } catch (e) {
512
- console.warn(`[agether] AgentAccount collateral fetch failed for ${info.symbol}:`, e instanceof Error ? e.message : e);
513
- acctCollateral[info.symbol] = "0";
514
- }
515
- }
516
- result.agentAccount = {
517
- address: acctAddr,
518
- eth: import_ethers.ethers.formatEther(acctEth),
519
- usdc: import_ethers.ethers.formatUnits(acctUsdc, 6),
520
- collateral: acctCollateral
521
- };
522
- } catch (err) {
523
- if (err instanceof AgetherError && err.code === "NO_ACCOUNT") {
524
- } else {
525
- console.warn("[agether] getBalances: failed to fetch AgentAccount data:", err.message ?? err);
526
- }
527
- }
528
- return result;
529
- }
530
- /** Transfer USDC from EOA to AgentAccount. */
531
- async fundAccount(usdcAmount) {
532
- const acctAddr = await this.getAccountAddress();
533
- const usdc = new import_ethers.Contract(this.config.contracts.usdc, ERC20_ABI, this._signer);
534
- const amount = import_ethers.ethers.parseUnits(usdcAmount, 6);
535
- const tx = await usdc.transfer(acctAddr, amount);
536
- const receipt = await tx.wait();
537
- this._refreshSigner();
538
- return { tx: receipt.hash, amount: usdcAmount, agentAccount: acctAddr };
539
- }
540
- /**
541
- * Withdraw (transfer) a token from AgentAccount to EOA.
542
- * Executes an ERC-20 transfer via Safe UserOp.
543
- *
544
- * @param tokenSymbol - Token to withdraw (e.g. 'USDC', 'WETH', 'wstETH')
545
- * @param amount - Amount to withdraw (human-readable, e.g. '100' for 100 USDC, or 'all')
546
- */
547
- async withdrawToken(tokenSymbol, amount) {
548
- const acctAddr = await this.getAccountAddress();
549
- const eoaAddr = await this.getSignerAddress();
550
- const tokenInfo = await this._resolveToken(tokenSymbol);
551
- const tokenContract = new import_ethers.Contract(tokenInfo.address, ERC20_ABI, this.provider);
552
- let weiAmount;
553
- if (amount === "all") {
554
- weiAmount = await tokenContract.balanceOf(acctAddr);
555
- if (weiAmount === 0n) throw new AgetherError(`No ${tokenSymbol} in AgentAccount`, "INSUFFICIENT_BALANCE");
556
- } else {
557
- weiAmount = import_ethers.ethers.parseUnits(amount, tokenInfo.decimals);
558
- }
559
- const data = erc20Iface.encodeFunctionData("transfer", [eoaAddr, weiAmount]);
560
- const receipt = await this.exec(tokenInfo.address, data);
561
- const actualAmount = amount === "all" ? import_ethers.ethers.formatUnits(weiAmount, tokenInfo.decimals) : amount;
562
- return { tx: receipt.hash, token: tokenSymbol, amount: actualAmount, destination: eoaAddr };
563
- }
564
- /**
565
- * Withdraw ETH from AgentAccount to EOA.
566
- * Executes a native ETH transfer via Safe UserOp.
567
- *
568
- * @param amount - ETH amount (e.g. '0.01' or 'all')
569
- */
570
- async withdrawEth(amount) {
571
- const acctAddr = await this.getAccountAddress();
572
- const eoaAddr = await this.getSignerAddress();
573
- let weiAmount;
574
- if (amount === "all") {
575
- weiAmount = await this.provider.getBalance(acctAddr);
576
- if (weiAmount === 0n) throw new AgetherError("No ETH in AgentAccount", "INSUFFICIENT_BALANCE");
577
- } else {
578
- weiAmount = import_ethers.ethers.parseEther(amount);
579
- }
580
- const receipt = await this.exec(eoaAddr, "0x", weiAmount);
581
- const actualAmount = amount === "all" ? import_ethers.ethers.formatEther(weiAmount) : amount;
582
- return { tx: receipt.hash, token: "ETH", amount: actualAmount, destination: eoaAddr };
583
- }
584
391
  // ════════════════════════════════════════════════════════
585
392
  // Market Discovery (Morpho GraphQL API)
586
393
  // ════════════════════════════════════════════════════════
@@ -759,7 +566,7 @@ var init_MorphoClient = __esm({
759
566
  }
760
567
  }
761
568
  return {
762
- agentId: this.agentId || "?",
569
+ agentId: this.agentId,
763
570
  agentAccount: acctAddr,
764
571
  totalDebt: import_ethers.ethers.formatUnits(totalDebt, 6),
765
572
  positions
@@ -1596,50 +1403,6 @@ var init_MorphoClient = __esm({
1596
1403
  destination: dest
1597
1404
  };
1598
1405
  }
1599
- /**
1600
- * Sponsor: transfer collateral to another agent's AgentAccount.
1601
- * (The agent must then supplyCollateral themselves via their own account.)
1602
- */
1603
- async sponsor(target, tokenSymbol, amount) {
1604
- const colInfo = await this._resolveToken(tokenSymbol);
1605
- let targetAddr;
1606
- if (target.address) {
1607
- targetAddr = target.address;
1608
- } else if (target.agentId) {
1609
- targetAddr = await this.agether4337Factory.getAccount(BigInt(target.agentId));
1610
- if (targetAddr === import_ethers.ethers.ZeroAddress) throw new AgetherError("Target agent has no account", "NO_ACCOUNT");
1611
- } else {
1612
- throw new AgetherError("Provide agentId or address", "INVALID_TARGET");
1613
- }
1614
- const weiAmount = import_ethers.ethers.parseUnits(amount, colInfo.decimals);
1615
- const colToken = new import_ethers.Contract(colInfo.address, ERC20_ABI, this._signer);
1616
- const tx = await colToken.transfer(targetAddr, weiAmount);
1617
- const receipt = await tx.wait();
1618
- this._refreshSigner();
1619
- return { tx: receipt.hash, targetAccount: targetAddr, targetAgentId: target.agentId };
1620
- }
1621
- // ════════════════════════════════════════════════════════
1622
- // Reputation (Agether8004Scorer contract)
1623
- // ════════════════════════════════════════════════════════
1624
- async getCreditScore() {
1625
- if (!this.agentId) throw new AgetherError("agentId not set", "NO_AGENT_ID");
1626
- return this.agether8004Scorer.getCreditScore(BigInt(this.agentId));
1627
- }
1628
- async getAttestation() {
1629
- if (!this.agentId) throw new AgetherError("agentId not set", "NO_AGENT_ID");
1630
- const att = await this.agether8004Scorer.getAttestation(BigInt(this.agentId));
1631
- return { score: att.score, timestamp: att.timestamp, signer: att.signer };
1632
- }
1633
- async isEligible(minScore = 500n) {
1634
- if (!this.agentId) throw new AgetherError("agentId not set", "NO_AGENT_ID");
1635
- const [eligible, currentScore] = await this.agether8004Scorer.isEligible(BigInt(this.agentId), minScore);
1636
- return { eligible, currentScore };
1637
- }
1638
- async isScoreFresh() {
1639
- if (!this.agentId) throw new AgetherError("agentId not set", "NO_AGENT_ID");
1640
- const [fresh, age] = await this.agether8004Scorer.isScoreFresh(BigInt(this.agentId));
1641
- return { fresh, age };
1642
- }
1643
1406
  // ════════════════════════════════════════════════════════
1644
1407
  // Internal Helpers
1645
1408
  // ════════════════════════════════════════════════════════
@@ -1661,9 +1424,6 @@ var init_MorphoClient = __esm({
1661
1424
  const addrs = this.config.contracts;
1662
1425
  this.agether4337Factory = new import_ethers.Contract(addrs.agether4337Factory, ACCOUNT_FACTORY_ABI, this._signer);
1663
1426
  this.entryPoint = new import_ethers.Contract(addrs.entryPoint, ENTRYPOINT_V07_ABI, this._signer);
1664
- this.validationModule = new import_ethers.Contract(addrs.erc8004ValidationModule, ERC8004_VALIDATION_MODULE_ABI, this.provider);
1665
- this.agether8004Scorer = new import_ethers.Contract(addrs.agether8004Scorer, AGENT_REPUTATION_ABI, this._signer);
1666
- this.identityRegistry = new import_ethers.Contract(addrs.identityRegistry, IDENTITY_REGISTRY_ABI, this._signer);
1667
1427
  } else {
1668
1428
  this.provider = new import_ethers.ethers.JsonRpcProvider(this._rpcUrl);
1669
1429
  const wallet = new import_ethers.ethers.Wallet(this._privateKey, this.provider);
@@ -1672,9 +1432,6 @@ var init_MorphoClient = __esm({
1672
1432
  const addrs = this.config.contracts;
1673
1433
  this.agether4337Factory = new import_ethers.Contract(addrs.agether4337Factory, ACCOUNT_FACTORY_ABI, this._signer);
1674
1434
  this.entryPoint = new import_ethers.Contract(addrs.entryPoint, ENTRYPOINT_V07_ABI, this._signer);
1675
- this.validationModule = new import_ethers.Contract(addrs.erc8004ValidationModule, ERC8004_VALIDATION_MODULE_ABI, this.provider);
1676
- this.agether8004Scorer = new import_ethers.Contract(addrs.agether8004Scorer, AGENT_REPUTATION_ABI, this._signer);
1677
- this.identityRegistry = new import_ethers.Contract(addrs.identityRegistry, IDENTITY_REGISTRY_ABI, this._signer);
1678
1435
  }
1679
1436
  }
1680
1437
  // ────────────────────────────────────────────────────────────
@@ -1877,23 +1634,6 @@ var init_MorphoClient = __esm({
1877
1634
  "UNKNOWN_COLLATERAL"
1878
1635
  );
1879
1636
  }
1880
- /**
1881
- * Get all discovered collateral tokens (for balance iteration, etc.).
1882
- * Returns unique tokens from the Morpho API market discovery.
1883
- */
1884
- async _getDiscoveredTokens() {
1885
- await this.getMarkets();
1886
- const seen = /* @__PURE__ */ new Set();
1887
- const tokens = [];
1888
- for (const [key, info] of this._tokenCache) {
1889
- if (key.startsWith("0x")) continue;
1890
- if (seen.has(info.address.toLowerCase())) continue;
1891
- seen.add(info.address.toLowerCase());
1892
- if (info.symbol === "USDC" || info.symbol === "USDbC") continue;
1893
- tokens.push(info);
1894
- }
1895
- return tokens;
1896
- }
1897
1637
  /**
1898
1638
  * Compute net deposited amounts per market using Morpho GraphQL API.
1899
1639
  *
@@ -1959,89 +1699,707 @@ var init_MorphoClient = __esm({
1959
1699
  }
1960
1700
  });
1961
1701
 
1962
- // src/clients/X402Client.ts
1963
- var X402Client_exports = {};
1964
- __export(X402Client_exports, {
1965
- X402Client: () => X402Client
1702
+ // src/clients/AgetherClient.ts
1703
+ var AgetherClient_exports = {};
1704
+ __export(AgetherClient_exports, {
1705
+ AgetherClient: () => AgetherClient
1966
1706
  });
1967
- var import_fetch, import_client, import_client2, import_accounts, X402Client;
1968
- var init_X402Client = __esm({
1969
- "src/clients/X402Client.ts"() {
1707
+ var import_ethers2, MODE_SINGLE2, erc20Iface2, KNOWN_TOKENS, AgetherClient;
1708
+ var init_AgetherClient = __esm({
1709
+ "src/clients/AgetherClient.ts"() {
1970
1710
  "use strict";
1971
- import_fetch = require("@x402/fetch");
1972
- import_client = require("@x402/core/client");
1973
- import_client2 = require("@x402/evm/exact/client");
1974
- import_accounts = require("viem/accounts");
1975
- X402Client = class {
1976
- constructor(config) {
1977
- this.config = config;
1978
- let baseSigner;
1979
- if ("walletClient" in config && config.walletClient) {
1980
- const wc = config.walletClient;
1981
- const account = wc.account;
1982
- if (!account) {
1983
- throw new Error(
1984
- "X402Client: walletClient must have an attached account. Pass an account when creating the WalletClient or use privateKey mode instead."
1985
- );
1986
- }
1987
- this.address = account.address;
1988
- baseSigner = {
1989
- address: account.address,
1990
- signTypedData: (msg) => wc.signTypedData({
1991
- account,
1992
- domain: msg.domain,
1993
- types: msg.types,
1994
- primaryType: msg.primaryType,
1995
- message: msg.message
1996
- })
1997
- };
1998
- } else if ("privateKey" in config && config.privateKey) {
1999
- const privateKey = config.privateKey.startsWith("0x") ? config.privateKey : `0x${config.privateKey}`;
2000
- const account = (0, import_accounts.privateKeyToAccount)(privateKey);
2001
- this.address = account.address;
2002
- baseSigner = account;
1711
+ import_ethers2 = require("ethers");
1712
+ init_types();
1713
+ init_abis();
1714
+ init_config();
1715
+ MODE_SINGLE2 = "0x0000000000000000000000000000000000000000000000000000000000000000";
1716
+ erc20Iface2 = new import_ethers2.ethers.Interface(ERC20_ABI);
1717
+ KNOWN_TOKENS = {
1718
+ [8453 /* Base */]: {
1719
+ WETH: { address: "0x4200000000000000000000000000000000000006", symbol: "WETH", decimals: 18 },
1720
+ wstETH: { address: "0xc1CBa3fCea344f92D9239c08C0568f6F2F0ee452", symbol: "wstETH", decimals: 18 },
1721
+ cbETH: { address: "0x2Ae3F1Ec7F1F5012CFEab0185bfc7aa3cf0DEc22", symbol: "cbETH", decimals: 18 }
1722
+ },
1723
+ [1 /* Ethereum */]: {
1724
+ WETH: { address: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", symbol: "WETH", decimals: 18 },
1725
+ wstETH: { address: "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0", symbol: "wstETH", decimals: 18 },
1726
+ cbETH: { address: "0xBe9895146f7AF43049ca1c1AE358B0541Ea49704", symbol: "cbETH", decimals: 18 }
1727
+ }
1728
+ };
1729
+ AgetherClient = class _AgetherClient {
1730
+ constructor(options) {
1731
+ this.config = options.config;
1732
+ this.signer = options.signer;
1733
+ this.agentId = options.agentId;
1734
+ this._rpcUrl = options.config.rpcUrl;
1735
+ if (options._privateKey) {
1736
+ this._privateKey = options._privateKey;
1737
+ this._useExternalSigner = false;
2003
1738
  } else {
2004
- throw new Error(
2005
- "X402Client: provide either privateKey or walletClient in config."
2006
- );
1739
+ this._useExternalSigner = true;
2007
1740
  }
2008
- let signer;
2009
- if (config.accountAddress) {
2010
- const accountAddr = config.accountAddress;
2011
- const inner = baseSigner;
2012
- signer = (0, import_accounts.toAccount)({
2013
- address: accountAddr,
2014
- async signMessage({ message }) {
2015
- if ("signMessage" in inner && typeof inner.signMessage === "function") {
2016
- return inner.signMessage({ message });
2017
- }
2018
- throw new Error("signMessage not supported by underlying signer");
2019
- },
2020
- async signTransaction(tx) {
2021
- if ("signTransaction" in inner && typeof inner.signTransaction === "function") {
2022
- return inner.signTransaction(tx);
2023
- }
2024
- throw new Error("signTransaction not supported by underlying signer");
2025
- },
2026
- async signTypedData(typedData) {
2027
- const sig = await inner.signTypedData(typedData);
2028
- if (config.validatorModule) {
2029
- const validatorHex = config.validatorModule.replace("0x", "").toLowerCase();
2030
- const sigHex = sig.replace("0x", "");
2031
- return `0x${validatorHex}${sigHex}`;
2032
- }
2033
- return `${sig}00`;
2034
- }
2035
- });
2036
- this.address = accountAddr;
1741
+ const provider = options.signer.provider;
1742
+ if (!provider) throw new AgetherError("Signer must have a provider", "NO_PROVIDER");
1743
+ if ("address" in options.signer && typeof options.signer.address === "string") {
1744
+ this._eoaAddress = options.signer.address;
1745
+ }
1746
+ const c = options.config.contracts;
1747
+ this.agether4337Factory = new import_ethers2.Contract(c.agether4337Factory, AGETHER_4337_FACTORY_ABI, options.signer);
1748
+ this.identityRegistry = new import_ethers2.Contract(c.identityRegistry, IDENTITY_REGISTRY_ABI, options.signer);
1749
+ this.agether8004Scorer = new import_ethers2.Contract(c.agether8004Scorer, AGETHER_8004_SCORER_ABI, provider);
1750
+ this.validationModule = new import_ethers2.Contract(c.erc8004ValidationModule, AGETHER_8004_VALIDATION_MODULE_ABI, provider);
1751
+ this.entryPoint = new import_ethers2.Contract(c.entryPoint, ENTRYPOINT_V07_ABI, options.signer);
1752
+ }
1753
+ static fromPrivateKey(privateKey, agentIdOrChain, chainIdOrConfig) {
1754
+ let agentId;
1755
+ let config;
1756
+ if (typeof agentIdOrChain === "bigint") {
1757
+ agentId = agentIdOrChain;
1758
+ config = typeof chainIdOrConfig === "number" ? getDefaultConfig(chainIdOrConfig) : chainIdOrConfig;
2037
1759
  } else {
2038
- signer = baseSigner;
1760
+ config = typeof agentIdOrChain === "number" ? getDefaultConfig(agentIdOrChain) : agentIdOrChain;
2039
1761
  }
2040
- const client = new import_client.x402Client();
2041
- (0, import_client2.registerExactEvmScheme)(client, { signer });
2042
- this.paidFetch = (0, import_fetch.wrapFetchWithPayment)(fetch, client);
2043
- const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
2044
- const dailyLimit = config.dailySpendLimitUsdc ? BigInt(Math.round(parseFloat(config.dailySpendLimitUsdc) * 1e6)) : 0n;
1762
+ const provider = new import_ethers2.ethers.JsonRpcProvider(config.rpcUrl);
1763
+ const signer = new import_ethers2.ethers.Wallet(privateKey, provider);
1764
+ return new _AgetherClient({ config, signer, agentId, _privateKey: privateKey });
1765
+ }
1766
+ // ════════════════════════════════════════════════════════
1767
+ // Registration
1768
+ // ════════════════════════════════════════════════════════
1769
+ /**
1770
+ * Register: create ERC-8004 identity + Safe account in one flow.
1771
+ * If already registered, returns existing state.
1772
+ *
1773
+ * Sets `this.agentId` on success so subsequent operations work immediately.
1774
+ */
1775
+ async register() {
1776
+ const eoaAddr = await this._getSignerAddress();
1777
+ if (this.agentId !== void 0) {
1778
+ const exists = await this.agether4337Factory.accountExists(this.agentId);
1779
+ if (exists) {
1780
+ const acct = await this.agether4337Factory.getAccount(this.agentId);
1781
+ this.accountAddress = acct;
1782
+ const kyaRequired2 = await this.isKyaRequired();
1783
+ return {
1784
+ agentId: this.agentId.toString(),
1785
+ address: eoaAddr,
1786
+ agentAccount: acct,
1787
+ alreadyRegistered: true,
1788
+ kyaRequired: kyaRequired2
1789
+ };
1790
+ }
1791
+ }
1792
+ let agentId;
1793
+ if (this.agentId !== void 0) {
1794
+ const balance = await this.identityRegistry.balanceOf(eoaAddr);
1795
+ if (balance > 0n) {
1796
+ agentId = this.agentId;
1797
+ } else {
1798
+ agentId = await this._mintNewIdentity();
1799
+ }
1800
+ } else {
1801
+ agentId = await this._mintNewIdentity();
1802
+ }
1803
+ this.agentId = agentId;
1804
+ const acctExists = await this.agether4337Factory.accountExists(agentId);
1805
+ let txHash;
1806
+ if (!acctExists) {
1807
+ const tx = await this.agether4337Factory.createAccount(agentId);
1808
+ const receipt = await tx.wait();
1809
+ this._refreshSigner();
1810
+ txHash = receipt.hash;
1811
+ }
1812
+ const acctAddr = await this.agether4337Factory.getAccount(agentId);
1813
+ this.accountAddress = acctAddr;
1814
+ const kyaRequired = await this.isKyaRequired();
1815
+ return {
1816
+ agentId: agentId.toString(),
1817
+ address: eoaAddr,
1818
+ agentAccount: acctAddr,
1819
+ alreadyRegistered: acctExists,
1820
+ kyaRequired,
1821
+ tx: txHash
1822
+ };
1823
+ }
1824
+ /** Mint a new ERC-8004 identity and return the agentId. */
1825
+ async _mintNewIdentity() {
1826
+ const regTx = await this.identityRegistry.register();
1827
+ const regReceipt = await regTx.wait();
1828
+ this._refreshSigner();
1829
+ let agentId = 0n;
1830
+ for (const log of regReceipt.logs) {
1831
+ try {
1832
+ const parsed = this.identityRegistry.interface.parseLog({
1833
+ topics: log.topics,
1834
+ data: log.data
1835
+ });
1836
+ if (parsed?.name === "Transfer") {
1837
+ agentId = parsed.args[2];
1838
+ break;
1839
+ }
1840
+ } catch (e) {
1841
+ console.warn("[agether] parseLog skip:", e instanceof Error ? e.message : e);
1842
+ continue;
1843
+ }
1844
+ }
1845
+ if (agentId === 0n) {
1846
+ throw new AgetherError("Failed to parse agentId from registration", "PARSE_ERROR");
1847
+ }
1848
+ return agentId;
1849
+ }
1850
+ // ════════════════════════════════════════════════════════
1851
+ // Account Management
1852
+ // ════════════════════════════════════════════════════════
1853
+ /**
1854
+ * Deploy a Safe account smart wallet for the agent.
1855
+ * The caller must own the ERC-8004 NFT.
1856
+ */
1857
+ async createAccount() {
1858
+ const id = this._requireAgentId();
1859
+ const tx = await this.agether4337Factory.createAccount(id);
1860
+ const receipt = await tx.wait();
1861
+ this._refreshSigner();
1862
+ const event = receipt.logs.map((log) => {
1863
+ try {
1864
+ return this.agether4337Factory.interface.parseLog(log);
1865
+ } catch {
1866
+ return null;
1867
+ }
1868
+ }).find((e) => e?.name === "AccountCreated");
1869
+ if (event) {
1870
+ this.accountAddress = event.args.safeAccount;
1871
+ } else {
1872
+ this.accountAddress = await this.agether4337Factory.getAccount(id);
1873
+ }
1874
+ return this.accountAddress;
1875
+ }
1876
+ /** Get the Safe account address for the current agent. Cached after first call. */
1877
+ async getAccountAddress() {
1878
+ if (this.accountAddress) return this.accountAddress;
1879
+ const id = this._requireAgentId();
1880
+ const addr = await this.agether4337Factory.getAccount(id);
1881
+ if (addr === import_ethers2.ethers.ZeroAddress) {
1882
+ throw new AgetherError(
1883
+ "No account found. Create one with createAccount() or register().",
1884
+ "NO_ACCOUNT"
1885
+ );
1886
+ }
1887
+ this.accountAddress = addr;
1888
+ return addr;
1889
+ }
1890
+ /** Check whether the Safe account has been deployed. */
1891
+ async accountExists() {
1892
+ const id = this._requireAgentId();
1893
+ return this.agether4337Factory.accountExists(id);
1894
+ }
1895
+ // ════════════════════════════════════════════════════════
1896
+ // Balances
1897
+ // ════════════════════════════════════════════════════════
1898
+ /**
1899
+ * Get ETH, USDC, and collateral token balances for EOA and Safe account.
1900
+ *
1901
+ * Collateral tokens are resolved from a built-in registry of well-known
1902
+ * tokens per chain (WETH, wstETH, cbETH).
1903
+ */
1904
+ async getBalances() {
1905
+ const provider = this.signer.provider;
1906
+ const eoaAddr = await this._getSignerAddress();
1907
+ const usdc = new import_ethers2.Contract(this.config.contracts.usdc, ERC20_ABI, provider);
1908
+ const ethBal = await provider.getBalance(eoaAddr);
1909
+ const usdcBal = await usdc.balanceOf(eoaAddr);
1910
+ const knownTokens = KNOWN_TOKENS[this.config.chainId] ?? {};
1911
+ const eoaCollateral = {};
1912
+ for (const [symbol, info] of Object.entries(knownTokens)) {
1913
+ try {
1914
+ const token = new import_ethers2.Contract(info.address, ERC20_ABI, provider);
1915
+ const bal = await token.balanceOf(eoaAddr);
1916
+ eoaCollateral[symbol] = import_ethers2.ethers.formatUnits(bal, info.decimals);
1917
+ } catch (e) {
1918
+ console.warn(`[agether] EOA collateral fetch failed for ${symbol}:`, e instanceof Error ? e.message : e);
1919
+ eoaCollateral[symbol] = "0";
1920
+ }
1921
+ }
1922
+ const result = {
1923
+ agentId: this.agentId !== void 0 ? this.agentId.toString() : "?",
1924
+ address: eoaAddr,
1925
+ eth: import_ethers2.ethers.formatEther(ethBal),
1926
+ usdc: import_ethers2.ethers.formatUnits(usdcBal, 6),
1927
+ collateral: eoaCollateral
1928
+ };
1929
+ try {
1930
+ const acctAddr = await this.getAccountAddress();
1931
+ const acctEth = await provider.getBalance(acctAddr);
1932
+ const acctUsdc = await usdc.balanceOf(acctAddr);
1933
+ const acctCollateral = {};
1934
+ for (const [symbol, info] of Object.entries(knownTokens)) {
1935
+ try {
1936
+ const token = new import_ethers2.Contract(info.address, ERC20_ABI, provider);
1937
+ const bal = await token.balanceOf(acctAddr);
1938
+ acctCollateral[symbol] = import_ethers2.ethers.formatUnits(bal, info.decimals);
1939
+ } catch (e) {
1940
+ console.warn(`[agether] Account collateral fetch failed for ${symbol}:`, e instanceof Error ? e.message : e);
1941
+ acctCollateral[symbol] = "0";
1942
+ }
1943
+ }
1944
+ result.agentAccount = {
1945
+ address: acctAddr,
1946
+ eth: import_ethers2.ethers.formatEther(acctEth),
1947
+ usdc: import_ethers2.ethers.formatUnits(acctUsdc, 6),
1948
+ collateral: acctCollateral
1949
+ };
1950
+ } catch (e) {
1951
+ if (e instanceof AgetherError && (e.code === "NO_ACCOUNT" || e.code === "NO_AGENT_ID")) {
1952
+ } else {
1953
+ console.warn("[agether] getBalances: failed to fetch Safe account data:", e.message ?? e);
1954
+ }
1955
+ }
1956
+ return result;
1957
+ }
1958
+ /**
1959
+ * Fund the Safe account with USDC from EOA.
1960
+ * This is a simple ERC-20 transfer (does NOT require a UserOp).
1961
+ */
1962
+ async fundAccount(usdcAmount) {
1963
+ const acctAddr = await this.getAccountAddress();
1964
+ const usdc = new import_ethers2.Contract(this.config.contracts.usdc, ERC20_ABI, this.signer);
1965
+ const amount = import_ethers2.ethers.parseUnits(usdcAmount, 6);
1966
+ const tx = await usdc.transfer(acctAddr, amount);
1967
+ const receipt = await tx.wait();
1968
+ this._refreshSigner();
1969
+ return {
1970
+ txHash: receipt.hash,
1971
+ blockNumber: receipt.blockNumber,
1972
+ status: receipt.status === 1 ? "success" : "failed",
1973
+ gasUsed: receipt.gasUsed
1974
+ };
1975
+ }
1976
+ // ════════════════════════════════════════════════════════
1977
+ // Withdrawals (Safe → EOA via UserOps)
1978
+ // ════════════════════════════════════════════════════════
1979
+ /**
1980
+ * Withdraw an ERC-20 token from Safe account to EOA.
1981
+ * Executes a transfer via Safe UserOp.
1982
+ *
1983
+ * @param tokenSymbol - Token to withdraw (e.g. 'USDC', 'WETH', 'wstETH') or 0x address
1984
+ * @param amount - Amount to withdraw (human-readable, e.g. '100', or 'all')
1985
+ */
1986
+ async withdrawToken(tokenSymbol, amount) {
1987
+ const acctAddr = await this.getAccountAddress();
1988
+ const eoaAddr = await this._getSignerAddress();
1989
+ const tokenInfo = await this._resolveToken(tokenSymbol);
1990
+ const tokenContract = new import_ethers2.Contract(tokenInfo.address, ERC20_ABI, this.signer.provider);
1991
+ let weiAmount;
1992
+ if (amount === "all") {
1993
+ weiAmount = await tokenContract.balanceOf(acctAddr);
1994
+ if (weiAmount === 0n) {
1995
+ throw new AgetherError(`No ${tokenInfo.symbol} in Safe account`, "INSUFFICIENT_BALANCE");
1996
+ }
1997
+ } else {
1998
+ weiAmount = import_ethers2.ethers.parseUnits(amount, tokenInfo.decimals);
1999
+ }
2000
+ const data = erc20Iface2.encodeFunctionData("transfer", [eoaAddr, weiAmount]);
2001
+ const receipt = await this._exec(tokenInfo.address, data);
2002
+ const actualAmount = amount === "all" ? import_ethers2.ethers.formatUnits(weiAmount, tokenInfo.decimals) : amount;
2003
+ return { tx: receipt.hash, token: tokenInfo.symbol, amount: actualAmount, destination: eoaAddr };
2004
+ }
2005
+ /**
2006
+ * Withdraw ETH from Safe account to EOA.
2007
+ * Executes a native ETH transfer via Safe UserOp.
2008
+ *
2009
+ * @param amount - ETH amount (e.g. '0.01' or 'all')
2010
+ */
2011
+ async withdrawEth(amount) {
2012
+ const acctAddr = await this.getAccountAddress();
2013
+ const eoaAddr = await this._getSignerAddress();
2014
+ let weiAmount;
2015
+ if (amount === "all") {
2016
+ weiAmount = await this.signer.provider.getBalance(acctAddr);
2017
+ if (weiAmount === 0n) throw new AgetherError("No ETH in Safe account", "INSUFFICIENT_BALANCE");
2018
+ } else {
2019
+ weiAmount = import_ethers2.ethers.parseEther(amount);
2020
+ }
2021
+ const receipt = await this._exec(eoaAddr, "0x", weiAmount);
2022
+ const actualAmount = amount === "all" ? import_ethers2.ethers.formatEther(weiAmount) : amount;
2023
+ return { tx: receipt.hash, token: "ETH", amount: actualAmount, destination: eoaAddr };
2024
+ }
2025
+ // ════════════════════════════════════════════════════════
2026
+ // Sponsorship
2027
+ // ════════════════════════════════════════════════════════
2028
+ /**
2029
+ * Send tokens to another agent's Safe account (or any address).
2030
+ * Transfers from EOA (does NOT require a UserOp).
2031
+ *
2032
+ * @param target - `{ agentId: '42' }` or `{ address: '0x...' }`
2033
+ * @param tokenSymbol - Token to send (e.g. 'WETH', 'USDC') or 0x address
2034
+ * @param amount - Amount to send (human-readable)
2035
+ */
2036
+ async sponsor(target, tokenSymbol, amount) {
2037
+ const tokenInfo = await this._resolveToken(tokenSymbol);
2038
+ let targetAddr;
2039
+ if (target.address) {
2040
+ targetAddr = target.address;
2041
+ } else if (target.agentId) {
2042
+ targetAddr = await this.agether4337Factory.getAccount(BigInt(target.agentId));
2043
+ if (targetAddr === import_ethers2.ethers.ZeroAddress) {
2044
+ throw new AgetherError("Target agent has no account", "NO_ACCOUNT");
2045
+ }
2046
+ } else {
2047
+ throw new AgetherError("Provide agentId or address", "INVALID_TARGET");
2048
+ }
2049
+ const weiAmount = import_ethers2.ethers.parseUnits(amount, tokenInfo.decimals);
2050
+ const tokenContract = new import_ethers2.Contract(tokenInfo.address, ERC20_ABI, this.signer);
2051
+ const tx = await tokenContract.transfer(targetAddr, weiAmount);
2052
+ const receipt = await tx.wait();
2053
+ this._refreshSigner();
2054
+ return { tx: receipt.hash, targetAccount: targetAddr, targetAgentId: target.agentId };
2055
+ }
2056
+ // ════════════════════════════════════════════════════════
2057
+ // Identity & Validation
2058
+ // ════════════════════════════════════════════════════════
2059
+ /**
2060
+ * Check if the KYA gate is active on the validation module.
2061
+ * If validationRegistry is not set, all txs pass (KYA disabled).
2062
+ */
2063
+ async isKyaRequired() {
2064
+ try {
2065
+ const registryAddr = await this.validationModule.validationRegistry();
2066
+ return registryAddr !== import_ethers2.ethers.ZeroAddress;
2067
+ } catch {
2068
+ return false;
2069
+ }
2070
+ }
2071
+ /**
2072
+ * Check if this agent's code is KYA-approved.
2073
+ * Uses the ERC8004ValidationModule.isKYAApproved(account) view.
2074
+ */
2075
+ async isKyaApproved() {
2076
+ try {
2077
+ const acctAddr = await this.getAccountAddress();
2078
+ return this.validationModule.isKYAApproved(acctAddr);
2079
+ } catch {
2080
+ return false;
2081
+ }
2082
+ }
2083
+ /** Check whether the agent's ERC-8004 NFT exists. */
2084
+ async identityExists() {
2085
+ const id = this._requireAgentId();
2086
+ try {
2087
+ await this.identityRegistry.ownerOf(id);
2088
+ return true;
2089
+ } catch (e) {
2090
+ console.warn("[agether] identityExists check failed:", e instanceof Error ? e.message : e);
2091
+ return false;
2092
+ }
2093
+ }
2094
+ /** Get the owner address of the ERC-8004 NFT. */
2095
+ async getIdentityOwner() {
2096
+ const id = this._requireAgentId();
2097
+ return this.identityRegistry.ownerOf(id);
2098
+ }
2099
+ // ════════════════════════════════════════════════════════
2100
+ // Reputation
2101
+ // ════════════════════════════════════════════════════════
2102
+ /** Read the agent's current credit score from the Agether8004Scorer contract. */
2103
+ async getCreditScore() {
2104
+ const id = this._requireAgentId();
2105
+ return this.agether8004Scorer.getCreditScore(id);
2106
+ }
2107
+ /** Check if the score is fresh (within MAX_ORACLE_AGE). */
2108
+ async isScoreFresh() {
2109
+ const id = this._requireAgentId();
2110
+ const [fresh, age] = await this.agether8004Scorer.isScoreFresh(id);
2111
+ return { fresh, age };
2112
+ }
2113
+ /** Check if the agent meets a minimum score threshold. */
2114
+ async isEligible(minScore = 500n) {
2115
+ const id = this._requireAgentId();
2116
+ const [eligible, currentScore] = await this.agether8004Scorer.isEligible(id, minScore);
2117
+ return { eligible, currentScore };
2118
+ }
2119
+ // ════════════════════════════════════════════════════════
2120
+ // Getters
2121
+ // ════════════════════════════════════════════════════════
2122
+ get chainId() {
2123
+ return this.config.chainId;
2124
+ }
2125
+ get contracts() {
2126
+ return this.config.contracts;
2127
+ }
2128
+ get currentAccountAddress() {
2129
+ return this.accountAddress;
2130
+ }
2131
+ getSigner() {
2132
+ return this.signer;
2133
+ }
2134
+ getAgentId() {
2135
+ return this._requireAgentId();
2136
+ }
2137
+ // ════════════════════════════════════════════════════════
2138
+ // Private Helpers
2139
+ // ════════════════════════════════════════════════════════
2140
+ /** Require agentId to be set, throw a helpful error otherwise. */
2141
+ _requireAgentId() {
2142
+ if (this.agentId === void 0) {
2143
+ throw new AgetherError("agentId not set. Call register() first.", "NO_AGENT_ID");
2144
+ }
2145
+ return this.agentId;
2146
+ }
2147
+ /** Resolve EOA signer address (async, cached). */
2148
+ async _getSignerAddress() {
2149
+ if (!this._eoaAddress) {
2150
+ this._eoaAddress = await this.signer.getAddress();
2151
+ }
2152
+ return this._eoaAddress;
2153
+ }
2154
+ /**
2155
+ * Resolve a token symbol or address to { address, symbol, decimals }.
2156
+ *
2157
+ * Supports:
2158
+ * - `'USDC'` → from chain config
2159
+ * - Well-known symbols (`'WETH'`, `'wstETH'`, `'cbETH'`) → built-in per-chain registry
2160
+ * - `'0x...'` address → reads decimals and symbol onchain
2161
+ */
2162
+ async _resolveToken(symbolOrAddress) {
2163
+ if (symbolOrAddress.toUpperCase() === "USDC") {
2164
+ return { address: this.config.contracts.usdc, symbol: "USDC", decimals: 6 };
2165
+ }
2166
+ const chainTokens = KNOWN_TOKENS[this.config.chainId] ?? {};
2167
+ const bySymbol = chainTokens[symbolOrAddress] || chainTokens[symbolOrAddress.toUpperCase()];
2168
+ if (bySymbol) return bySymbol;
2169
+ if (symbolOrAddress.startsWith("0x") && symbolOrAddress.length === 42) {
2170
+ try {
2171
+ const token = new import_ethers2.Contract(
2172
+ symbolOrAddress,
2173
+ ["function decimals() view returns (uint8)", "function symbol() view returns (string)"],
2174
+ this.signer.provider
2175
+ );
2176
+ const [decimals, symbol] = await Promise.all([token.decimals(), token.symbol()]);
2177
+ return { address: symbolOrAddress, symbol, decimals: Number(decimals) };
2178
+ } catch (e) {
2179
+ throw new AgetherError(
2180
+ `Failed to read token at ${symbolOrAddress}: ${e instanceof Error ? e.message : e}`,
2181
+ "UNKNOWN_TOKEN"
2182
+ );
2183
+ }
2184
+ }
2185
+ throw new AgetherError(
2186
+ `Unknown token: ${symbolOrAddress}. Use a known symbol (USDC, WETH, wstETH, cbETH) or a 0x address.`,
2187
+ "UNKNOWN_TOKEN"
2188
+ );
2189
+ }
2190
+ /**
2191
+ * Refresh signer and rebind contracts for fresh nonce.
2192
+ *
2193
+ * For the privateKey path: recreates provider + wallet.
2194
+ * For external signers: just rebinds contract instances.
2195
+ */
2196
+ _refreshSigner() {
2197
+ if (!this._useExternalSigner && this._privateKey) {
2198
+ const provider = new import_ethers2.ethers.JsonRpcProvider(this._rpcUrl);
2199
+ const wallet = new import_ethers2.ethers.Wallet(this._privateKey, provider);
2200
+ this.signer = wallet;
2201
+ this._eoaAddress = wallet.address;
2202
+ }
2203
+ const c = this.config.contracts;
2204
+ this.agether4337Factory = new import_ethers2.Contract(c.agether4337Factory, AGETHER_4337_FACTORY_ABI, this.signer);
2205
+ this.identityRegistry = new import_ethers2.Contract(c.identityRegistry, IDENTITY_REGISTRY_ABI, this.signer);
2206
+ this.agether8004Scorer = new import_ethers2.Contract(c.agether8004Scorer, AGETHER_8004_SCORER_ABI, this.signer.provider);
2207
+ this.validationModule = new import_ethers2.Contract(c.erc8004ValidationModule, AGETHER_8004_VALIDATION_MODULE_ABI, this.signer.provider);
2208
+ this.entryPoint = new import_ethers2.Contract(c.entryPoint, ENTRYPOINT_V07_ABI, this.signer);
2209
+ }
2210
+ // ────────────────────────────────────────────────────────
2211
+ // ERC-4337 UserOp helpers (Safe + Safe7579 + EntryPoint v0.7)
2212
+ // ────────────────────────────────────────────────────────
2213
+ /**
2214
+ * Pack two uint128 values into a single bytes32:
2215
+ * bytes32 = (hi << 128) | lo
2216
+ */
2217
+ _packUint128(hi, lo) {
2218
+ return import_ethers2.ethers.zeroPadValue(import_ethers2.ethers.toBeHex(hi << 128n | lo), 32);
2219
+ }
2220
+ /**
2221
+ * Build, sign and submit a PackedUserOperation through EntryPoint.handleOps.
2222
+ */
2223
+ async _submitUserOp(callData) {
2224
+ const sender = await this.getAccountAddress();
2225
+ const eoaAddr = await this._getSignerAddress();
2226
+ const validatorAddr = this.config.contracts.erc8004ValidationModule;
2227
+ const nonceKey = BigInt(validatorAddr) << 32n;
2228
+ const nonce = await this.entryPoint.getNonce(sender, nonceKey);
2229
+ const feeData = await this.signer.provider.getFeeData();
2230
+ const maxFeePerGas = feeData.maxFeePerGas ?? import_ethers2.ethers.parseUnits("0.5", "gwei");
2231
+ const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas ?? import_ethers2.ethers.parseUnits("0.1", "gwei");
2232
+ const verificationGasLimit = 500000n;
2233
+ const callGasLimit = 800000n;
2234
+ const preVerificationGas = 100000n;
2235
+ const accountGasLimits = this._packUint128(verificationGasLimit, callGasLimit);
2236
+ const gasFees = this._packUint128(maxPriorityFeePerGas, maxFeePerGas);
2237
+ const requiredPrefund = (verificationGasLimit + callGasLimit + preVerificationGas) * maxFeePerGas;
2238
+ const accountBalance = await this.signer.provider.getBalance(sender);
2239
+ if (accountBalance < requiredPrefund) {
2240
+ const topUp = requiredPrefund - accountBalance;
2241
+ const topUpWithBuffer = topUp * 120n / 100n;
2242
+ const fundTx = await this.signer.sendTransaction({
2243
+ to: sender,
2244
+ value: topUpWithBuffer
2245
+ });
2246
+ await fundTx.wait();
2247
+ this._refreshSigner();
2248
+ }
2249
+ const userOp = {
2250
+ sender,
2251
+ nonce,
2252
+ initCode: "0x",
2253
+ callData,
2254
+ accountGasLimits,
2255
+ preVerificationGas,
2256
+ gasFees,
2257
+ paymasterAndData: "0x",
2258
+ signature: "0x"
2259
+ };
2260
+ const userOpHash = await this.entryPoint.getUserOpHash(userOp);
2261
+ const signature = await this.signer.signMessage(import_ethers2.ethers.getBytes(userOpHash));
2262
+ userOp.signature = signature;
2263
+ const tx = await this.entryPoint.handleOps([userOp], eoaAddr);
2264
+ const receipt = await tx.wait();
2265
+ this._refreshSigner();
2266
+ const epIface = new import_ethers2.ethers.Interface(ENTRYPOINT_V07_ABI);
2267
+ for (const log of receipt.logs) {
2268
+ try {
2269
+ const parsed = epIface.parseLog({ topics: log.topics, data: log.data });
2270
+ if (parsed?.name === "UserOperationEvent" && !parsed.args.success) {
2271
+ let revertMsg = "UserOp inner execution reverted";
2272
+ for (const rLog of receipt.logs) {
2273
+ try {
2274
+ const rParsed = epIface.parseLog({ topics: rLog.topics, data: rLog.data });
2275
+ if (rParsed?.name === "UserOperationRevertReason") {
2276
+ const reason = rParsed.args.revertReason;
2277
+ try {
2278
+ if (reason.length >= 10 && reason.slice(0, 10) === "0x08c379a0") {
2279
+ const decoded = import_ethers2.ethers.AbiCoder.defaultAbiCoder().decode(
2280
+ ["string"],
2281
+ "0x" + reason.slice(10)
2282
+ );
2283
+ revertMsg = `UserOp reverted: ${decoded[0]}`;
2284
+ } else {
2285
+ revertMsg = `UserOp reverted with data: ${reason}`;
2286
+ }
2287
+ } catch {
2288
+ revertMsg = `UserOp reverted with data: ${reason}`;
2289
+ }
2290
+ break;
2291
+ }
2292
+ } catch {
2293
+ continue;
2294
+ }
2295
+ }
2296
+ throw new AgetherError(revertMsg, "USEROP_EXECUTION_FAILED");
2297
+ }
2298
+ } catch (e) {
2299
+ if (e instanceof AgetherError) throw e;
2300
+ continue;
2301
+ }
2302
+ }
2303
+ return receipt;
2304
+ }
2305
+ /**
2306
+ * Execute a single call via Safe7579 account (ERC-7579 single mode)
2307
+ * through an ERC-4337 UserOperation.
2308
+ */
2309
+ async _exec(target, data, value = 0n) {
2310
+ const valueHex = import_ethers2.ethers.zeroPadValue(import_ethers2.ethers.toBeHex(value), 32);
2311
+ const executionCalldata = import_ethers2.ethers.concat([target, valueHex, data]);
2312
+ const safe7579Iface = new import_ethers2.ethers.Interface(SAFE7579_ACCOUNT_ABI);
2313
+ const callData = safe7579Iface.encodeFunctionData("execute", [MODE_SINGLE2, executionCalldata]);
2314
+ return this._submitUserOp(callData);
2315
+ }
2316
+ };
2317
+ }
2318
+ });
2319
+
2320
+ // src/clients/X402Client.ts
2321
+ var X402Client_exports = {};
2322
+ __export(X402Client_exports, {
2323
+ X402Client: () => X402Client
2324
+ });
2325
+ var import_fetch, import_client, import_client2, import_accounts, X402Client;
2326
+ var init_X402Client = __esm({
2327
+ "src/clients/X402Client.ts"() {
2328
+ "use strict";
2329
+ import_fetch = require("@x402/fetch");
2330
+ import_client = require("@x402/core/client");
2331
+ import_client2 = require("@x402/evm/exact/client");
2332
+ import_accounts = require("viem/accounts");
2333
+ X402Client = class {
2334
+ constructor(config) {
2335
+ this.config = config;
2336
+ let baseSigner;
2337
+ if ("walletClient" in config && config.walletClient) {
2338
+ const wc = config.walletClient;
2339
+ const account = wc.account;
2340
+ if (!account) {
2341
+ throw new Error(
2342
+ "X402Client: walletClient must have an attached account. Pass an account when creating the WalletClient or use privateKey mode instead."
2343
+ );
2344
+ }
2345
+ this.address = account.address;
2346
+ baseSigner = {
2347
+ address: account.address,
2348
+ signTypedData: (msg) => wc.signTypedData({
2349
+ account,
2350
+ domain: msg.domain,
2351
+ types: msg.types,
2352
+ primaryType: msg.primaryType,
2353
+ message: msg.message
2354
+ })
2355
+ };
2356
+ } else if ("privateKey" in config && config.privateKey) {
2357
+ const privateKey = config.privateKey.startsWith("0x") ? config.privateKey : `0x${config.privateKey}`;
2358
+ const account = (0, import_accounts.privateKeyToAccount)(privateKey);
2359
+ this.address = account.address;
2360
+ baseSigner = account;
2361
+ } else {
2362
+ throw new Error(
2363
+ "X402Client: provide either privateKey or walletClient in config."
2364
+ );
2365
+ }
2366
+ let signer;
2367
+ if (config.accountAddress) {
2368
+ const accountAddr = config.accountAddress;
2369
+ const inner = baseSigner;
2370
+ signer = (0, import_accounts.toAccount)({
2371
+ address: accountAddr,
2372
+ async signMessage({ message }) {
2373
+ if ("signMessage" in inner && typeof inner.signMessage === "function") {
2374
+ return inner.signMessage({ message });
2375
+ }
2376
+ throw new Error("signMessage not supported by underlying signer");
2377
+ },
2378
+ async signTransaction(tx) {
2379
+ if ("signTransaction" in inner && typeof inner.signTransaction === "function") {
2380
+ return inner.signTransaction(tx);
2381
+ }
2382
+ throw new Error("signTransaction not supported by underlying signer");
2383
+ },
2384
+ async signTypedData(typedData) {
2385
+ const sig = await inner.signTypedData(typedData);
2386
+ if (config.validatorModule) {
2387
+ const validatorHex = config.validatorModule.replace("0x", "").toLowerCase();
2388
+ const sigHex = sig.replace("0x", "");
2389
+ return `0x${validatorHex}${sigHex}`;
2390
+ }
2391
+ return `${sig}00`;
2392
+ }
2393
+ });
2394
+ this.address = accountAddr;
2395
+ } else {
2396
+ signer = baseSigner;
2397
+ }
2398
+ const client = new import_client.x402Client();
2399
+ (0, import_client2.registerExactEvmScheme)(client, { signer });
2400
+ this.paidFetch = (0, import_fetch.wrapFetchWithPayment)(fetch, client);
2401
+ const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
2402
+ const dailyLimit = config.dailySpendLimitUsdc ? BigInt(Math.round(parseFloat(config.dailySpendLimitUsdc) * 1e6)) : 0n;
2045
2403
  const restored = config.initialSpendingState;
2046
2404
  const restoredBorrowed = restored && restored.date === today ? BigInt(restored.totalBorrowed) : 0n;
2047
2405
  this._spendingTracker = { date: today, totalBorrowed: restoredBorrowed, dailyLimit };
@@ -2325,7 +2683,7 @@ var init_X402Client = __esm({
2325
2683
  });
2326
2684
 
2327
2685
  // src/cli.ts
2328
- var import_ethers2 = require("ethers");
2686
+ var import_ethers3 = require("ethers");
2329
2687
  var fs = __toESM(require("fs"));
2330
2688
  var path = __toESM(require("path"));
2331
2689
  var os = __toESM(require("os"));
@@ -2369,13 +2727,25 @@ async function waitForTx(tx, retries = 5) {
2369
2727
  }
2370
2728
  async function getMorphoClient(config) {
2371
2729
  const { MorphoClient: MorphoClient2 } = await Promise.resolve().then(() => (init_MorphoClient(), MorphoClient_exports));
2730
+ if (!config.agentId || config.agentId === "0") {
2731
+ throw new Error("Agent not registered. Run: agether register");
2732
+ }
2372
2733
  return new MorphoClient2({
2373
2734
  privateKey: config.privateKey,
2374
2735
  rpcUrl: config.rpcUrl,
2375
- agentId: config.agentId !== "0" ? config.agentId : void 0,
2736
+ agentId: config.agentId,
2376
2737
  chainId: config.chainId
2377
2738
  });
2378
2739
  }
2740
+ async function getAgetherClient(config) {
2741
+ const { AgetherClient: AgetherClient2 } = await Promise.resolve().then(() => (init_AgetherClient(), AgetherClient_exports));
2742
+ const chainId = config.chainId ?? 1;
2743
+ const agentId = config.agentId && config.agentId !== "0" ? BigInt(config.agentId) : void 0;
2744
+ if (agentId !== void 0) {
2745
+ return AgetherClient2.fromPrivateKey(config.privateKey, agentId, chainId);
2746
+ }
2747
+ return AgetherClient2.fromPrivateKey(config.privateKey, chainId);
2748
+ }
2379
2749
  async function getX402Client(config) {
2380
2750
  const { X402Client: X402Client2 } = await Promise.resolve().then(() => (init_X402Client(), X402Client_exports));
2381
2751
  let accountAddress;
@@ -2438,7 +2808,7 @@ async function cmdInit(privateKey, agentId, chain) {
2438
2808
  const rpcUrl = process.env.AGETHER_RPC_URL || CHAIN_RPC[chainId] || DEFAULT_RPC;
2439
2809
  let wallet;
2440
2810
  try {
2441
- wallet = new import_ethers2.ethers.Wallet(privateKey);
2811
+ wallet = new import_ethers3.ethers.Wallet(privateKey);
2442
2812
  } catch {
2443
2813
  console.error("\u274C Invalid private key");
2444
2814
  process.exit(1);
@@ -2455,8 +2825,8 @@ async function cmdInit(privateKey, agentId, chain) {
2455
2825
  }
2456
2826
  async function cmdRegister(name) {
2457
2827
  const config = requireConfig();
2458
- const provider = new import_ethers2.ethers.JsonRpcProvider(config.rpcUrl);
2459
- const signer = new import_ethers2.ethers.Wallet(config.privateKey, provider);
2828
+ const provider = new import_ethers3.ethers.JsonRpcProvider(config.rpcUrl);
2829
+ const signer = new import_ethers3.ethers.Wallet(config.privateKey, provider);
2460
2830
  const agentName = name || `Agent-${signer.address.slice(0, 8)}`;
2461
2831
  console.log(`\u{1F916} Registering agent: ${agentName}
2462
2832
  `);
@@ -2479,7 +2849,7 @@ async function cmdRegister(name) {
2479
2849
  process.exit(1);
2480
2850
  }
2481
2851
  console.log(" [2/4] Registering on ERC-8004 IdentityRegistry...");
2482
- const agentRegistry = new import_ethers2.ethers.Contract(registryAddr, ERC8004_ABI, signer);
2852
+ const agentRegistry = new import_ethers3.ethers.Contract(registryAddr, ERC8004_ABI, signer);
2483
2853
  let agentId;
2484
2854
  if (config.agentId && config.agentId !== "0") {
2485
2855
  agentId = BigInt(config.agentId);
@@ -2510,7 +2880,7 @@ async function cmdRegister(name) {
2510
2880
  const agentURI = `data:application/json;base64,${Buffer.from(registrationFile).toString("base64")}`;
2511
2881
  const tx = await agentRegistry["register(string)"](agentURI);
2512
2882
  const receipt = await waitForTx(tx);
2513
- const transferTopic = import_ethers2.ethers.id("Transfer(address,address,uint256)");
2883
+ const transferTopic = import_ethers3.ethers.id("Transfer(address,address,uint256)");
2514
2884
  const transferLog = receipt.logs.find((log) => log.topics[0] === transferTopic);
2515
2885
  if (transferLog && transferLog.topics.length >= 4) {
2516
2886
  agentId = BigInt(transferLog.topics[3]);
@@ -2543,11 +2913,11 @@ async function cmdRegister(name) {
2543
2913
  if (chainId === 31337 || chainId === 1) {
2544
2914
  console.log(" [3/4] Minting test USDC (Hardhat fork)...");
2545
2915
  const deployerPk = "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80";
2546
- const deployer = new import_ethers2.ethers.Wallet(deployerPk, provider);
2916
+ const deployer = new import_ethers3.ethers.Wallet(deployerPk, provider);
2547
2917
  const usdcAddr = contracts.usdc;
2548
2918
  if (usdcAddr) {
2549
2919
  try {
2550
- const usdc = new import_ethers2.ethers.Contract(usdcAddr, MOCK_ERC20_ABI, deployer);
2920
+ const usdc = new import_ethers3.ethers.Contract(usdcAddr, MOCK_ERC20_ABI, deployer);
2551
2921
  const tx = await usdc.mint(signer.address, BigInt(5e10));
2552
2922
  await waitForTx(tx);
2553
2923
  console.log(" \u2713 Minted $50,000 USDC");
@@ -2560,7 +2930,7 @@ async function cmdRegister(name) {
2560
2930
  }
2561
2931
  console.log(" [4/4] Creating Safe account...");
2562
2932
  if (factoryAddr) {
2563
- const factory = new import_ethers2.ethers.Contract(factoryAddr, ACCOUNT_FACTORY_ABI2, signer);
2933
+ const factory = new import_ethers3.ethers.Contract(factoryAddr, ACCOUNT_FACTORY_ABI2, signer);
2564
2934
  try {
2565
2935
  const exists = await factory.accountExists(agentId);
2566
2936
  if (exists) {
@@ -2578,7 +2948,7 @@ async function cmdRegister(name) {
2578
2948
  }
2579
2949
  }
2580
2950
  if (validationAddr) {
2581
- const vr = new import_ethers2.ethers.Contract(validationAddr, VALIDATION_REGISTRY_ABI, provider);
2951
+ const vr = new import_ethers3.ethers.Contract(validationAddr, VALIDATION_REGISTRY_ABI, provider);
2582
2952
  try {
2583
2953
  const approved = await vr.isAgentCodeApproved(agentId);
2584
2954
  console.log(`
@@ -2597,8 +2967,8 @@ async function cmdRegister(name) {
2597
2967
  }
2598
2968
  async function cmdBalance() {
2599
2969
  const config = requireConfig();
2600
- const mc = await getMorphoClient(config);
2601
- const balances = await mc.getBalances();
2970
+ const ac = await getAgetherClient(config);
2971
+ const balances = await ac.getBalances();
2602
2972
  console.log(`
2603
2973
  \u{1F4B0} Agent #${balances.agentId} Balances
2604
2974
  `);
@@ -2636,8 +3006,9 @@ async function cmdStatus() {
2636
3006
  }
2637
3007
  console.log(" \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
2638
3008
  try {
2639
- const score = await mc.getCreditScore();
2640
- const { fresh, age } = await mc.isScoreFresh();
3009
+ const ac = await getAgetherClient(config);
3010
+ const score = await ac.getCreditScore();
3011
+ const { fresh, age } = await ac.isScoreFresh();
2641
3012
  const ageHrs = Number(age) / 3600;
2642
3013
  console.log(`
2643
3014
  Credit Score: ${score} ${fresh ? "\u2705" : `\u26A0\uFE0F stale (${ageHrs.toFixed(1)}h old)`}`);
@@ -2766,13 +3137,13 @@ async function cmdWithdraw(amount, token) {
2766
3137
  }
2767
3138
  async function cmdSponsor(amount, token, agentId, address) {
2768
3139
  const config = requireConfig();
2769
- const mc = await getMorphoClient(config);
3140
+ const ac = await getAgetherClient(config);
2770
3141
  const target = agentId ? { agentId } : { address };
2771
3142
  console.log(`
2772
3143
  \u{1F381} Sponsoring ${amount} ${token} to ${agentId || address}...
2773
3144
  `);
2774
3145
  try {
2775
- const result = await mc.sponsor(target, token, amount);
3146
+ const result = await ac.sponsor(target, token, amount);
2776
3147
  console.log(`\u2705 Sponsored ${amount} ${token}`);
2777
3148
  console.log(` Target: ${result.targetAccount}`);
2778
3149
  console.log(` TX: ${result.tx}`);
@@ -2782,15 +3153,14 @@ async function cmdSponsor(amount, token, agentId, address) {
2782
3153
  }
2783
3154
  async function cmdFund(amount) {
2784
3155
  const config = requireConfig();
2785
- const mc = await getMorphoClient(config);
3156
+ const ac = await getAgetherClient(config);
2786
3157
  console.log(`
2787
3158
  \u{1F4B5} Funding AgentAccount with $${amount} USDC...
2788
3159
  `);
2789
3160
  try {
2790
- const result = await mc.fundAccount(amount);
3161
+ const result = await ac.fundAccount(amount);
2791
3162
  console.log(`\u2705 Funded $${amount} USDC`);
2792
- console.log(` AgentAccount: ${result.agentAccount}`);
2793
- console.log(` TX: ${result.tx}`);
3163
+ console.log(` TX: ${result.txHash}`);
2794
3164
  } catch (e) {
2795
3165
  console.error(`\u274C ${decodeError(e)}`);
2796
3166
  }
@@ -2799,7 +3169,7 @@ async function cmdX402Call(url, method = "GET", body) {
2799
3169
  const config = requireConfig();
2800
3170
  console.log("\n\u{1F510} x402 Paid API Call\n");
2801
3171
  const x402 = await getX402Client(config);
2802
- console.log(` Wallet: ${new import_ethers2.ethers.Wallet(config.privateKey).address}`);
3172
+ console.log(` Wallet: ${new import_ethers3.ethers.Wallet(config.privateKey).address}`);
2803
3173
  console.log(`
2804
3174
  \u{1F4E1} ${method} ${url}`);
2805
3175
  if (body) console.log(`\u{1F4E6} Body: ${body}`);