@exagent/sdk 0.1.17 → 0.1.19

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.d.mts CHANGED
@@ -192,6 +192,10 @@ interface RouterTradeResponse {
192
192
  agentId: number;
193
193
  };
194
194
  mock?: boolean;
195
+ /** Present when API's pre-flight simulation failed (for sells) */
196
+ simulationSkipped?: boolean;
197
+ /** Warning message when simulation failed */
198
+ simulationWarning?: string;
195
199
  }
196
200
  /**
197
201
  * Trade execution result
@@ -1083,7 +1087,7 @@ declare class ExagentVault {
1083
1087
  }
1084
1088
 
1085
1089
  /** SDK version — sent to API for version gating */
1086
- declare const SDK_VERSION = "0.1.14";
1090
+ declare const SDK_VERSION = "0.1.18";
1087
1091
  /**
1088
1092
  * Default RPC URL for Base mainnet.
1089
1093
  * Coinbase's official Base RPC — reliable for reads and transactions.
@@ -1505,7 +1509,16 @@ declare class ExagentClient {
1505
1509
  /** Standard headers for all API requests (includes SDK version for gating) */
1506
1510
  private apiHeaders;
1507
1511
  /**
1508
- * Register as a new agent on Exagent
1512
+ * Register as a new agent on Exagent.
1513
+ *
1514
+ * RECOMMENDED: Register your agent at https://exagent.io instead of using this method.
1515
+ * The website handles the full registration flow including risk universe selection,
1516
+ * position size limits, daily loss limits, and metadata upload — all in one step.
1517
+ * After registering on the website, use your agent ID in agent-config.json.
1518
+ *
1519
+ * This SDK method is available for programmatic registration but uses default
1520
+ * risk parameters (universe=1, maxPositionSize=10%, maxDailyLoss=5%).
1521
+ *
1509
1522
  * @param metadata Agent metadata (will be uploaded to IPFS)
1510
1523
  * @returns The assigned agent ID
1511
1524
  * @throws Error if wallet already owns an agent (one agent per wallet rule)
@@ -1524,9 +1537,19 @@ declare class ExagentClient {
1524
1537
  */
1525
1538
  getAgentByName(name: string): Promise<bigint>;
1526
1539
  /**
1527
- * Get the current agent's ID (if registered)
1540
+ * Get the current agent's ID (if registered).
1541
+ *
1542
+ * Resolution order:
1543
+ * 1. Cached value (from prior register() or getAgentId() call)
1544
+ * 2. walletToAgent mapping (linked wallets)
1545
+ * 3. Owner lookup (unlinked owner wallet)
1546
+ *
1547
+ * If the agent was just registered, public RPCs may return stale data (0).
1548
+ * Use `retries` to wait for the on-chain state to propagate.
1549
+ *
1550
+ * @param retries Number of retries with 2s delay for stale RPC reads (default: 0)
1528
1551
  */
1529
- getAgentId(): Promise<bigint | undefined>;
1552
+ getAgentId(retries?: number): Promise<bigint | undefined>;
1530
1553
  /**
1531
1554
  * Get agent profile
1532
1555
  * @param agentId Optional agent ID (defaults to current agent)
@@ -1575,6 +1598,10 @@ declare class ExagentClient {
1575
1598
  * Useful for simulation or multi-step workflows
1576
1599
  */
1577
1600
  buildRouterTrade(intent: Omit<TradeIntent, 'action'>, agentId?: bigint): Promise<RouterTradeResponse>;
1601
+ /**
1602
+ * Check if an address is the ETH sentinel or WETH
1603
+ */
1604
+ private isETHAddress;
1578
1605
  /**
1579
1606
  * Read current ERC-20 allowance for a (token, spender) pair
1580
1607
  */
package/dist/index.d.ts CHANGED
@@ -192,6 +192,10 @@ interface RouterTradeResponse {
192
192
  agentId: number;
193
193
  };
194
194
  mock?: boolean;
195
+ /** Present when API's pre-flight simulation failed (for sells) */
196
+ simulationSkipped?: boolean;
197
+ /** Warning message when simulation failed */
198
+ simulationWarning?: string;
195
199
  }
