@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 +31 -4
- package/dist/index.d.ts +31 -4
- package/dist/index.js +90 -30
- package/dist/index.mjs +93 -31
- package/package.json +1 -1
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.
|
|
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.
|
|
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.
|
|
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: "
|
|
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
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
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 (
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
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
|
|
1807
|
-
|
|
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
|
-
|
|
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.
|
|
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: "
|
|
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
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
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 (
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
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
|
|
1774
|
-
|
|
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
|
-
|
|
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
|
|