@agether/sdk 1.8.0 → 1.10.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
@@ -62,7 +62,10 @@ var ACCOUNT_FACTORY_ABI = [
62
62
  "function totalAccounts() view returns (uint256)",
63
63
  "function getAgentId(address account) view returns (uint256)",
64
64
  "function createAccount(uint256 agentId) returns (address account)",
65
- "event AccountCreated(uint256 indexed agentId, address indexed account, address indexed owner)"
65
+ "function validationRegistry() view returns (address)",
66
+ "function setValidationRegistry(address newRegistry)",
67
+ "event AccountCreated(uint256 indexed agentId, address indexed account, address indexed owner)",
68
+ "event ValidationRegistryUpdated(address indexed oldRegistry, address indexed newRegistry)"
66
69
  ];
67
70
  var AGENT_ACCOUNT_ABI = [
68
71
  "function agentId() view returns (uint256)",
@@ -135,9 +138,9 @@ var CONTRACT_ADDRESSES = {
135
138
  morphoBlue: "0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb"
136
139
  },
137
140
  [8453 /* Base */]: {
138
- accountFactory: "0xb5b09213d0718f3FD56F1b111C8A83FDFcBdd5d8",
139
- validationRegistry: "0x867F4F6f749Dc422aeFEcF4273cD22015d2CBCc2",
140
- agentReputation: "0x352883c396bc7e88891a7D343ba550A7638256c0",
141
+ accountFactory: "0xFab8b924fb292a736BA05AF7b4AEC2c8d05cdcbF",
142
+ validationRegistry: "0x493f1551cbbC75afb2127CDBD5375ad8e8959f42",
143
+ agentReputation: "0x1fcb28eE3E8F3234E653b0A7a6fb56dE11E3c203",
141
144
  usdc: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
142
145
  identityRegistry: "0x8004A169FB4a3325136EB29fA0ceB6D2e539a432",
143
146
  morphoBlue: "0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb"
@@ -399,14 +402,44 @@ var MorphoClient = class {
399
402
  this.config = defaultCfg;
400
403
  this.agentId = config.agentId;
401
404
  this._rpcUrl = config.rpcUrl || defaultCfg.rpcUrl;
402
- this._privateKey = config.privateKey;
403
- this.provider = new ethers2.JsonRpcProvider(this._rpcUrl);
404
- this.wallet = new ethers2.Wallet(this._privateKey, this.provider);
405
+ if ("signer" in config && config.signer) {
406
+ this._useExternalSigner = true;
407
+ const signerProvider = config.signer.provider;
408
+ if (signerProvider) {
409
+ this.provider = signerProvider;
410
+ this._signer = config.signer;
411
+ } else {
412
+ this.provider = new ethers2.JsonRpcProvider(this._rpcUrl);
413
+ this._signer = config.signer.connect(this.provider);
414
+ }
415
+ if ("address" in config.signer && typeof config.signer.address === "string") {
416
+ this._eoaAddress = config.signer.address;
417
+ }
418
+ } else {
419
+ this._privateKey = config.privateKey;
420
+ this._useExternalSigner = false;
421
+ this.provider = new ethers2.JsonRpcProvider(this._rpcUrl);
422
+ const wallet = new ethers2.Wallet(this._privateKey, this.provider);
423
+ this._signer = wallet;
424
+ this._eoaAddress = wallet.address;
425
+ }
405
426
  const addrs = { ...defaultCfg.contracts, ...config.contracts };
406
- this.accountFactory = new Contract2(addrs.accountFactory, ACCOUNT_FACTORY_ABI, this.wallet);
427
+ this.accountFactory = new Contract2(addrs.accountFactory, ACCOUNT_FACTORY_ABI, this._signer);
407
428
  this.morphoBlue = new Contract2(addrs.morphoBlue, MORPHO_BLUE_ABI, this.provider);
408
- this.agentReputation = new Contract2(addrs.agentReputation, AGENT_REPUTATION_ABI, this.wallet);
409
- this.identityRegistry = new Contract2(addrs.identityRegistry, IDENTITY_REGISTRY_ABI, this.wallet);
429
+ this.agentReputation = new Contract2(addrs.agentReputation, AGENT_REPUTATION_ABI, this._signer);
430
+ this.identityRegistry = new Contract2(addrs.identityRegistry, IDENTITY_REGISTRY_ABI, this._signer);
431
+ }
432
+ // ════════════════════════════════════════════════════════
433
+ // KYA Gate Check
434
+ // ════════════════════════════════════════════════════════
435
+ /**
436
+ * Check whether the KYA (Know Your Agent) code verification gate is active.
437
+ * When validationRegistry is address(0), KYA is disabled — agents can use
438
+ * execute/executeBatch without prior code approval.
439
+ */
440
+ async isKyaRequired() {
441
+ const registryAddr = await this.accountFactory.validationRegistry();
442
+ return registryAddr !== ethers2.ZeroAddress;
410
443
  }
411
444
  // ════════════════════════════════════════════════════════
412
445
  // Account Management
@@ -426,8 +459,35 @@ var MorphoClient = class {
426
459
  if (!this.agentId) throw new AgetherError("agentId not set", "NO_AGENT_ID");
427
460
  return this.agentId;
428
461
  }
462
+ /**
463
+ * Get the EOA wallet address (synchronous, best-effort).
464
+ *
465
+ * For the `privateKey` path this always works. For the `signer` path
466
+ * it works if the signer exposes `.address` synchronously (e.g. ethers.Wallet).
467
+ * If the address has not been resolved yet, throws — call `getSignerAddress()` first.
468
+ */
429
469
  getWalletAddress() {
430
- return this.wallet.address;
470
+ if (this._eoaAddress) return this._eoaAddress;
471
+ const signer = this._signer;
472
+ if (signer.address && typeof signer.address === "string") {
473
+ const addr = signer.address;
474
+ this._eoaAddress = addr;
475
+ return addr;
476
+ }
477
+ throw new AgetherError(
478
+ "EOA address not yet resolved. Call getSignerAddress() (async) first, or use a signer that exposes .address synchronously.",
479
+ "ADDRESS_NOT_RESOLVED"
480
+ );
481
+ }
482
+ /**
483
+ * Resolve the EOA signer address (async, works with all signer types).
484
+ * Result is cached after the first call.
485
+ */
486
+ async getSignerAddress() {
487
+ if (!this._eoaAddress) {
488
+ this._eoaAddress = await this._signer.getAddress();
489
+ }
490
+ return this._eoaAddress;
431
491
  }
432
492
  /** Mint a new ERC-8004 identity and return the agentId. */
433
493
  async _mintNewIdentity() {
@@ -454,13 +514,14 @@ var MorphoClient = class {
454
514
  * If already registered, returns existing state.
455
515
  */
456
516
  async register(_name) {
457
- const eoaAddr = this.wallet.address;
517
+ const eoaAddr = await this.getSignerAddress();
458
518
  if (this.agentId) {
459
519
  const exists = await this.accountFactory.accountExists(BigInt(this.agentId));
460
520
  if (exists) {
461
521
  const acct = await this.accountFactory.getAccount(BigInt(this.agentId));
462
522
  this._accountAddress = acct;
463
- return { agentId: this.agentId, address: eoaAddr, agentAccount: acct, alreadyRegistered: true };
523
+ const kyaRequired2 = await this.isKyaRequired();
524
+ return { agentId: this.agentId, address: eoaAddr, agentAccount: acct, alreadyRegistered: true, kyaRequired: kyaRequired2 };
464
525
  }
465
526
  }
466
527
  let agentId;
@@ -485,17 +546,19 @@ var MorphoClient = class {
485
546
  }
486
547
  const acctAddr = await this.accountFactory.getAccount(agentId);
487
548
  this._accountAddress = acctAddr;
549
+ const kyaRequired = await this.isKyaRequired();
488
550
  return {
489
551
  agentId: this.agentId,
490
552
  address: eoaAddr,
491
553
  agentAccount: acctAddr,
492
554
  alreadyRegistered: acctExists,
555
+ kyaRequired,
493
556
  tx: txHash
494
557
  };
495
558
  }
496
559
  /** Get ETH / USDC / collateral balances for EOA and AgentAccount. */
497
560
  async getBalances() {
498
- const eoaAddr = this.wallet.address;
561
+ const eoaAddr = await this.getSignerAddress();
499
562
  const usdc = new Contract2(this.config.contracts.usdc, ERC20_ABI, this.provider);
500
563
  const ethBal = await this.provider.getBalance(eoaAddr);
501
564
  const usdcBal = await usdc.balanceOf(eoaAddr);
@@ -543,7 +606,7 @@ var MorphoClient = class {
543
606
  /** Transfer USDC from EOA to AgentAccount. */
544
607
  async fundAccount(usdcAmount) {
545
608
  const acctAddr = await this.getAccountAddress();
546
- const usdc = new Contract2(this.config.contracts.usdc, ERC20_ABI, this.wallet);
609
+ const usdc = new Contract2(this.config.contracts.usdc, ERC20_ABI, this._signer);
547
610
  const amount = ethers2.parseUnits(usdcAmount, 6);
548
611
  const tx = await usdc.transfer(acctAddr, amount);
549
612
  const receipt = await tx.wait();
@@ -891,7 +954,7 @@ var MorphoClient = class {
891
954
  const params = marketParams ?? await this.findMarketForCollateral(tokenSymbol);
892
955
  const weiAmount = ethers2.parseUnits(amount, colInfo.decimals);
893
956
  const morphoAddr = this.config.contracts.morphoBlue;
894
- const colToken = new Contract2(colInfo.address, ERC20_ABI, this.wallet);
957
+ const colToken = new Contract2(colInfo.address, ERC20_ABI, this._signer);
895
958
  const transferTx = await colToken.transfer(acctAddr, weiAmount);
896
959
  await transferTx.wait();
897
960
  this._refreshSigner();
@@ -968,7 +1031,7 @@ var MorphoClient = class {
968
1031
  const colWei = ethers2.parseUnits(collateralAmount, colInfo.decimals);
969
1032
  const borrowWei = ethers2.parseUnits(borrowUsdcAmount, 6);
970
1033
  const morphoAddr = this.config.contracts.morphoBlue;
971
- const colToken = new Contract2(colInfo.address, ERC20_ABI, this.wallet);
1034
+ const colToken = new Contract2(colInfo.address, ERC20_ABI, this._signer);
972
1035
  const transferTx = await colToken.transfer(acctAddr, colWei);
973
1036
  await transferTx.wait();
974
1037
  this._refreshSigner();
@@ -1098,7 +1161,7 @@ var MorphoClient = class {
1098
1161
  if (!colInfo) throw new AgetherError(`Unknown collateral: ${tokenSymbol}`, "UNKNOWN_COLLATERAL");
1099
1162
  const params = marketParams ?? await this.findMarketForCollateral(tokenSymbol);
1100
1163
  const morphoAddr = this.config.contracts.morphoBlue;
1101
- const dest = receiver || this.wallet.address;
1164
+ const dest = receiver || await this.getSignerAddress();
1102
1165
  let weiAmount;
1103
1166
  if (amount === "all") {
1104
1167
  const markets = await this.getMarkets();
@@ -1156,7 +1219,7 @@ var MorphoClient = class {
1156
1219
  throw new AgetherError("Provide agentId or address", "INVALID_TARGET");
1157
1220
  }
1158
1221
  const weiAmount = ethers2.parseUnits(amount, colInfo.decimals);
1159
- const colToken = new Contract2(colInfo.address, ERC20_ABI, this.wallet);
1222
+ const colToken = new Contract2(colInfo.address, ERC20_ABI, this._signer);
1160
1223
  const tx = await colToken.transfer(targetAddr, weiAmount);
1161
1224
  const receipt = await tx.wait();
1162
1225
  this._refreshSigner();
@@ -1188,24 +1251,41 @@ var MorphoClient = class {
1188
1251
  // Internal Helpers
1189
1252
  // ════════════════════════════════════════════════════════
1190
1253
  /**
1191
- * Recreate provider + wallet so the next tx fetches a fresh nonce from chain.
1192
- * Anvil (and some RPC providers) return a stale `eth_getTransactionCount`
1193
- * right after a block is mined, causing "nonce too low" on the follow-up tx.
1254
+ * Refresh the signer and re-bind contract instances.
1255
+ *
1256
+ * For the **privateKey** path: recreates provider + wallet so the next tx
1257
+ * fetches a fresh nonce from chain. Anvil (and some RPC providers) return a
1258
+ * stale `eth_getTransactionCount` right after a block is mined, causing
1259
+ * "nonce too low" on the follow-up tx.
1260
+ *
1261
+ * For the **external signer** path: the signer is immutable and owned by the
1262
+ * caller (e.g. custody provider). We only re-bind contract instances to
1263
+ * ensure they reference the current signer. Nonce management is the caller's
1264
+ * responsibility.
1194
1265
  */
1195
1266
  _refreshSigner() {
1196
- this.provider = new ethers2.JsonRpcProvider(this._rpcUrl);
1197
- this.wallet = new ethers2.Wallet(this._privateKey, this.provider);
1198
- const addrs = this.config.contracts;
1199
- this.accountFactory = new Contract2(addrs.accountFactory, ACCOUNT_FACTORY_ABI, this.wallet);
1200
- this.agentReputation = new Contract2(addrs.agentReputation, AGENT_REPUTATION_ABI, this.wallet);
1201
- this.identityRegistry = new Contract2(addrs.identityRegistry, IDENTITY_REGISTRY_ABI, this.wallet);
1267
+ if (this._useExternalSigner) {
1268
+ const addrs = this.config.contracts;
1269
+ this.accountFactory = new Contract2(addrs.accountFactory, ACCOUNT_FACTORY_ABI, this._signer);
1270
+ this.agentReputation = new Contract2(addrs.agentReputation, AGENT_REPUTATION_ABI, this._signer);
1271
+ this.identityRegistry = new Contract2(addrs.identityRegistry, IDENTITY_REGISTRY_ABI, this._signer);
1272
+ } else {
1273
+ this.provider = new ethers2.JsonRpcProvider(this._rpcUrl);
1274
+ const wallet = new ethers2.Wallet(this._privateKey, this.provider);
1275
+ this._signer = wallet;
1276
+ this._eoaAddress = wallet.address;
1277
+ const addrs = this.config.contracts;
1278
+ this.accountFactory = new Contract2(addrs.accountFactory, ACCOUNT_FACTORY_ABI, this._signer);
1279
+ this.agentReputation = new Contract2(addrs.agentReputation, AGENT_REPUTATION_ABI, this._signer);
1280
+ this.identityRegistry = new Contract2(addrs.identityRegistry, IDENTITY_REGISTRY_ABI, this._signer);
1281
+ }
1202
1282
  }
1203
1283
  /**
1204
1284
  * Execute a single call via AgentAccount.execute.
1205
1285
  */
1206
1286
  async exec(target, data, value = 0n) {
1207
1287
  const acctAddr = await this.getAccountAddress();
1208
- const account = new Contract2(acctAddr, AGENT_ACCOUNT_ABI, this.wallet);
1288
+ const account = new Contract2(acctAddr, AGENT_ACCOUNT_ABI, this._signer);
1209
1289
  let gasLimit;
1210
1290
  try {
1211
1291
  const estimate = await account.execute.estimateGas(target, value, data);
@@ -1223,7 +1303,7 @@ var MorphoClient = class {
1223
1303
  */
1224
1304
  async batch(targets, values, datas) {
1225
1305
  const acctAddr = await this.getAccountAddress();
1226
- const account = new Contract2(acctAddr, AGENT_ACCOUNT_ABI, this.wallet);
1306
+ const account = new Contract2(acctAddr, AGENT_ACCOUNT_ABI, this._signer);
1227
1307
  let gasLimit;
1228
1308
  try {
1229
1309
  const estimate = await account.executeBatch.estimateGas(targets, values, datas);
@@ -1280,28 +1360,62 @@ import { privateKeyToAccount, toAccount } from "viem/accounts";
1280
1360
  var X402Client = class {
1281
1361
  constructor(config) {
1282
1362
  this.config = config;
1283
- const privateKey = config.privateKey.startsWith("0x") ? config.privateKey : `0x${config.privateKey}`;
1284
- const eoaSigner = privateKeyToAccount(privateKey);
1363
+ let baseSigner;
1364
+ if ("walletClient" in config && config.walletClient) {
1365
+ const wc = config.walletClient;
1366
+ const account = wc.account;
1367
+ if (!account) {
1368
+ throw new Error(
1369
+ "X402Client: walletClient must have an attached account. Pass an account when creating the WalletClient or use privateKey mode instead."
1370
+ );
1371
+ }
1372
+ this.address = account.address;
1373
+ baseSigner = {
1374
+ address: account.address,
1375
+ signTypedData: (msg) => wc.signTypedData({
1376
+ account,
1377
+ domain: msg.domain,
1378
+ types: msg.types,
1379
+ primaryType: msg.primaryType,
1380
+ message: msg.message
1381
+ })
1382
+ };
1383
+ } else if ("privateKey" in config && config.privateKey) {
1384
+ const privateKey = config.privateKey.startsWith("0x") ? config.privateKey : `0x${config.privateKey}`;
1385
+ const account = privateKeyToAccount(privateKey);
1386
+ this.address = account.address;
1387
+ baseSigner = account;
1388
+ } else {
1389
+ throw new Error(
1390
+ "X402Client: provide either privateKey or walletClient in config."
1391
+ );
1392
+ }
1285
1393
  let signer;
1286
1394
  if (config.accountAddress) {
1287
1395
  const accountAddr = config.accountAddress;
1396
+ const inner = baseSigner;
1288
1397
  signer = toAccount({
1289
1398
  address: accountAddr,
1290
1399
  async signMessage({ message }) {
1291
- return eoaSigner.signMessage({ message });
1400
+ if ("signMessage" in inner && typeof inner.signMessage === "function") {
1401
+ return inner.signMessage({ message });
1402
+ }
1403
+ throw new Error("signMessage not supported by underlying signer");
1292
1404
  },
1293
1405
  async signTransaction(tx) {
1294
- return eoaSigner.signTransaction(tx);
1406
+ if ("signTransaction" in inner && typeof inner.signTransaction === "function") {
1407
+ return inner.signTransaction(tx);
1408
+ }
1409
+ throw new Error("signTransaction not supported by underlying signer");
1295
1410
  },
1296
1411
  async signTypedData(typedData) {
1297
- const sig = await eoaSigner.signTypedData(typedData);
1412
+ const sig = await inner.signTypedData(typedData);
1298
1413
  return `${sig}00`;
1299
1414
  }
1300
1415
  });
1301
1416
  this.address = accountAddr;
1302
1417
  } else {
1303
- signer = eoaSigner;
1304
- this.address = eoaSigner.address;
1418
+ signer = baseSigner;
1305
1419
  }
1306
1420
  const client = new x402Client();
1307
1421
  registerExactEvmScheme(client, { signer });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agether/sdk",
3
- "version": "1.8.0",
3
+ "version": "1.10.0",
4
4
  "description": "TypeScript SDK for Agether - autonomous credit for AI agents on Base",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",