196
200
  /**
197
201
  * Trade execution result
@@ -1083,7 +1087,7 @@ declare class ExagentVault {
1083
1087
  }
1084
1088
 
1085
1089
  /** SDK version — sent to API for version gating */
1086
- declare const SDK_VERSION = "0.1.14";
1090
+ declare const SDK_VERSION = "0.1.18";
1087
1091
  /**
1088
1092
  * Default RPC URL for Base mainnet.
1089
1093
  * Coinbase's official Base RPC — reliable for reads and transactions.
@@ -1505,7 +1509,16 @@ declare class ExagentClient {
1505
1509
  /** Standard headers for all API requests (includes SDK version for gating) */
1506
1510
  private apiHeaders;
1507
1511
  /**
1508
- * Register as a new agent on Exagent
1512
+ * Register as a new agent on Exagent.
1513
+ *
1514
+ * RECOMMENDED: Register your agent at https://exagent.io instead of using this method.
1515
+ * The website handles the full registration flow including risk universe selection,
1516
+ * position size limits, daily loss limits, and metadata upload — all in one step.
1517
+ * After registering on the website, use your agent ID in agent-config.json.
1518
+ *
1519
+ * This SDK method is available for programmatic registration but uses default
1520
+ * risk parameters (universe=1, maxPositionSize=10%, maxDailyLoss=5%).
1521
+ *
1509
1522
  * @param metadata Agent metadata (will be uploaded to IPFS)
1510
1523
  * @returns The assigned agent ID
1511
1524
  * @throws Error if wallet already owns an agent (one agent per wallet rule)
@@ -1524,9 +1537,19 @@ declare class ExagentClient {
1524
1537
  */
1525
1538
  getAgentByName(name: string): Promise<bigint>;
1526
1539
  /**
1527
- * Get the current agent's ID (if registered)
1540
+ * Get the current agent's ID (if registered).
1541
+ *
1542
+ * Resolution order:
1543
+ * 1. Cached value (from prior register() or getAgentId() call)
1544
+ * 2. walletToAgent mapping (linked wallets)
1545
+ * 3. Owner lookup (unlinked owner wallet)
1546
+ *
1547
+ * If the agent was just registered, public RPCs may return stale data (0).
1548
+ * Use `retries` to wait for the on-chain state to propagate.
1549
+ *
1550
+ * @param retries Number of retries with 2s delay for stale RPC reads (default: 0)
1528
1551
  */
1529
- getAgentId(): Promise<bigint | undefined>;
1552
+ getAgentId(retries?: number): Promise<bigint | undefined>;
1530
1553
  /**
1531
1554
  * Get agent profile
1532
1555
  * @param agentId Optional agent ID (defaults to current agent)
@@ -1575,6 +1598,10 @@ declare class ExagentClient {
1575
1598
  * Useful for simulation or multi-step workflows
1576
1599
  */
1577
1600
  buildRouterTrade(intent: Omit<TradeIntent, 'action'>, agentId?: bigint): Promise<RouterTradeResponse>;
1601
+ /**
1602
+ * Check if an address is the ETH sentinel or WETH
1603
+ */
1604
+ private isETHAddress;
1578
1605
  /**
1579
1606
  * Read current ERC-20 allowance for a (token, spender) pair
1580
1607
  */
