@agether/sdk 2.8.1 → 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 +737 -367
- package/dist/index.d.mts +141 -113
- package/dist/index.d.ts +141 -113
- package/dist/index.js +497 -326
- package/dist/index.mjs +497 -326
- package/package.json +1 -1
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,
|
|
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/
|
|
1963
|
-
var
|
|
1964
|
-
__export(
|
|
1965
|
-
|
|
1702
|
+
// src/clients/AgetherClient.ts
|
|
1703
|
+
var AgetherClient_exports = {};
|
|
1704
|
+
__export(AgetherClient_exports, {
|
|
1705
|
+
AgetherClient: () => AgetherClient
|
|
1966
1706
|
});
|
|
1967
|
-
var
|
|
1968
|
-
var
|
|
1969
|
-
"src/clients/
|
|
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
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
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
|
-
|
|
2005
|
-
"X402Client: provide either privateKey or walletClient in config."
|
|
2006
|
-
);
|
|
1739
|
+
this._useExternalSigner = true;
|
|
2007
1740
|
}
|
|
2008
|
-
|
|
2009
|
-
if (
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
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
|
-
|
|
1760
|
+
config = typeof agentIdOrChain === "number" ? getDefaultConfig(agentIdOrChain) : agentIdOrChain;
|
|
2039
1761
|
}
|
|
2040
|
-
const
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
2459
|
-
const signer = new
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
2601
|
-
const balances = await
|
|
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
|
|
2640
|
-
const
|
|
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
|
|
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
|
|
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
|
|
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
|
|
3161
|
+
const result = await ac.fundAccount(amount);
|
|
2791
3162
|
console.log(`\u2705 Funded $${amount} USDC`);
|
|
2792
|
-
console.log(`
|
|
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
|
|
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}`);
|