package/dist/index.js CHANGED
@@ -1199,7 +1199,7 @@ var ExagentVault = class {
1199
1199
 
1200
1200
  // src/constants.ts
1201
1201
  var import_chains = require("viem/chains");
1202
- var SDK_VERSION = "0.1.14";
1202
+ var SDK_VERSION = "0.1.18";
1203
1203
  var DEFAULT_RPC_URL = "https://mainnet.base.org";
1204
1204
  function getRpcUrl() {
1205
1205
  if (typeof process !== "undefined" && process.env) {
@@ -1213,7 +1213,7 @@ var CHAIN_CONFIG = {
1213
1213
  var CONTRACT_ADDRESSES = {
1214
1214
  mainnet: {
1215
1215
  agentRegistry: "0x2261706C751F8ac5cdDb481B7b56EA2137d4A723",
1216
- router: "0x1BCFa13f677fDCf697D8b7d5120f544817F1de1A",
1216
+ router: "0x20feB3054750970773Fe7370c391732EE0559743",
1217
1217
  vaultFactory: "0x1E0e4E445A9fda2e7aBBfFEcA80392ABb0921554",
1218
1218
  feeCollector: "0x00Ab9847049b5496619dFDd1A7bd36FA49eB7195",
1219
1219
  serviceEscrow: "0x63A4d1dA774422EFC2cc57d71F948231BD812516"
@@ -1321,7 +1321,16 @@ var ExagentClient = class {
1321
1321
  }
1322
1322
  // ============ Agent Registration ============
1323
1323
  /**
1324
- * Register as a new agent on Exagent
1324
+ * Register as a new agent on Exagent.
1325
+ *
1326
+ * RECOMMENDED: Register your agent at https://exagent.io instead of using this method.
1327
+ * The website handles the full registration flow including risk universe selection,
1328
+ * position size limits, daily loss limits, and metadata upload — all in one step.
1329
+ * After registering on the website, use your agent ID in agent-config.json.
1330
+ *
1331
+ * This SDK method is available for programmatic registration but uses default
1332
+ * risk parameters (universe=1, maxPositionSize=10%, maxDailyLoss=5%).
1333
+ *
1325
1334
  * @param metadata Agent metadata (will be uploaded to IPFS)
1326
1335
  * @returns The assigned agent ID
1327
1336
  * @throws Error if wallet already owns an agent (one agent per wallet rule)
@@ -1363,19 +1372,34 @@ var ExagentClient = class {
1363
1372
  return this.registry.getAgentByName(name);
1364
1373
  }
1365
1374
  /**
1366
- * Get the current agent's ID (if registered)
1375
+ * Get the current agent's ID (if registered).
1376
+ *
1377
+ * Resolution order:
1378
+ * 1. Cached value (from prior register() or getAgentId() call)
1379
+ * 2. walletToAgent mapping (linked wallets)
1380
+ * 3. Owner lookup (unlinked owner wallet)
1381
+ *
1382
+ * If the agent was just registered, public RPCs may return stale data (0).
1383
+ * Use `retries` to wait for the on-chain state to propagate.
1384
+ *
1385
+ * @param retries Number of retries with 2s delay for stale RPC reads (default: 0)
1367
1386
  */
1368
- async getAgentId() {
1387
+ async getAgentId(retries = 0) {
1369
1388
  if (this._agentId) return this._agentId;
1370
- const agentId = await this.registry.getAgentForWallet(this.account.address);
1371
- if (agentId > 0n) {
1372
- this._agentId = agentId;
1373
- return agentId;
1374
- }
1375
- const ownedAgentId = await this.registry.getAgentByOwner(this.account.address);
1376
- if (ownedAgentId > 0n) {
1377
- this._agentId = ownedAgentId;
1378
- return ownedAgentId;
1389
+ for (let attempt = 0; attempt <= retries; attempt++) {
1390
+ if (attempt > 0) {
1391
+ await new Promise((r) => setTimeout(r, 2e3));
1392
+ }
1393
+ const agentId = await this.registry.getAgentForWallet(this.account.address);
1394
+ if (agentId > 0n) {
1395
+ this._agentId = agentId;
1396
+ return agentId;
1397
+ }
1398
+ const ownedAgentId = await this.registry.getAgentByOwner(this.account.address);
1399
+ if (ownedAgentId > 0n) {
1400
+ this._agentId = ownedAgentId;
1401
+ return ownedAgentId;
1402
+ }
1379
1403
  }
1380
1404
  return void 0;
1381
1405
  }
@@ -1468,6 +1492,7 @@ var ExagentClient = class {
1468
1492
  data: routerTrade.transaction.data,
1469
1493
  value: BigInt(routerTrade.transaction.value)
1470
1494
  };
1495
+ const isETHInput = this.isETHAddress(intent.tokenIn);
1471
1496
  try {
1472
1497
  const estimated = await this.publicClient.estimateGas({
1473
1498
  account: this.account,
@@ -1478,20 +1503,34 @@ var ExagentClient = class {
1478
1503
  txParams.gas = estimated * 150n / 100n;
1479
1504
  } catch (err) {
1480
1505
  const errorData = err?.data;
1481
- if (errorData && errorData.length > 2) {
1482
- console.error(`Gas estimation revert data: ${errorData}`);
1483
- try {
1484
- const decoded = (0, import_viem2.decodeErrorResult)({
1485
- abi: [...EXAGENT_ROUTER_ABI, ...EXAGENT_REGISTRY_ABI],
1486
- data: errorData
1487
- });
1488
- throw new Error(`Trade will revert: ${decoded.errorName}${decoded.args ? ` (${decoded.args.join(", ")})` : ""}`);
1489
- } catch (decodeErr) {
1490
- if (decodeErr instanceof Error && decodeErr.message.startsWith("Trade will revert:")) throw decodeErr;
1491
- throw new Error(`Trade will revert: unknown error selector ${errorData.slice(0, 10)} (raw: ${errorData.slice(0, 66)})`);
1506
+ if (isETHInput) {
1507
+ if (errorData && errorData.length > 2) {
1508
+ console.error(`Gas estimation revert data: ${errorData}`);
1509
+ try {
1510
+ const decoded = (0, import_viem2.decodeErrorResult)({
1511
+ abi: [...EXAGENT_ROUTER_ABI, ...EXAGENT_REGISTRY_ABI],
1512
+ data: errorData
1513
+ });
1514
+ throw new Error(`Trade will revert: ${decoded.errorName}${decoded.args ? ` (${decoded.args.join(", ")})` : ""}`);
1515
+ } catch (decodeErr) {
1516
+ if (decodeErr instanceof Error && decodeErr.message.startsWith("Trade will revert:")) throw decodeErr;
1517
+ throw new Error(`Trade will revert: unknown error selector ${errorData.slice(0, 10)} (raw: ${errorData.slice(0, 66)})`);
1518
+ }
1492
1519
  }
1520
+ throw new Error(`Trade will revert: gas estimation failed. ${err?.message || "Unknown reason"}`);
1521
+ }
1522
+ if (routerTrade.gasEstimate) {
1523
+ const apiGas = BigInt(routerTrade.gasEstimate);
1524
+ txParams.gas = apiGas * 200n / 100n;
1525
+ console.warn(
1526
+ `[SDK] Local gas estimation failed for sell, using API estimate with 100% buffer: ${txParams.gas}. This is expected for some DEX routes. Warning: ${routerTrade.simulationWarning || "none"}`
1527
+ );
1528
+ } else {
1529
+ txParams.gas = 800000n;
1530
+ console.warn(
1531
+ `[SDK] Local gas estimation failed for sell and no API estimate available. Using safe default: 800000. This may result in wasted gas if the transaction reverts.`
1532
+ );
1493
1533
  }
1494
- throw new Error(`Trade will revert: gas estimation failed. ${err?.message || "Unknown reason"}`);
1495
1534
  }
1496
1535
  const hash = await this.walletClient.sendTransaction(txParams);
1497
1536
  return {
@@ -1537,6 +1576,13 @@ var ExagentClient = class {
1537
1576
  }
1538
1577
  return response.json();
1539
1578
  }
1579
+ /**
1580
+ * Check if an address is the ETH sentinel or WETH
1581
+ */
1582
+ isETHAddress(addr) {
1583
+ const lower = addr.toLowerCase();
1584
+ return lower === "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" || lower === "0x0000000000000000000000000000000000000000" || lower === "0x4200000000000000000000000000000000000006";
1585
+ }
1540
1586
  /**
1541
1587
  * Read current ERC-20 allowance for a (token, spender) pair
1542
1588
  */
@@ -1801,14 +1847,28 @@ var ExagentClient = class {
1801
1847
  }
1802
1848
  parseAgentIdFromReceipt(receipt) {
1803
1849
  const registryAddress = this.registry.address.toLowerCase();
1850
+ const AGENT_REGISTERED_TOPIC = (0, import_viem2.keccak256)(
1851
+ (0, import_viem2.toHex)("AgentRegistered(uint256,address,string,string)")
1852
+ );
1853
+ const TRANSFER_TOPIC = (0, import_viem2.keccak256)(
1854
+ (0, import_viem2.toHex)("Transfer(address,address,uint256)")
1855
+ );
1856
+ const ZERO_ADDRESS2 = "0x0000000000000000000000000000000000000000000000000000000000000000";
1804
1857
  for (const log of receipt.logs) {
1805
1858
  if (log.address.toLowerCase() !== registryAddress) continue;
1806
- if (log.topics.length >= 2 && log.topics[1]) {
1807
- const agentId = BigInt(log.topics[1]);
1808
- return agentId;
1859
+ if (log.topics[0] === AGENT_REGISTERED_TOPIC && log.topics[1]) {
1860
+ return BigInt(log.topics[1]);
1809
1861
  }
1810
1862
  }
1811
- throw new Error("AgentRegistered event not found in transaction receipt");
1863
+ for (const log of receipt.logs) {
1864
+ if (log.address.toLowerCase() !== registryAddress) continue;
1865
+ if (log.topics[0] === TRANSFER_TOPIC && log.topics[1] === ZERO_ADDRESS2 && log.topics[3]) {
1866
+ return BigInt(log.topics[3]);
1867
+ }
1868
+ }
1869
+ throw new Error(
1870
+ "Could not extract agent ID from transaction receipt.\nNeither AgentRegistered nor ERC721 Transfer event found in logs.\nCheck the transaction on BaseScan to verify registration succeeded."
1871
+ );
1812
1872
  }
1813
1873
  };
1814
1874
 
package/dist/index.mjs CHANGED
@@ -4,7 +4,9 @@ import {
4
4
  createWalletClient,
5
5
  http,
6
6
  decodeErrorResult,
7
- maxUint256
7
+ maxUint256,
8
+ keccak256 as keccak2562,
9
+ toHex
8
10
  } from "viem";
9
11
  import { privateKeyToAccount } from "viem/accounts";
10
12
 
@@ -1166,7 +1168,7 @@ var ExagentVault = class {
1166
1168
 
1167
1169
  // src/constants.ts
1168
1170
  import { base } from "viem/chains";
1169
- var SDK_VERSION = "0.1.14";
1171
+ var SDK_VERSION = "0.1.18";
1170
1172
  var DEFAULT_RPC_URL = "https://mainnet.base.org";
1171
1173
  function getRpcUrl() {
1172
1174
  if (typeof process !== "undefined" && process.env) {
@@ -1180,7 +1182,7 @@ var CHAIN_CONFIG = {
1180
1182
  var CONTRACT_ADDRESSES = {
1181
1183
  mainnet: {
1182
1184
  agentRegistry: "0x2261706C751F8ac5cdDb481B7b56EA2137d4A723",
1183
- router: "0x1BCFa13f677fDCf697D8b7d5120f544817F1de1A",
1185
+ router: "0x20feB3054750970773Fe7370c391732EE0559743",
1184
1186
  vaultFactory: "0x1E0e4E445A9fda2e7aBBfFEcA80392ABb0921554",
1185
1187
  feeCollector: "0x00Ab9847049b5496619dFDd1A7bd36FA49eB7195",
1186
1188
  serviceEscrow: "0x63A4d1dA774422EFC2cc57d71F948231BD812516"
@@ -1288,7 +1290,16 @@ var ExagentClient = class {
1288
1290
  }
1289
1291
  // ============ Agent Registration ============
1290
1292
  /**
1291
- * Register as a new agent on Exagent
1293
+ * Register as a new agent on Exagent.
1294
+ *
1295
+ * RECOMMENDED: Register your agent at https://exagent.io instead of using this method.
1296
+ * The website handles the full registration flow including risk universe selection,
1297
+ * position size limits, daily loss limits, and metadata upload — all in one step.
1298
+ * After registering on the website, use your agent ID in agent-config.json.
1299
+ *
1300
+ * This SDK method is available for programmatic registration but uses default
1301
+ * risk parameters (universe=1, maxPositionSize=10%, maxDailyLoss=5%).
1302
+ *
1292
1303
  * @param metadata Agent metadata (will be uploaded to IPFS)
1293
1304
  * @returns The assigned agent ID
1294
1305
  * @throws Error if wallet already owns an agent (one agent per wallet rule)
@@ -1330,19 +1341,34 @@ var ExagentClient = class {
1330
1341
  return this.registry.getAgentByName(name);
1331
1342
  }
1332
1343
  /**
1333
- * Get the current agent's ID (if registered)
1344
+ * Get the current agent's ID (if registered).
1345
+ *
1346
+ * Resolution order:
1347
+ * 1. Cached value (from prior register() or getAgentId() call)
1348
+ * 2. walletToAgent mapping (linked wallets)
1349
+ * 3. Owner lookup (unlinked owner wallet)
1350
+ *
1351
+ * If the agent was just registered, public RPCs may return stale data (0).
1352
+ * Use `retries` to wait for the on-chain state to propagate.
1353
+ *
1354
+ * @param retries Number of retries with 2s delay for stale RPC reads (default: 0)
1334
1355
  */
1335
- async getAgentId() {
1356
+ async getAgentId(retries = 0) {
1336
1357
  if (this._agentId) return this._agentId;
1337
- const agentId = await this.registry.getAgentForWallet(this.account.address);
1338
- if (agentId > 0n) {
1339
- this._agentId = agentId;
1340
- return agentId;
1341
- }
1342
- const ownedAgentId = await this.registry.getAgentByOwner(this.account.address);
1343
- if (ownedAgentId > 0n) {
1344
- this._agentId = ownedAgentId;
1345
- return ownedAgentId;
1358
+ for (let attempt = 0; attempt <= retries; attempt++) {
1359
+ if (attempt > 0) {
1360
+ await new Promise((r) => setTimeout(r, 2e3));
1361
+ }
1362
+ const agentId = await this.registry.getAgentForWallet(this.account.address);
1363
+ if (agentId > 0n) {
1364
+ this._agentId = agentId;
1365
+ return agentId;
1366
+ }
1367
+ const ownedAgentId = await this.registry.getAgentByOwner(this.account.address);
1368
+ if (ownedAgentId > 0n) {
1369
+ this._agentId = ownedAgentId;
1370
+ return ownedAgentId;
1371
+ }
1346
1372
  }
1347
1373
  return void 0;
1348
1374
  }
@@ -1435,6 +1461,7 @@ var ExagentClient = class {
1435
1461
  data: routerTrade.transaction.data,
1436
1462
  value: BigInt(routerTrade.transaction.value)
1437
1463
  };
1464
+ const isETHInput = this.isETHAddress(intent.tokenIn);
1438
1465
  try {
1439
1466
  const estimated = await this.publicClient.estimateGas({
1440
1467
  account: this.account,
@@ -1445,20 +1472,34 @@ var ExagentClient = class {
1445
1472
  txParams.gas = estimated * 150n / 100n;
1446
1473
  } catch (err) {
1447
1474
  const errorData = err?.data;
1448
- if (errorData && errorData.length > 2) {
1449
- console.error(`Gas estimation revert data: ${errorData}`);
1450
- try {
1451
- const decoded = decodeErrorResult({
1452
- abi: [...EXAGENT_ROUTER_ABI, ...EXAGENT_REGISTRY_ABI],
1453
- data: errorData
1454
- });
1455
- throw new Error(`Trade will revert: ${decoded.errorName}${decoded.args ? ` (${decoded.args.join(", ")})` : ""}`);
1456
- } catch (decodeErr) {
1457
- if (decodeErr instanceof Error && decodeErr.message.startsWith("Trade will revert:")) throw decodeErr;
1458
- throw new Error(`Trade will revert: unknown error selector ${errorData.slice(0, 10)} (raw: ${errorData.slice(0, 66)})`);
1475
+ if (isETHInput) {
1476
+ if (errorData && errorData.length > 2) {
1477
+ console.error(`Gas estimation revert data: ${errorData}`);
1478
+ try {
1479
+ const decoded = decodeErrorResult({
1480
+ abi: [...EXAGENT_ROUTER_ABI, ...EXAGENT_REGISTRY_ABI],
1481
+ data: errorData
1482
+ });
1483
+ throw new Error(`Trade will revert: ${decoded.errorName}${decoded.args ? ` (${decoded.args.join(", ")})` : ""}`);
1484
+ } catch (decodeErr) {
1485
+ if (decodeErr instanceof Error && decodeErr.message.startsWith("Trade will revert:")) throw decodeErr;
1486
+ throw new Error(`Trade will revert: unknown error selector ${errorData.slice(0, 10)} (raw: ${errorData.slice(0, 66)})`);
1487
+ }
1459
1488
  }
1489
+ throw new Error(`Trade will revert: gas estimation failed. ${err?.message || "Unknown reason"}`);
1490
+ }
1491
+ if (routerTrade.gasEstimate) {
1492
+ const apiGas = BigInt(routerTrade.gasEstimate);
1493
+ txParams.gas = apiGas * 200n / 100n;
1494
+ console.warn(
1495
+ `[SDK] Local gas estimation failed for sell, using API estimate with 100% buffer: ${txParams.gas}. This is expected for some DEX routes. Warning: ${routerTrade.simulationWarning || "none"}`
1496
+ );
1497
+ } else {
1498
+ txParams.gas = 800000n;
1499
+ console.warn(
1500
+ `[SDK] Local gas estimation failed for sell and no API estimate available. Using safe default: 800000. This may result in wasted gas if the transaction reverts.`
1501
+ );
1460
1502
  }
1461
- throw new Error(`Trade will revert: gas estimation failed. ${err?.message || "Unknown reason"}`);
1462
1503
  }
1463
1504
  const hash = await this.walletClient.sendTransaction(txParams);
1464
1505
  return {
@@ -1504,6 +1545,13 @@ var ExagentClient = class {
1504
1545
  }
1505
1546
  return response.json();
1506
1547
  }
1548
+ /**
1549
+ * Check if an address is the ETH sentinel or WETH
1550
+ */
1551
+ isETHAddress(addr) {
1552
+ const lower = addr.toLowerCase();
1553
+ return lower === "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" || lower === "0x0000000000000000000000000000000000000000" || lower === "0x4200000000000000000000000000000000000006";
1554
+ }
1507
1555
  /**
1508
1556
  * Read current ERC-20 allowance for a (token, spender) pair
1509
1557
  */
@@ -1768,14 +1816,28 @@ var ExagentClient = class {
1768
1816
  }
1769
1817
  parseAgentIdFromReceipt(receipt) {
1770
1818
  const registryAddress = this.registry.address.toLowerCase();
1819
+ const AGENT_REGISTERED_TOPIC = keccak2562(
1820
+ toHex("AgentRegistered(uint256,address,string,string)")
1821
+ );
1822
+ const TRANSFER_TOPIC = keccak2562(
1823
+ toHex("Transfer(address,address,uint256)")
1824
+ );
1825
+ const ZERO_ADDRESS2 = "0x0000000000000000000000000000000000000000000000000000000000000000";
1771
1826
  for (const log of receipt.logs) {
1772
1827
  if (log.address.toLowerCase() !== registryAddress) continue;
1773
- if (log.topics.length >= 2 && log.topics[1]) {
1774
- const agentId = BigInt(log.topics[1]);
1775
- return agentId;
1828
+ if (log.topics[0] === AGENT_REGISTERED_TOPIC && log.topics[1]) {
1829
+ return BigInt(log.topics[1]);
1776
1830
  }
1777
1831
  }
1778
- throw new Error("AgentRegistered event not found in transaction receipt");
1832
+ for (const log of receipt.logs) {
1833
+ if (log.address.toLowerCase() !== registryAddress) continue;
1834
+ if (log.topics[0] === TRANSFER_TOPIC && log.topics[1] === ZERO_ADDRESS2 && log.topics[3]) {
1835
+ return BigInt(log.topics[3]);
1836
+ }
1837
+ }
1838
+ throw new Error(
1839
+ "Could not extract agent ID from transaction receipt.\nNeither AgentRegistered nor ERC721 Transfer event found in logs.\nCheck the transaction on BaseScan to verify registration succeeded."
1840
+ );
1779
1841
  }
1780
1842
  };
1781
1843
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exagent/sdk",
3
- "version": "0.1.17",
3
+ "version": "0.1.19",
4
4
  "description": "TypeScript SDK for Exagent",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",