@agether/sdk 1.0.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/README.md +480 -0
- package/dist/cli.d.mts +2 -0
- package/dist/cli.d.ts +19 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +2149 -0
- package/dist/cli.mjs +0 -0
- package/dist/clients/AgentIdentityClient.d.ts +163 -0
- package/dist/clients/AgentIdentityClient.d.ts.map +1 -0
- package/dist/clients/AgentIdentityClient.js +293 -0
- package/dist/clients/AgetherClient.d.ts +101 -0
- package/dist/clients/AgetherClient.d.ts.map +1 -0
- package/dist/clients/AgetherClient.js +272 -0
- package/dist/clients/ScoringClient.d.ts +138 -0
- package/dist/clients/ScoringClient.d.ts.map +1 -0
- package/dist/clients/ScoringClient.js +135 -0
- package/dist/clients/VaultClient.d.ts +62 -0
- package/dist/clients/VaultClient.d.ts.map +1 -0
- package/dist/clients/VaultClient.js +157 -0
- package/dist/clients/WalletClient.d.ts +73 -0
- package/dist/clients/WalletClient.d.ts.map +1 -0
- package/dist/clients/WalletClient.js +174 -0
- package/dist/clients/X402Client.d.ts +61 -0
- package/dist/clients/X402Client.d.ts.map +1 -0
- package/dist/clients/X402Client.js +303 -0
- package/dist/index.d.mts +932 -0
- package/dist/index.d.ts +932 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1680 -0
- package/dist/index.mjs +1610 -0
- package/dist/types/index.d.ts +220 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +52 -0
- package/dist/utils/abis.d.ts +21 -0
- package/dist/utils/abis.d.ts.map +1 -0
- package/dist/utils/abis.js +134 -0
- package/dist/utils/config.d.ts +31 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +117 -0
- package/dist/utils/format.d.ts +44 -0
- package/dist/utils/format.d.ts.map +1 -0
- package/dist/utils/format.js +75 -0
- package/package.json +57 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1680 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
ACCOUNT_FACTORY_ABI: () => ACCOUNT_FACTORY_ABI,
|
|
34
|
+
AGENT_ACCOUNT_ABI: () => AGENT_ACCOUNT_ABI,
|
|
35
|
+
AGENT_REPUTATION_ABI: () => AGENT_REPUTATION_ABI,
|
|
36
|
+
AgentIdentityClient: () => AgentIdentityClient,
|
|
37
|
+
AgetherClient: () => AgetherClient,
|
|
38
|
+
AgetherError: () => AgetherError,
|
|
39
|
+
CREDIT_PROVIDER_ABI: () => CREDIT_PROVIDER_ABI,
|
|
40
|
+
ChainId: () => ChainId,
|
|
41
|
+
CreditNotActiveError: () => CreditNotActiveError,
|
|
42
|
+
CreditStatus: () => CreditStatus,
|
|
43
|
+
ERC20_ABI: () => ERC20_ABI,
|
|
44
|
+
IDENTITY_REGISTRY_ABI: () => IDENTITY_REGISTRY_ABI,
|
|
45
|
+
InsufficientCreditError: () => InsufficientCreditError,
|
|
46
|
+
LP_VAULT_ABI: () => LP_VAULT_ABI,
|
|
47
|
+
REPUTATION_CREDIT_ABI: () => REPUTATION_CREDIT_ABI,
|
|
48
|
+
ScoringClient: () => ScoringClient,
|
|
49
|
+
ScoringRejectedError: () => ScoringRejectedError,
|
|
50
|
+
VALIDATION_REGISTRY_ABI: () => VALIDATION_REGISTRY_ABI,
|
|
51
|
+
VaultClient: () => VaultClient,
|
|
52
|
+
WalletClient: () => WalletClient,
|
|
53
|
+
X402Client: () => X402Client,
|
|
54
|
+
bpsToRate: () => bpsToRate,
|
|
55
|
+
createConfig: () => createConfig,
|
|
56
|
+
formatAPR: () => formatAPR,
|
|
57
|
+
formatAddress: () => formatAddress,
|
|
58
|
+
formatHealthFactor: () => formatHealthFactor,
|
|
59
|
+
formatPercent: () => formatPercent,
|
|
60
|
+
formatTimestamp: () => formatTimestamp,
|
|
61
|
+
formatUSD: () => formatUSD,
|
|
62
|
+
formatUnits: () => formatUnits,
|
|
63
|
+
getDefaultConfig: () => getDefaultConfig,
|
|
64
|
+
getUSDCAddress: () => getUSDCAddress,
|
|
65
|
+
parseUnits: () => parseUnits,
|
|
66
|
+
rateToBps: () => rateToBps
|
|
67
|
+
});
|
|
68
|
+
module.exports = __toCommonJS(index_exports);
|
|
69
|
+
|
|
70
|
+
// src/clients/AgetherClient.ts
|
|
71
|
+
var import_ethers = require("ethers");
|
|
72
|
+
|
|
73
|
+
// src/types/index.ts
|
|
74
|
+
var CreditStatus = /* @__PURE__ */ ((CreditStatus3) => {
|
|
75
|
+
CreditStatus3[CreditStatus3["None"] = 0] = "None";
|
|
76
|
+
CreditStatus3[CreditStatus3["Pending"] = 1] = "Pending";
|
|
77
|
+
CreditStatus3[CreditStatus3["Active"] = 2] = "Active";
|
|
78
|
+
CreditStatus3[CreditStatus3["Frozen"] = 3] = "Frozen";
|
|
79
|
+
CreditStatus3[CreditStatus3["Closed"] = 4] = "Closed";
|
|
80
|
+
CreditStatus3[CreditStatus3["Defaulted"] = 5] = "Defaulted";
|
|
81
|
+
return CreditStatus3;
|
|
82
|
+
})(CreditStatus || {});
|
|
83
|
+
var ChainId = /* @__PURE__ */ ((ChainId3) => {
|
|
84
|
+
ChainId3[ChainId3["Ethereum"] = 1] = "Ethereum";
|
|
85
|
+
ChainId3[ChainId3["Base"] = 8453] = "Base";
|
|
86
|
+
ChainId3[ChainId3["BaseSepolia"] = 84532] = "BaseSepolia";
|
|
87
|
+
ChainId3[ChainId3["Sepolia"] = 11155111] = "Sepolia";
|
|
88
|
+
ChainId3[ChainId3["Hardhat"] = 31337] = "Hardhat";
|
|
89
|
+
return ChainId3;
|
|
90
|
+
})(ChainId || {});
|
|
91
|
+
var AgetherError = class extends Error {
|
|
92
|
+
constructor(message, code, details) {
|
|
93
|
+
super(message);
|
|
94
|
+
this.code = code;
|
|
95
|
+
this.details = details;
|
|
96
|
+
this.name = "AgetherError";
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
var InsufficientCreditError = class extends AgetherError {
|
|
100
|
+
constructor(available, requested) {
|
|
101
|
+
super(
|
|
102
|
+
`Insufficient credit: available ${available}, requested ${requested}`,
|
|
103
|
+
"INSUFFICIENT_CREDIT",
|
|
104
|
+
{ available: available.toString(), requested: requested.toString() }
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
var ScoringRejectedError = class extends AgetherError {
|
|
109
|
+
constructor(riskScore, reason) {
|
|
110
|
+
super(
|
|
111
|
+
`Scoring rejected: risk score ${riskScore}${reason ? `, ${reason}` : ""}`,
|
|
112
|
+
"SCORING_REJECTED",
|
|
113
|
+
{ riskScore, reason }
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
var CreditNotActiveError = class extends AgetherError {
|
|
118
|
+
constructor(account, status) {
|
|
119
|
+
super(
|
|
120
|
+
`Credit line for ${account} is not active (status: ${CreditStatus[status]})`,
|
|
121
|
+
"CREDIT_NOT_ACTIVE",
|
|
122
|
+
{ account, status: CreditStatus[status] }
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
// src/utils/abis.ts
|
|
128
|
+
var IDENTITY_REGISTRY_ABI = [
|
|
129
|
+
"function ownerOf(uint256 agentId) view returns (address)",
|
|
130
|
+
"function balanceOf(address owner) view returns (uint256)",
|
|
131
|
+
"function totalSupply() view returns (uint256)",
|
|
132
|
+
"function exists(uint256 agentId) view returns (bool)",
|
|
133
|
+
"function register() returns (uint256 agentId)",
|
|
134
|
+
"event Transfer(address indexed from, address indexed to, uint256 indexed tokenId)"
|
|
135
|
+
];
|
|
136
|
+
var ACCOUNT_FACTORY_ABI = [
|
|
137
|
+
"function getAccount(uint256 agentId) view returns (address)",
|
|
138
|
+
"function accountExists(uint256 agentId) view returns (bool)",
|
|
139
|
+
"function predictAddress(uint256 agentId) view returns (address)",
|
|
140
|
+
"function totalAccounts() view returns (uint256)",
|
|
141
|
+
"function getAgentId(address account) view returns (uint256)",
|
|
142
|
+
"function createAccount(uint256 agentId) returns (address account)",
|
|
143
|
+
"event AccountCreated(uint256 indexed agentId, address indexed account, address indexed owner)"
|
|
144
|
+
];
|
|
145
|
+
var AGENT_ACCOUNT_ABI = [
|
|
146
|
+
"function agentId() view returns (uint256)",
|
|
147
|
+
"function owner() view returns (address)",
|
|
148
|
+
"function balanceOf(address token) view returns (uint256)",
|
|
149
|
+
"function ethBalance() view returns (uint256)",
|
|
150
|
+
"function execute(address target, uint256 value, bytes data) payable returns (bytes)",
|
|
151
|
+
"function drawCredit(address creditProvider, uint256 amount)",
|
|
152
|
+
"function repayCredit(address creditProvider, uint256 amount)",
|
|
153
|
+
"function fund(address token, uint256 amount)",
|
|
154
|
+
"function withdraw(address token, uint256 amount, address to)"
|
|
155
|
+
];
|
|
156
|
+
var CREDIT_PROVIDER_ABI = [
|
|
157
|
+
"function asset() view returns (address)",
|
|
158
|
+
"function isEligible(address account) view returns (bool)",
|
|
159
|
+
"function getCreditInfo(address account) view returns (tuple(uint256 limit, uint256 used, uint256 available, uint256 accruedInterest, uint256 aprBps, bool isActive, bool requiresCollateral))",
|
|
160
|
+
"function getTotalDebt(address account) view returns (uint256)",
|
|
161
|
+
"function maxDrawable(address account) view returns (uint256)",
|
|
162
|
+
"function draw(address account, uint256 amount)",
|
|
163
|
+
"function repay(address account, uint256 amount)",
|
|
164
|
+
"event CreditDrawn(address indexed account, uint256 amount, uint256 totalUsed)",
|
|
165
|
+
"event CreditRepaid(address indexed account, uint256 amount, uint256 totalUsed)",
|
|
166
|
+
"event CreditLineOpened(address indexed account, uint256 limit, uint256 aprBps)",
|
|
167
|
+
"event CreditLineClosed(address indexed account)"
|
|
168
|
+
];
|
|
169
|
+
var REPUTATION_CREDIT_ABI = [
|
|
170
|
+
...CREDIT_PROVIDER_ABI,
|
|
171
|
+
// Application / Approval flow
|
|
172
|
+
"function applyForCredit(address account, uint256 requestedLimit)",
|
|
173
|
+
"function approveCreditLine(address account, uint256 limit, uint256 aprBps)",
|
|
174
|
+
"function rejectCreditLine(address account, string reason)",
|
|
175
|
+
"function requestLimitIncrease(address account, uint256 newRequestedLimit)",
|
|
176
|
+
"function approveLimitIncrease(address account, uint256 newLimit)",
|
|
177
|
+
"function freezeCreditLine(address account)",
|
|
178
|
+
"function unfreezeCreditLine(address account)",
|
|
179
|
+
// Admin
|
|
180
|
+
"function setCreditLine(address account, uint256 limit, uint256 aprBps)",
|
|
181
|
+
"function openScoredCreditLine(address account)",
|
|
182
|
+
"function closeCreditLine(address account)",
|
|
183
|
+
"function declareDefault(address account)",
|
|
184
|
+
// View
|
|
185
|
+
"function getCreditLineStatus(address account) view returns (uint8)",
|
|
186
|
+
"function getCreditLineDetails(address account) view returns (uint256 agentId, uint256 limit, uint256 used, uint256 aprBps, uint256 accruedInterest, uint256 requestedLimit, uint256 createdAt, uint256 lastActivityAt, uint8 status)",
|
|
187
|
+
"function getAgentAccount(uint256 agentId) view returns (address)",
|
|
188
|
+
"function previewScoredLimit(uint256 agentId) view returns (uint256 limit, uint256 score, bool eligible)",
|
|
189
|
+
"function dailyDrawLimit() view returns (uint256)",
|
|
190
|
+
"function totalBorrowed() view returns (uint256)",
|
|
191
|
+
// Events
|
|
192
|
+
"event CreditApplied(uint256 indexed creditLineId, uint256 indexed agentId, uint256 requestedLimit)",
|
|
193
|
+
"event CreditApproved(uint256 indexed creditLineId, uint256 limit, uint256 aprBps)",
|
|
194
|
+
"event CreditRejected(uint256 indexed creditLineId, string reason)",
|
|
195
|
+
"event CreditFrozen(uint256 indexed creditLineId)",
|
|
196
|
+
"event CreditUnfrozen(uint256 indexed creditLineId)",
|
|
197
|
+
"event DefaultDeclared(address indexed account, uint256 amount)"
|
|
198
|
+
];
|
|
199
|
+
var LP_VAULT_ABI = [
|
|
200
|
+
"function asset() view returns (address)",
|
|
201
|
+
"function totalAssets() view returns (uint256)",
|
|
202
|
+
"function totalSupply() view returns (uint256)",
|
|
203
|
+
"function balanceOf(address account) view returns (uint256)",
|
|
204
|
+
"function convertToShares(uint256 assets) view returns (uint256)",
|
|
205
|
+
"function convertToAssets(uint256 shares) view returns (uint256)",
|
|
206
|
+
"function previewDeposit(uint256 assets) view returns (uint256)",
|
|
207
|
+
"function previewRedeem(uint256 shares) view returns (uint256)",
|
|
208
|
+
"function deposit(uint256 assets, address receiver) returns (uint256)",
|
|
209
|
+
"function withdraw(uint256 assets, address receiver, address owner) returns (uint256)",
|
|
210
|
+
"function redeem(uint256 shares, address receiver, address owner) returns (uint256)",
|
|
211
|
+
"function totalBorrowed() view returns (uint256)",
|
|
212
|
+
"function availableLiquidity() view returns (uint256)",
|
|
213
|
+
"event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares)",
|
|
214
|
+
"event Withdraw(address indexed sender, address indexed receiver, address indexed owner, uint256 assets, uint256 shares)"
|
|
215
|
+
];
|
|
216
|
+
var AGENT_REPUTATION_ABI = [
|
|
217
|
+
"function getReputation(uint256 agentId) view returns (tuple(uint256 totalBorrowed, uint256 totalRepaid, uint256 totalInterestPaid, uint256 onTimePayments, uint256 latePayments, uint256 missedPayments, uint256 peakUtilization, uint256 avgUtilization, uint256 utilizationSamples, uint256 firstActivityAt, uint256 lastActivityAt, uint256 lastScoreUpdate, uint256 creditScore, uint256 creditLinesOpened, uint256 lastCreditOpenedAt, uint256 currentOutstanding, uint256 currentLimit, uint256 totalDeposits, uint256 totalWithdrawals))",
|
|
218
|
+
"function getCreditScore(uint256 agentId) view returns (uint256)",
|
|
219
|
+
"function getBayesianScore(uint256 agentId) view returns (uint256 combinedScore, uint256 confidence)",
|
|
220
|
+
"function getRecommendedLimit(uint256 agentId, uint256 baseLimit) view returns (uint256)",
|
|
221
|
+
"function isEligible(uint256 agentId, uint256 minScore) view returns (bool eligible, uint256 currentScore)",
|
|
222
|
+
"function getDecayedScore(uint256 agentId) view returns (uint256)",
|
|
223
|
+
"function getScoreExplanation(uint256 agentId) view returns (uint256 historical, uint256 currentRisk, uint256 utilization, uint256 onChainTx, uint256 newCredit, uint256 rawScore, uint256 decayedScore)",
|
|
224
|
+
"function getLoanPositions(uint256 agentId) view returns (tuple(uint256 amount, uint256 collateral, uint256 ltvBps, uint256 timestamp, bool liquidated, bool repaid, bool active)[])",
|
|
225
|
+
"function stressMultiplier() view returns (uint256)",
|
|
226
|
+
"function decayPeriod() view returns (uint256)"
|
|
227
|
+
];
|
|
228
|
+
var VALIDATION_REGISTRY_ABI = [
|
|
229
|
+
"function isAgentCodeApproved(uint256 agentId) view returns (bool)",
|
|
230
|
+
"function isAgentCodeApprovedForTag(uint256 agentId, string tag) view returns (bool)",
|
|
231
|
+
"function getAgentValidations(uint256 agentId) view returns (bytes32[])"
|
|
232
|
+
];
|
|
233
|
+
var ERC20_ABI = [
|
|
234
|
+
"function balanceOf(address account) view returns (uint256)",
|
|
235
|
+
"function allowance(address owner, address spender) view returns (uint256)",
|
|
236
|
+
"function approve(address spender, uint256 amount) returns (bool)",
|
|
237
|
+
"function transfer(address to, uint256 amount) returns (bool)",
|
|
238
|
+
"function transferFrom(address from, address to, uint256 amount) returns (bool)",
|
|
239
|
+
"function decimals() view returns (uint8)",
|
|
240
|
+
"function symbol() view returns (string)"
|
|
241
|
+
];
|
|
242
|
+
|
|
243
|
+
// src/utils/config.ts
|
|
244
|
+
var CONTRACT_ADDRESSES = {
|
|
245
|
+
[1 /* Ethereum */]: {
|
|
246
|
+
accountFactory: "0x0000000000000000000000000000000000000000",
|
|
247
|
+
reputationCredit: "0x0000000000000000000000000000000000000000",
|
|
248
|
+
lpVault: "0x0000000000000000000000000000000000000000",
|
|
249
|
+
validationRegistry: "0x0000000000000000000000000000000000000000",
|
|
250
|
+
usdc: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
251
|
+
identityRegistry: "0x8004A169FB4a3325136EB29fA0ceB6D2e539a432",
|
|
252
|
+
agentReputation: "0x0000000000000000000000000000000000000000"
|
|
253
|
+
},
|
|
254
|
+
[8453 /* Base */]: {
|
|
255
|
+
accountFactory: "0xeB72f248Ad9F4bf4024e8D9da75cf7AAD37B58f5",
|
|
256
|
+
reputationCredit: "0x57B2B4ef3e7B8BE5FC86c6369602125d240F552A",
|
|
257
|
+
lpVault: "0x612A80D6c3175F8283e9C7EE71d5177fE9acc338",
|
|
258
|
+
validationRegistry: "0x8842f2383A86134Dd80c3Ecf6Bbae2e38396A5ec",
|
|
259
|
+
usdc: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
260
|
+
identityRegistry: "0x8004A169FB4a3325136EB29fA0ceB6D2e539a432",
|
|
261
|
+
agentReputation: "0xF1bed094D4E33E47CC8C72E086FFFde09e2211b4",
|
|
262
|
+
morphoCredit: "0x7dFfa40E17471F7f26F5662D0F07a31977F47BeB"
|
|
263
|
+
},
|
|
264
|
+
[84532 /* BaseSepolia */]: {
|
|
265
|
+
accountFactory: "0x0000000000000000000000000000000000000000",
|
|
266
|
+
reputationCredit: "0x0000000000000000000000000000000000000000",
|
|
267
|
+
lpVault: "0x0000000000000000000000000000000000000000",
|
|
268
|
+
validationRegistry: "0x0000000000000000000000000000000000000000",
|
|
269
|
+
usdc: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
|
|
270
|
+
identityRegistry: "0x8004A818BFB912233c491871b3d84c89A494BD9e",
|
|
271
|
+
agentReputation: "0x0000000000000000000000000000000000000000"
|
|
272
|
+
},
|
|
273
|
+
[11155111 /* Sepolia */]: {
|
|
274
|
+
accountFactory: "0x0000000000000000000000000000000000000000",
|
|
275
|
+
reputationCredit: "0x0000000000000000000000000000000000000000",
|
|
276
|
+
lpVault: "0x0000000000000000000000000000000000000000",
|
|
277
|
+
validationRegistry: "0x0000000000000000000000000000000000000000",
|
|
278
|
+
usdc: "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238",
|
|
279
|
+
identityRegistry: "0x8004A818BFB912233c491871b3d84c89A494BD9e",
|
|
280
|
+
agentReputation: "0x0000000000000000000000000000000000000000"
|
|
281
|
+
},
|
|
282
|
+
[31337 /* Hardhat */]: {
|
|
283
|
+
accountFactory: "0x0000000000000000000000000000000000000000",
|
|
284
|
+
reputationCredit: "0x0000000000000000000000000000000000000000",
|
|
285
|
+
lpVault: "0x0000000000000000000000000000000000000000",
|
|
286
|
+
validationRegistry: "0x0000000000000000000000000000000000000000",
|
|
287
|
+
usdc: "0x56d4d6aEe0278c5Df2FA23Ecb32eC146C9446FDf",
|
|
288
|
+
identityRegistry: "0x8004A169FB4a3325136EB29fA0ceB6D2e539a432",
|
|
289
|
+
agentReputation: "0x0000000000000000000000000000000000000000",
|
|
290
|
+
morphoCredit: "0x0000000000000000000000000000000000000000"
|
|
291
|
+
}
|
|
292
|
+
};
|
|
293
|
+
var RPC_URLS = {
|
|
294
|
+
[1 /* Ethereum */]: "https://ethereum-rpc.publicnode.com",
|
|
295
|
+
[8453 /* Base */]: "https://base-rpc.publicnode.com",
|
|
296
|
+
[84532 /* BaseSepolia */]: "https://sepolia.base.org",
|
|
297
|
+
[11155111 /* Sepolia */]: "https://rpc.sepolia.org",
|
|
298
|
+
[31337 /* Hardhat */]: "http://127.0.0.1:8545"
|
|
299
|
+
};
|
|
300
|
+
var SCORING_ENDPOINTS = {
|
|
301
|
+
[1 /* Ethereum */]: "https://scoring.agether.ai/v1",
|
|
302
|
+
[8453 /* Base */]: "http://95.179.189.214:3001",
|
|
303
|
+
[84532 /* BaseSepolia */]: "http://95.179.189.214:3001",
|
|
304
|
+
[11155111 /* Sepolia */]: "https://scoring-testnet.agether.ai/v1",
|
|
305
|
+
[31337 /* Hardhat */]: "http://127.0.0.1:3001"
|
|
306
|
+
};
|
|
307
|
+
function getDefaultConfig(chainId) {
|
|
308
|
+
return {
|
|
309
|
+
chainId,
|
|
310
|
+
rpcUrl: RPC_URLS[chainId],
|
|
311
|
+
contracts: CONTRACT_ADDRESSES[chainId],
|
|
312
|
+
scoringEndpoint: SCORING_ENDPOINTS[chainId]
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
function createConfig(chainId, options) {
|
|
316
|
+
const defaultConfig = getDefaultConfig(chainId);
|
|
317
|
+
return {
|
|
318
|
+
...defaultConfig,
|
|
319
|
+
...options,
|
|
320
|
+
contracts: {
|
|
321
|
+
...defaultConfig.contracts,
|
|
322
|
+
...options?.contracts
|
|
323
|
+
}
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
function getUSDCAddress(chainId) {
|
|
327
|
+
return CONTRACT_ADDRESSES[chainId].usdc;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// src/clients/AgetherClient.ts
|
|
331
|
+
var AgetherClient = class _AgetherClient {
|
|
332
|
+
/**
|
|
333
|
+
* Undercollateralized credit is disabled for now.
|
|
334
|
+
* All credit operations go through MorphoCredit (overcollateralized).
|
|
335
|
+
*/
|
|
336
|
+
_requireUndercollateralizedEnabled() {
|
|
337
|
+
throw new AgetherError(
|
|
338
|
+
"Undercollateralized credit is not available yet. Use MorphoCredit for overcollateralized lending via the CLI: agether morpho-deposit / morpho-draw / morpho-repay",
|
|
339
|
+
"UNDERCOLLATERALIZED_NOT_AVAILABLE"
|
|
340
|
+
);
|
|
341
|
+
}
|
|
342
|
+
constructor(options) {
|
|
343
|
+
this.config = options.config;
|
|
344
|
+
this.signer = options.signer;
|
|
345
|
+
this.agentId = options.agentId;
|
|
346
|
+
const provider = options.signer.provider;
|
|
347
|
+
if (!provider) {
|
|
348
|
+
throw new AgetherError("Signer must have a provider", "NO_PROVIDER");
|
|
349
|
+
}
|
|
350
|
+
this.accountFactory = new import_ethers.Contract(
|
|
351
|
+
options.config.contracts.accountFactory,
|
|
352
|
+
ACCOUNT_FACTORY_ABI,
|
|
353
|
+
options.signer
|
|
354
|
+
);
|
|
355
|
+
this.reputationCredit = new import_ethers.Contract(
|
|
356
|
+
options.config.contracts.reputationCredit,
|
|
357
|
+
REPUTATION_CREDIT_ABI,
|
|
358
|
+
options.signer
|
|
359
|
+
);
|
|
360
|
+
}
|
|
361
|
+
// ============ Static Factory ============
|
|
362
|
+
/**
|
|
363
|
+
* Create client from private key.
|
|
364
|
+
*
|
|
365
|
+
* Simplest usage — only needs key, agentId, and chainId:
|
|
366
|
+
* AgetherClient.fromPrivateKey(key, 42n, ChainId.Sepolia)
|
|
367
|
+
*
|
|
368
|
+
* All contract addresses and RPC URLs are resolved automatically.
|
|
369
|
+
*/
|
|
370
|
+
static fromPrivateKey(privateKey, agentId, chainIdOrConfig) {
|
|
371
|
+
const config = typeof chainIdOrConfig === "number" ? getDefaultConfig(chainIdOrConfig) : chainIdOrConfig;
|
|
372
|
+
const provider = new import_ethers.ethers.JsonRpcProvider(config.rpcUrl);
|
|
373
|
+
const signer = new import_ethers.ethers.Wallet(privateKey, provider);
|
|
374
|
+
return new _AgetherClient({ config, signer, agentId });
|
|
375
|
+
}
|
|
376
|
+
// ============ Account Management ============
|
|
377
|
+
/**
|
|
378
|
+
* Create an AgentAccount (smart wallet) for this agent.
|
|
379
|
+
* Returns the account address.
|
|
380
|
+
*/
|
|
381
|
+
async createAccount() {
|
|
382
|
+
const tx = await this.accountFactory.createAccount(this.agentId);
|
|
383
|
+
const receipt = await tx.wait();
|
|
384
|
+
const event = receipt.logs.map((log) => {
|
|
385
|
+
try {
|
|
386
|
+
return this.accountFactory.interface.parseLog(log);
|
|
387
|
+
} catch {
|
|
388
|
+
return null;
|
|
389
|
+
}
|
|
390
|
+
}).find((e) => e?.name === "AccountCreated");
|
|
391
|
+
if (event) {
|
|
392
|
+
this.accountAddress = event.args.account;
|
|
393
|
+
} else {
|
|
394
|
+
this.accountAddress = await this.accountFactory.getAccount(this.agentId);
|
|
395
|
+
}
|
|
396
|
+
return this.accountAddress;
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* Get the AgentAccount address for this agent.
|
|
400
|
+
*/
|
|
401
|
+
async getAccountAddress() {
|
|
402
|
+
if (this.accountAddress) return this.accountAddress;
|
|
403
|
+
const addr = await this.accountFactory.getAccount(this.agentId);
|
|
404
|
+
if (addr === import_ethers.ethers.ZeroAddress) {
|
|
405
|
+
throw new AgetherError(
|
|
406
|
+
"No account found. Create one first with createAccount().",
|
|
407
|
+
"NO_ACCOUNT"
|
|
408
|
+
);
|
|
409
|
+
}
|
|
410
|
+
this.accountAddress = addr;
|
|
411
|
+
return addr;
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* Check if an account already exists.
|
|
415
|
+
*/
|
|
416
|
+
async accountExists() {
|
|
417
|
+
return this.accountFactory.accountExists(this.agentId);
|
|
418
|
+
}
|
|
419
|
+
// ============ Credit Application ============
|
|
420
|
+
/**
|
|
421
|
+
* Apply for a credit line.
|
|
422
|
+
* @deprecated Undercollateralized credit is not available yet. Use MorphoCredit.
|
|
423
|
+
*/
|
|
424
|
+
async apply(_limitOrApplication) {
|
|
425
|
+
this._requireUndercollateralizedEnabled();
|
|
426
|
+
}
|
|
427
|
+
// ============ Credit Line Info ============
|
|
428
|
+
/**
|
|
429
|
+
* Get full credit line details from ReputationCredit.
|
|
430
|
+
*/
|
|
431
|
+
async getCreditLine() {
|
|
432
|
+
const account = await this.getAccountAddress();
|
|
433
|
+
const data = await this.reputationCredit.getCreditLineDetails(account);
|
|
434
|
+
return {
|
|
435
|
+
agentId: data[0],
|
|
436
|
+
limit: data[1],
|
|
437
|
+
used: data[2],
|
|
438
|
+
aprBps: data[3],
|
|
439
|
+
accruedInterest: data[4],
|
|
440
|
+
requestedLimit: data[5],
|
|
441
|
+
createdAt: data[6],
|
|
442
|
+
lastActivityAt: data[7],
|
|
443
|
+
status: Number(data[8])
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* Get ICreditProvider.CreditInfo view.
|
|
448
|
+
*/
|
|
449
|
+
async getCreditInfo() {
|
|
450
|
+
const account = await this.getAccountAddress();
|
|
451
|
+
const info = await this.reputationCredit.getCreditInfo(account);
|
|
452
|
+
return {
|
|
453
|
+
limit: info.limit,
|
|
454
|
+
used: info.used,
|
|
455
|
+
available: info.available,
|
|
456
|
+
accruedInterest: info.accruedInterest,
|
|
457
|
+
aprBps: info.aprBps,
|
|
458
|
+
isActive: info.isActive,
|
|
459
|
+
requiresCollateral: info.requiresCollateral
|
|
460
|
+
};
|
|
461
|
+
}
|
|
462
|
+
/**
|
|
463
|
+
* Get credit line status.
|
|
464
|
+
*/
|
|
465
|
+
async getStatus() {
|
|
466
|
+
const account = await this.getAccountAddress();
|
|
467
|
+
const status = await this.reputationCredit.getCreditLineStatus(account);
|
|
468
|
+
return Number(status);
|
|
469
|
+
}
|
|
470
|
+
/**
|
|
471
|
+
* Get available credit.
|
|
472
|
+
*/
|
|
473
|
+
async getAvailableCredit() {
|
|
474
|
+
const account = await this.getAccountAddress();
|
|
475
|
+
return this.reputationCredit.maxDrawable(account);
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* Get total debt (principal + interest).
|
|
479
|
+
*/
|
|
480
|
+
async getTotalDebt() {
|
|
481
|
+
const account = await this.getAccountAddress();
|
|
482
|
+
return this.reputationCredit.getTotalDebt(account);
|
|
483
|
+
}
|
|
484
|
+
/**
|
|
485
|
+
* Check if agent is eligible for credit.
|
|
486
|
+
*/
|
|
487
|
+
async isEligible() {
|
|
488
|
+
const account = await this.getAccountAddress();
|
|
489
|
+
return this.reputationCredit.isEligible(account);
|
|
490
|
+
}
|
|
491
|
+
// ============ Draw & Repay ============
|
|
492
|
+
/**
|
|
493
|
+
* Draw funds from credit line via AgentAccount.
|
|
494
|
+
* @deprecated Undercollateralized credit is not available yet. Use MorphoCredit.
|
|
495
|
+
*/
|
|
496
|
+
async draw(_amountOrRequest) {
|
|
497
|
+
this._requireUndercollateralizedEnabled();
|
|
498
|
+
}
|
|
499
|
+
/**
|
|
500
|
+
* Repay credit line debt via AgentAccount.
|
|
501
|
+
* @deprecated Undercollateralized credit is not available yet. Use MorphoCredit.
|
|
502
|
+
*/
|
|
503
|
+
async repay(_amountOrRequest) {
|
|
504
|
+
this._requireUndercollateralizedEnabled();
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* Repay full debt.
|
|
508
|
+
* @deprecated Undercollateralized credit is not available yet. Use MorphoCredit.
|
|
509
|
+
*/
|
|
510
|
+
async repayFull() {
|
|
511
|
+
this._requireUndercollateralizedEnabled();
|
|
512
|
+
}
|
|
513
|
+
// ============ Limit Increase ============
|
|
514
|
+
/**
|
|
515
|
+
* Request a limit increase on-chain.
|
|
516
|
+
* @deprecated Undercollateralized credit is not available yet. Use MorphoCredit.
|
|
517
|
+
*/
|
|
518
|
+
async requestLimitIncrease(_newLimit) {
|
|
519
|
+
this._requireUndercollateralizedEnabled();
|
|
520
|
+
}
|
|
521
|
+
// ============ x402 Payments ============
|
|
522
|
+
/**
|
|
523
|
+
* Pay for a service using credit line.
|
|
524
|
+
* @deprecated Undercollateralized credit is not available yet. Use MorphoCredit.
|
|
525
|
+
*/
|
|
526
|
+
async pay(_service, _amount, _asset = "USDC") {
|
|
527
|
+
this._requireUndercollateralizedEnabled();
|
|
528
|
+
}
|
|
529
|
+
// ============ Getters ============
|
|
530
|
+
get chainId() {
|
|
531
|
+
return this.config.chainId;
|
|
532
|
+
}
|
|
533
|
+
get contracts() {
|
|
534
|
+
return this.config.contracts;
|
|
535
|
+
}
|
|
536
|
+
get currentAccountAddress() {
|
|
537
|
+
return this.accountAddress;
|
|
538
|
+
}
|
|
539
|
+
/** Get the underlying signer */
|
|
540
|
+
getSigner() {
|
|
541
|
+
return this.signer;
|
|
542
|
+
}
|
|
543
|
+
};
|
|
544
|
+
|
|
545
|
+
// src/clients/ScoringClient.ts
|
|
546
|
+
var import_axios = __toESM(require("axios"));
|
|
547
|
+
var ScoringClient = class {
|
|
548
|
+
constructor(endpoint, apiKey) {
|
|
549
|
+
this.client = import_axios.default.create({
|
|
550
|
+
baseURL: endpoint,
|
|
551
|
+
headers: {
|
|
552
|
+
"Content-Type": "application/json",
|
|
553
|
+
...apiKey && { Authorization: `Bearer ${apiKey}` }
|
|
554
|
+
},
|
|
555
|
+
timeout: 3e4
|
|
556
|
+
});
|
|
557
|
+
}
|
|
558
|
+
/**
|
|
559
|
+
* Evaluate a credit application (does not submit on-chain)
|
|
560
|
+
* Backend endpoint: POST /credit/evaluate
|
|
561
|
+
*/
|
|
562
|
+
async evaluateCredit(request) {
|
|
563
|
+
try {
|
|
564
|
+
const response = await this.client.post("/credit/evaluate", {
|
|
565
|
+
agentId: request.agentId.toString(),
|
|
566
|
+
requestedLimit: request.requestedLimit.toString(),
|
|
567
|
+
codeHash: request.codeHash
|
|
568
|
+
});
|
|
569
|
+
const data = response.data;
|
|
570
|
+
if (!data.approved) {
|
|
571
|
+
throw new ScoringRejectedError(data.riskScore, data.reason);
|
|
572
|
+
}
|
|
573
|
+
return {
|
|
574
|
+
approved: data.approved,
|
|
575
|
+
limit: BigInt(data.limit),
|
|
576
|
+
aprBps: data.aprBps,
|
|
577
|
+
riskScore: data.riskScore,
|
|
578
|
+
bayesianScore: data.bayesianScore ?? 0,
|
|
579
|
+
confidence: data.confidence ?? 0,
|
|
580
|
+
reason: data.reason
|
|
581
|
+
};
|
|
582
|
+
} catch (error) {
|
|
583
|
+
if (error instanceof ScoringRejectedError) {
|
|
584
|
+
throw error;
|
|
585
|
+
}
|
|
586
|
+
if (import_axios.default.isAxiosError(error)) {
|
|
587
|
+
throw new AgetherError(
|
|
588
|
+
`Scoring request failed: ${error.message}`,
|
|
589
|
+
"SCORING_REQUEST_FAILED",
|
|
590
|
+
{ status: error.response?.status }
|
|
591
|
+
);
|
|
592
|
+
}
|
|
593
|
+
throw error;
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
/**
|
|
597
|
+
* Process a credit application (evaluate + on-chain approve/reject)
|
|
598
|
+
* Backend endpoint: POST /admin/credit/process
|
|
599
|
+
*
|
|
600
|
+
* Requires the credit application to be in Pending status on-chain
|
|
601
|
+
* (agent must have called applyForCredit first).
|
|
602
|
+
*/
|
|
603
|
+
async processApplication(agentId, requestedLimit, codeHash) {
|
|
604
|
+
try {
|
|
605
|
+
const response = await this.client.post("/admin/credit/process", {
|
|
606
|
+
agentId: agentId.toString(),
|
|
607
|
+
requestedLimit: requestedLimit.toString(),
|
|
608
|
+
codeHash
|
|
609
|
+
});
|
|
610
|
+
return response.data;
|
|
611
|
+
} catch (error) {
|
|
612
|
+
if (import_axios.default.isAxiosError(error)) {
|
|
613
|
+
if (error.response?.status === 400) {
|
|
614
|
+
return error.response.data;
|
|
615
|
+
}
|
|
616
|
+
throw new AgetherError(
|
|
617
|
+
`Process application failed: ${error.message}`,
|
|
618
|
+
"PROCESS_APPLICATION_FAILED",
|
|
619
|
+
{ status: error.response?.status }
|
|
620
|
+
);
|
|
621
|
+
}
|
|
622
|
+
throw error;
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
/**
|
|
626
|
+
* Get credit score for an agent
|
|
627
|
+
* Backend endpoint: GET /credit/score/:agentId
|
|
628
|
+
*/
|
|
629
|
+
async getCreditScore(agentId) {
|
|
630
|
+
const response = await this.client.get(
|
|
631
|
+
`/credit/score/${agentId.toString()}`
|
|
632
|
+
);
|
|
633
|
+
return response.data;
|
|
634
|
+
}
|
|
635
|
+
/**
|
|
636
|
+
* Preview scored limit for an agent
|
|
637
|
+
* Backend endpoint: GET /credit/preview/:agentId
|
|
638
|
+
*/
|
|
639
|
+
async previewScoredLimit(agentId) {
|
|
640
|
+
const response = await this.client.get(
|
|
641
|
+
`/credit/preview/${agentId.toString()}`
|
|
642
|
+
);
|
|
643
|
+
return response.data;
|
|
644
|
+
}
|
|
645
|
+
/**
|
|
646
|
+
* Get credit line info for an agent
|
|
647
|
+
* Backend endpoint: GET /credit/agent/:agentId
|
|
648
|
+
*/
|
|
649
|
+
async getAgentCredit(agentId) {
|
|
650
|
+
const response = await this.client.get(
|
|
651
|
+
`/credit/agent/${agentId.toString()}`
|
|
652
|
+
);
|
|
653
|
+
return response.data;
|
|
654
|
+
}
|
|
655
|
+
/**
|
|
656
|
+
* Get protocol info
|
|
657
|
+
* Backend endpoint: GET /credit/protocol-info
|
|
658
|
+
*/
|
|
659
|
+
async getProtocolInfo() {
|
|
660
|
+
const response = await this.client.get("/credit/protocol-info");
|
|
661
|
+
return response.data;
|
|
662
|
+
}
|
|
663
|
+
/**
|
|
664
|
+
* Get backend service status
|
|
665
|
+
* Backend endpoint: GET /status
|
|
666
|
+
*/
|
|
667
|
+
async getStatus() {
|
|
668
|
+
const response = await this.client.get("/status");
|
|
669
|
+
return response.data;
|
|
670
|
+
}
|
|
671
|
+
/**
|
|
672
|
+
* Get full OCCR score explanation with subscores, decay, and loan positions
|
|
673
|
+
* Backend endpoint: GET /agents/:agentId/score-explanation
|
|
674
|
+
*/
|
|
675
|
+
async getScoreExplanation(agentId) {
|
|
676
|
+
const response = await this.client.get(
|
|
677
|
+
`/agents/${agentId.toString()}/score-explanation`
|
|
678
|
+
);
|
|
679
|
+
return response.data;
|
|
680
|
+
}
|
|
681
|
+
};
|
|
682
|
+
|
|
683
|
+
// src/clients/VaultClient.ts
|
|
684
|
+
var import_ethers2 = require("ethers");
|
|
685
|
+
var VaultClient = class {
|
|
686
|
+
constructor(options) {
|
|
687
|
+
this.config = options.config;
|
|
688
|
+
this.signer = options.signer;
|
|
689
|
+
this.vault = new import_ethers2.Contract(
|
|
690
|
+
options.config.contracts.lpVault,
|
|
691
|
+
LP_VAULT_ABI,
|
|
692
|
+
options.signer
|
|
693
|
+
);
|
|
694
|
+
}
|
|
695
|
+
// ============ LP Operations ============
|
|
696
|
+
/**
|
|
697
|
+
* Deposit assets to vault
|
|
698
|
+
*/
|
|
699
|
+
async deposit(amount) {
|
|
700
|
+
const asset = await this.getAsset();
|
|
701
|
+
const allowance = await asset.allowance(
|
|
702
|
+
await this.signer.getAddress(),
|
|
703
|
+
this.config.contracts.lpVault
|
|
704
|
+
);
|
|
705
|
+
if (allowance < amount) {
|
|
706
|
+
const approveTx = await asset.approve(
|
|
707
|
+
this.config.contracts.lpVault,
|
|
708
|
+
amount
|
|
709
|
+
);
|
|
710
|
+
await approveTx.wait();
|
|
711
|
+
}
|
|
712
|
+
const receiver = await this.signer.getAddress();
|
|
713
|
+
const tx = await this.vault.deposit(amount, receiver);
|
|
714
|
+
const receipt = await tx.wait();
|
|
715
|
+
return {
|
|
716
|
+
txHash: receipt.hash,
|
|
717
|
+
blockNumber: receipt.blockNumber,
|
|
718
|
+
status: receipt.status === 1 ? "success" : "failed",
|
|
719
|
+
gasUsed: receipt.gasUsed
|
|
720
|
+
};
|
|
721
|
+
}
|
|
722
|
+
/**
|
|
723
|
+
* Withdraw assets from vault
|
|
724
|
+
*/
|
|
725
|
+
async withdraw(amount) {
|
|
726
|
+
const receiver = await this.signer.getAddress();
|
|
727
|
+
const owner = receiver;
|
|
728
|
+
const tx = await this.vault.withdraw(amount, receiver, owner);
|
|
729
|
+
const receipt = await tx.wait();
|
|
730
|
+
return {
|
|
731
|
+
txHash: receipt.hash,
|
|
732
|
+
blockNumber: receipt.blockNumber,
|
|
733
|
+
status: receipt.status === 1 ? "success" : "failed",
|
|
734
|
+
gasUsed: receipt.gasUsed
|
|
735
|
+
};
|
|
736
|
+
}
|
|
737
|
+
/**
|
|
738
|
+
* Redeem shares for assets
|
|
739
|
+
*/
|
|
740
|
+
async redeem(shares) {
|
|
741
|
+
const receiver = await this.signer.getAddress();
|
|
742
|
+
const owner = receiver;
|
|
743
|
+
const tx = await this.vault.redeem(shares, receiver, owner);
|
|
744
|
+
const receipt = await tx.wait();
|
|
745
|
+
return {
|
|
746
|
+
txHash: receipt.hash,
|
|
747
|
+
blockNumber: receipt.blockNumber,
|
|
748
|
+
status: receipt.status === 1 ? "success" : "failed",
|
|
749
|
+
gasUsed: receipt.gasUsed
|
|
750
|
+
};
|
|
751
|
+
}
|
|
752
|
+
// ============ View Functions ============
|
|
753
|
+
/**
|
|
754
|
+
* Get vault statistics
|
|
755
|
+
*/
|
|
756
|
+
async getStats() {
|
|
757
|
+
const [totalAssets, totalBorrowed, availableLiquidity] = await Promise.all([
|
|
758
|
+
this.vault.totalAssets(),
|
|
759
|
+
this.vault.totalBorrowed(),
|
|
760
|
+
this.vault.availableLiquidity()
|
|
761
|
+
]);
|
|
762
|
+
const utilizationRate = totalAssets > 0n ? Number(totalBorrowed * 10000n / totalAssets) / 100 : 0;
|
|
763
|
+
const totalSupply = await this.vault.totalSupply();
|
|
764
|
+
const sharePrice = totalSupply > 0n ? totalAssets * BigInt(1e18) / totalSupply : BigInt(1e18);
|
|
765
|
+
return {
|
|
766
|
+
totalAssets,
|
|
767
|
+
totalBorrowed,
|
|
768
|
+
availableLiquidity,
|
|
769
|
+
utilizationRate,
|
|
770
|
+
sharePrice
|
|
771
|
+
};
|
|
772
|
+
}
|
|
773
|
+
/**
|
|
774
|
+
* Get LP position
|
|
775
|
+
*/
|
|
776
|
+
async getPosition(address) {
|
|
777
|
+
const owner = address || await this.signer.getAddress();
|
|
778
|
+
const shares = await this.vault.balanceOf(owner);
|
|
779
|
+
const assets = await this.vault.convertToAssets(shares);
|
|
780
|
+
const pendingYield = 0n;
|
|
781
|
+
return {
|
|
782
|
+
shares,
|
|
783
|
+
assets,
|
|
784
|
+
pendingYield
|
|
785
|
+
};
|
|
786
|
+
}
|
|
787
|
+
/**
|
|
788
|
+
* Preview deposit (how many shares for assets)
|
|
789
|
+
*/
|
|
790
|
+
async previewDeposit(assets) {
|
|
791
|
+
return await this.vault.previewDeposit(assets);
|
|
792
|
+
}
|
|
793
|
+
/**
|
|
794
|
+
* Preview withdraw (how many assets for shares)
|
|
795
|
+
*/
|
|
796
|
+
async previewRedeem(shares) {
|
|
797
|
+
return await this.vault.previewRedeem(shares);
|
|
798
|
+
}
|
|
799
|
+
/**
|
|
800
|
+
* Check if withdrawal is allowed (sufficient liquidity)
|
|
801
|
+
*/
|
|
802
|
+
async canWithdraw(assets) {
|
|
803
|
+
const liquidity = await this.vault.availableLiquidity();
|
|
804
|
+
return liquidity >= assets;
|
|
805
|
+
}
|
|
806
|
+
/**
|
|
807
|
+
* Get current APY estimate
|
|
808
|
+
*/
|
|
809
|
+
async estimateAPY() {
|
|
810
|
+
const stats = await this.getStats();
|
|
811
|
+
const avgAPR = 1200;
|
|
812
|
+
const protocolFee = 1e3;
|
|
813
|
+
const lpYield = avgAPR * (1e4 - protocolFee) / 1e4;
|
|
814
|
+
const effectiveYield = lpYield * stats.utilizationRate / 100;
|
|
815
|
+
return effectiveYield / 100;
|
|
816
|
+
}
|
|
817
|
+
// ============ Utility ============
|
|
818
|
+
async getAsset() {
|
|
819
|
+
if (!this.asset) {
|
|
820
|
+
const assetAddress = await this.vault.asset();
|
|
821
|
+
this.asset = new import_ethers2.Contract(assetAddress, ERC20_ABI, this.signer);
|
|
822
|
+
}
|
|
823
|
+
return this.asset;
|
|
824
|
+
}
|
|
825
|
+
/**
|
|
826
|
+
* Get underlying asset address
|
|
827
|
+
*/
|
|
828
|
+
async getAssetAddress() {
|
|
829
|
+
return await this.vault.asset();
|
|
830
|
+
}
|
|
831
|
+
/**
|
|
832
|
+
* Get vault share token address
|
|
833
|
+
*/
|
|
834
|
+
getVaultAddress() {
|
|
835
|
+
return this.config.contracts.lpVault;
|
|
836
|
+
}
|
|
837
|
+
};
|
|
838
|
+
|
|
839
|
+
// src/clients/AgentIdentityClient.ts
|
|
840
|
+
var import_ethers3 = require("ethers");
|
|
841
|
+
var ERC8004_IDENTITY_ABI = [
|
|
842
|
+
// Registration
|
|
843
|
+
"function register() returns (uint256)",
|
|
844
|
+
"function register(string agentURI) returns (uint256)",
|
|
845
|
+
"function register(string agentURI, tuple(string key, bytes value)[] metadata) returns (uint256)",
|
|
846
|
+
// Management
|
|
847
|
+
"function setAgentURI(uint256 agentId, string newURI)",
|
|
848
|
+
"function setMetadata(uint256 agentId, string metadataKey, bytes metadataValue)",
|
|
849
|
+
"function getMetadata(uint256 agentId, string metadataKey) view returns (bytes)",
|
|
850
|
+
// ERC-721 standard
|
|
851
|
+
"function ownerOf(uint256 tokenId) view returns (address)",
|
|
852
|
+
"function balanceOf(address owner) view returns (uint256)",
|
|
853
|
+
"function tokenURI(uint256 tokenId) view returns (string)",
|
|
854
|
+
"function transferFrom(address from, address to, uint256 tokenId)",
|
|
855
|
+
"function approve(address to, uint256 tokenId)",
|
|
856
|
+
"function getApproved(uint256 tokenId) view returns (address)",
|
|
857
|
+
// Events
|
|
858
|
+
"event Transfer(address indexed from, address indexed to, uint256 indexed tokenId)"
|
|
859
|
+
];
|
|
860
|
+
var ERC8004_REPUTATION_ABI = [
|
|
861
|
+
// Feedback
|
|
862
|
+
"function giveFeedback(uint256 agentId, int128 value, uint8 valueDecimals, string tag1, string tag2, string endpoint, string feedbackURI, bytes32 feedbackHash)",
|
|
863
|
+
"function revokeFeedback(uint256 agentId, uint64 feedbackIndex)",
|
|
864
|
+
// Queries
|
|
865
|
+
"function readFeedback(uint256 agentId, address clientAddress, uint64 feedbackIndex) view returns (int128 value, uint8 valueDecimals, string tag1, string tag2, bool isRevoked)",
|
|
866
|
+
"function getSummary(uint256 agentId, address[] clientAddresses, string tag1, string tag2) view returns (uint64 count, int128 summaryValue, uint8 summaryValueDecimals)",
|
|
867
|
+
"function getClients(uint256 agentId) view returns (address[])",
|
|
868
|
+
"function getLastIndex(uint256 agentId, address clientAddress) view returns (uint64)",
|
|
869
|
+
// Registry
|
|
870
|
+
"function getIdentityRegistry() view returns (address)"
|
|
871
|
+
];
|
|
872
|
+
var ERC8004_SEPOLIA = {
|
|
873
|
+
identityRegistry: "0x8004A818BFB912233c491871b3d84c89A494BD9e",
|
|
874
|
+
reputationRegistry: "0x8004B663056A597Dffe9eCcC1965A193B7388713"
|
|
875
|
+
};
|
|
876
|
+
var AgentIdentityClient = class {
|
|
877
|
+
constructor(options) {
|
|
878
|
+
this.config = options.config;
|
|
879
|
+
this.signer = options.signer;
|
|
880
|
+
const identityAddr = options.config.contracts?.identityRegistry || ERC8004_SEPOLIA.identityRegistry;
|
|
881
|
+
const reputationAddr = ERC8004_SEPOLIA.reputationRegistry;
|
|
882
|
+
this.identityRegistry = new import_ethers3.ethers.Contract(identityAddr, ERC8004_IDENTITY_ABI, this.signer);
|
|
883
|
+
this.reputationRegistry = new import_ethers3.ethers.Contract(reputationAddr, ERC8004_REPUTATION_ABI, this.signer);
|
|
884
|
+
}
|
|
885
|
+
// ============ Identity Functions ============
|
|
886
|
+
/**
|
|
887
|
+
* Register a new agent (minimal - no metadata)
|
|
888
|
+
*/
|
|
889
|
+
async register() {
|
|
890
|
+
const tx = await this.identityRegistry["register()"]();
|
|
891
|
+
const receipt = await tx.wait();
|
|
892
|
+
const agentId = this.parseAgentIdFromReceipt(receipt);
|
|
893
|
+
return { agentId, txHash: receipt.hash };
|
|
894
|
+
}
|
|
895
|
+
/**
|
|
896
|
+
* Register agent with IPFS/HTTP URI to metadata JSON
|
|
897
|
+
* @param agentURI URI pointing to agent metadata (ipfs:// or https://)
|
|
898
|
+
*/
|
|
899
|
+
async registerWithURI(agentURI) {
|
|
900
|
+
const tx = await this.identityRegistry["register(string)"](agentURI);
|
|
901
|
+
const receipt = await tx.wait();
|
|
902
|
+
const agentId = this.parseAgentIdFromReceipt(receipt);
|
|
903
|
+
return { agentId, txHash: receipt.hash };
|
|
904
|
+
}
|
|
905
|
+
/**
|
|
906
|
+
* Check if the signer already owns an ERC-8004 identity token.
|
|
907
|
+
* Returns true if balanceOf > 0, false otherwise.
|
|
908
|
+
* Note: Cannot determine the specific agentId without enumeration —
|
|
909
|
+
* use agether init <pk> --agent-id <id> if you know your agentId.
|
|
910
|
+
*/
|
|
911
|
+
async hasExistingIdentity() {
|
|
912
|
+
try {
|
|
913
|
+
const address = await this.signer.getAddress();
|
|
914
|
+
const balance = await this.identityRegistry.balanceOf(address);
|
|
915
|
+
return balance > 0n;
|
|
916
|
+
} catch {
|
|
917
|
+
return false;
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
/**
|
|
921
|
+
* Register only if no identity exists; otherwise throw.
|
|
922
|
+
* Prevents accidental double-registration.
|
|
923
|
+
*/
|
|
924
|
+
async registerOrGet() {
|
|
925
|
+
const hasIdentity = await this.hasExistingIdentity();
|
|
926
|
+
if (hasIdentity) {
|
|
927
|
+
throw new Error("Wallet already owns an ERC-8004 identity. Use agether init <pk> --agent-id <id> to set it.");
|
|
928
|
+
}
|
|
929
|
+
const result = await this.register();
|
|
930
|
+
return { ...result, existing: false };
|
|
931
|
+
}
|
|
932
|
+
/**
|
|
933
|
+
* Register with URI only if no identity exists; otherwise throw.
|
|
934
|
+
* Prevents accidental double-registration.
|
|
935
|
+
*/
|
|
936
|
+
async registerOrGetWithURI(agentURI) {
|
|
937
|
+
const hasIdentity = await this.hasExistingIdentity();
|
|
938
|
+
if (hasIdentity) {
|
|
939
|
+
throw new Error("Wallet already owns an ERC-8004 identity. Use agether init <pk> --agent-id <id> to set it.");
|
|
940
|
+
}
|
|
941
|
+
const result = await this.registerWithURI(agentURI);
|
|
942
|
+
return { ...result, existing: false };
|
|
943
|
+
}
|
|
944
|
+
/**
|
|
945
|
+
* Register agent with URI and on-chain metadata
|
|
946
|
+
*/
|
|
947
|
+
async registerWithMetadata(agentURI, metadata) {
|
|
948
|
+
const metadataEntries = metadata.map((m) => ({
|
|
949
|
+
key: m.key,
|
|
950
|
+
value: import_ethers3.ethers.toUtf8Bytes(m.value)
|
|
951
|
+
}));
|
|
952
|
+
const tx = await this.identityRegistry["register(string,tuple(string,bytes)[])"](
|
|
953
|
+
agentURI,
|
|
954
|
+
metadataEntries
|
|
955
|
+
);
|
|
956
|
+
const receipt = await tx.wait();
|
|
957
|
+
const agentId = this.parseAgentIdFromReceipt(receipt);
|
|
958
|
+
return { agentId, txHash: receipt.hash };
|
|
959
|
+
}
|
|
960
|
+
/**
|
|
961
|
+
* Get agent owner address
|
|
962
|
+
*/
|
|
963
|
+
async getOwner(agentId) {
|
|
964
|
+
return await this.identityRegistry.ownerOf(agentId);
|
|
965
|
+
}
|
|
966
|
+
/**
|
|
967
|
+
* Get agent URI (metadata JSON location)
|
|
968
|
+
*/
|
|
969
|
+
async getAgentURI(agentId) {
|
|
970
|
+
return await this.identityRegistry.tokenURI(agentId);
|
|
971
|
+
}
|
|
972
|
+
/**
|
|
973
|
+
* Update agent URI
|
|
974
|
+
*/
|
|
975
|
+
async setAgentURI(agentId, newURI) {
|
|
976
|
+
const tx = await this.identityRegistry.setAgentURI(agentId, newURI);
|
|
977
|
+
const receipt = await tx.wait();
|
|
978
|
+
return receipt.hash;
|
|
979
|
+
}
|
|
980
|
+
/**
|
|
981
|
+
* Set on-chain metadata (key-value)
|
|
982
|
+
*/
|
|
983
|
+
async setMetadata(agentId, key, value) {
|
|
984
|
+
const tx = await this.identityRegistry.setMetadata(
|
|
985
|
+
agentId,
|
|
986
|
+
key,
|
|
987
|
+
import_ethers3.ethers.toUtf8Bytes(value)
|
|
988
|
+
);
|
|
989
|
+
const receipt = await tx.wait();
|
|
990
|
+
return receipt.hash;
|
|
991
|
+
}
|
|
992
|
+
/**
|
|
993
|
+
* Get on-chain metadata
|
|
994
|
+
*/
|
|
995
|
+
async getMetadata(agentId, key) {
|
|
996
|
+
const value = await this.identityRegistry.getMetadata(agentId, key);
|
|
997
|
+
return import_ethers3.ethers.toUtf8String(value);
|
|
998
|
+
}
|
|
999
|
+
/**
|
|
1000
|
+
* Transfer agent to new owner
|
|
1001
|
+
*/
|
|
1002
|
+
async transfer(agentId, to) {
|
|
1003
|
+
const from = await this.signer.getAddress();
|
|
1004
|
+
const tx = await this.identityRegistry.transferFrom(from, to, agentId);
|
|
1005
|
+
const receipt = await tx.wait();
|
|
1006
|
+
return receipt.hash;
|
|
1007
|
+
}
|
|
1008
|
+
/**
|
|
1009
|
+
* Fetch and parse agent metadata from URI
|
|
1010
|
+
*/
|
|
1011
|
+
async fetchAgentMetadata(agentId) {
|
|
1012
|
+
try {
|
|
1013
|
+
const uri = await this.getAgentURI(agentId);
|
|
1014
|
+
let fetchUrl = uri;
|
|
1015
|
+
if (uri.startsWith("ipfs://")) {
|
|
1016
|
+
const cid = uri.replace("ipfs://", "");
|
|
1017
|
+
fetchUrl = `https://ipfs.io/ipfs/${cid}`;
|
|
1018
|
+
}
|
|
1019
|
+
const response = await fetch(fetchUrl);
|
|
1020
|
+
if (!response.ok) return null;
|
|
1021
|
+
return await response.json();
|
|
1022
|
+
} catch {
|
|
1023
|
+
return null;
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
// ============ Reputation Functions ============
|
|
1027
|
+
/**
|
|
1028
|
+
* Give feedback to an agent
|
|
1029
|
+
*/
|
|
1030
|
+
async giveFeedback(input) {
|
|
1031
|
+
const feedbackHash = import_ethers3.ethers.keccak256(
|
|
1032
|
+
import_ethers3.ethers.AbiCoder.defaultAbiCoder().encode(
|
|
1033
|
+
["uint256", "int128", "uint256"],
|
|
1034
|
+
[input.agentId, input.value, Date.now()]
|
|
1035
|
+
)
|
|
1036
|
+
);
|
|
1037
|
+
const tx = await this.reputationRegistry.giveFeedback(
|
|
1038
|
+
input.agentId,
|
|
1039
|
+
input.value,
|
|
1040
|
+
input.decimals || 0,
|
|
1041
|
+
input.tag1 || "",
|
|
1042
|
+
input.tag2 || "",
|
|
1043
|
+
input.endpoint || "",
|
|
1044
|
+
input.feedbackURI || "",
|
|
1045
|
+
feedbackHash
|
|
1046
|
+
);
|
|
1047
|
+
const receipt = await tx.wait();
|
|
1048
|
+
return receipt.hash;
|
|
1049
|
+
}
|
|
1050
|
+
/**
|
|
1051
|
+
* Give positive feedback (shorthand)
|
|
1052
|
+
*/
|
|
1053
|
+
async givePosisitiveFeedback(agentId, value = 100, tags = {}) {
|
|
1054
|
+
return this.giveFeedback({
|
|
1055
|
+
agentId,
|
|
1056
|
+
value: Math.abs(value),
|
|
1057
|
+
...tags
|
|
1058
|
+
});
|
|
1059
|
+
}
|
|
1060
|
+
/**
|
|
1061
|
+
* Give negative feedback (e.g., for defaults)
|
|
1062
|
+
*/
|
|
1063
|
+
async giveNegativeFeedback(agentId, value = -100, tags = {}) {
|
|
1064
|
+
return this.giveFeedback({
|
|
1065
|
+
agentId,
|
|
1066
|
+
value: -Math.abs(value),
|
|
1067
|
+
...tags
|
|
1068
|
+
});
|
|
1069
|
+
}
|
|
1070
|
+
/**
|
|
1071
|
+
* Record credit default in reputation system
|
|
1072
|
+
*/
|
|
1073
|
+
async recordCreditDefault(agentId, creditLineId) {
|
|
1074
|
+
return this.giveFeedback({
|
|
1075
|
+
agentId,
|
|
1076
|
+
value: -100,
|
|
1077
|
+
tag1: "credit",
|
|
1078
|
+
tag2: "default",
|
|
1079
|
+
feedbackURI: `agether://default/${creditLineId}`
|
|
1080
|
+
});
|
|
1081
|
+
}
|
|
1082
|
+
/**
|
|
1083
|
+
* Get reputation summary for an agent
|
|
1084
|
+
*/
|
|
1085
|
+
async getReputation(agentId, tag1 = "", tag2 = "") {
|
|
1086
|
+
const clients = await this.reputationRegistry.getClients(agentId);
|
|
1087
|
+
if (clients.length === 0) {
|
|
1088
|
+
return {
|
|
1089
|
+
count: 0,
|
|
1090
|
+
totalValue: 0,
|
|
1091
|
+
averageValue: 0,
|
|
1092
|
+
clients: []
|
|
1093
|
+
};
|
|
1094
|
+
}
|
|
1095
|
+
const [count, summaryValue, decimals] = await this.reputationRegistry.getSummary(
|
|
1096
|
+
agentId,
|
|
1097
|
+
clients,
|
|
1098
|
+
tag1,
|
|
1099
|
+
tag2
|
|
1100
|
+
);
|
|
1101
|
+
const divisor = 10 ** Number(decimals);
|
|
1102
|
+
const total = Number(summaryValue) / divisor;
|
|
1103
|
+
return {
|
|
1104
|
+
count: Number(count),
|
|
1105
|
+
totalValue: total,
|
|
1106
|
+
averageValue: Number(count) > 0 ? total / Number(count) : 0,
|
|
1107
|
+
clients: clients.map((c) => c)
|
|
1108
|
+
};
|
|
1109
|
+
}
|
|
1110
|
+
/**
|
|
1111
|
+
* Check if agent has negative credit reputation
|
|
1112
|
+
*/
|
|
1113
|
+
async hasNegativeCreditReputation(agentId) {
|
|
1114
|
+
const rep = await this.getReputation(agentId, "credit", "");
|
|
1115
|
+
return rep.count > 0 && rep.averageValue < 0;
|
|
1116
|
+
}
|
|
1117
|
+
// ============ Agether Integration ============
|
|
1118
|
+
/**
|
|
1119
|
+
* Verify agent is eligible for Agether credit
|
|
1120
|
+
* Checks:
|
|
1121
|
+
* 1. Agent exists in ERC-8004 registry
|
|
1122
|
+
* 2. Agent has no negative credit reputation
|
|
1123
|
+
*/
|
|
1124
|
+
async verifyForCredit(agentId) {
|
|
1125
|
+
let owner;
|
|
1126
|
+
try {
|
|
1127
|
+
owner = await this.getOwner(agentId);
|
|
1128
|
+
} catch {
|
|
1129
|
+
return { eligible: false, reason: "Agent not found in ERC-8004 registry" };
|
|
1130
|
+
}
|
|
1131
|
+
const reputation = await this.getReputation(agentId, "credit", "");
|
|
1132
|
+
if (reputation.count > 0 && reputation.averageValue < 0) {
|
|
1133
|
+
return {
|
|
1134
|
+
eligible: false,
|
|
1135
|
+
reason: "Agent has negative credit reputation",
|
|
1136
|
+
owner,
|
|
1137
|
+
reputation
|
|
1138
|
+
};
|
|
1139
|
+
}
|
|
1140
|
+
return {
|
|
1141
|
+
eligible: true,
|
|
1142
|
+
owner,
|
|
1143
|
+
reputation
|
|
1144
|
+
};
|
|
1145
|
+
}
|
|
1146
|
+
// ============ Helpers ============
|
|
1147
|
+
parseAgentIdFromReceipt(receipt) {
|
|
1148
|
+
for (const log of receipt.logs) {
|
|
1149
|
+
try {
|
|
1150
|
+
const parsed = this.identityRegistry.interface.parseLog({
|
|
1151
|
+
topics: log.topics,
|
|
1152
|
+
data: log.data
|
|
1153
|
+
});
|
|
1154
|
+
if (parsed?.name === "Transfer") {
|
|
1155
|
+
return parsed.args[2];
|
|
1156
|
+
}
|
|
1157
|
+
} catch {
|
|
1158
|
+
continue;
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
return 0n;
|
|
1162
|
+
}
|
|
1163
|
+
/**
|
|
1164
|
+
* Get contract addresses
|
|
1165
|
+
*/
|
|
1166
|
+
getContractAddresses() {
|
|
1167
|
+
return {
|
|
1168
|
+
identity: this.identityRegistry.target,
|
|
1169
|
+
reputation: this.reputationRegistry.target
|
|
1170
|
+
};
|
|
1171
|
+
}
|
|
1172
|
+
};
|
|
1173
|
+
|
|
1174
|
+
// src/clients/X402Client.ts
|
|
1175
|
+
var import_ethers4 = require("ethers");
|
|
1176
|
+
var USDC_DOMAINS = {
|
|
1177
|
+
"eip155:1": { name: "USD Coin", version: "2", address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" },
|
|
1178
|
+
"eip155:8453": { name: "USD Coin", version: "2", address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913" },
|
|
1179
|
+
"eip155:84532": { name: "USD Coin", version: "2", address: "0x036CbD53842c5426634e7929541eC2318f3dCF7e" },
|
|
1180
|
+
"eip155:42161": { name: "USD Coin", version: "2", address: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831" },
|
|
1181
|
+
"eip155:10": { name: "USD Coin", version: "2", address: "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85" }
|
|
1182
|
+
};
|
|
1183
|
+
function chainIdFromNetwork(network) {
|
|
1184
|
+
const m = network.match(/^eip155:(\d+)$/);
|
|
1185
|
+
return m ? Number(m[1]) : 1;
|
|
1186
|
+
}
|
|
1187
|
+
var X402Client = class {
|
|
1188
|
+
constructor(config) {
|
|
1189
|
+
this.config = config;
|
|
1190
|
+
const provider = new import_ethers4.ethers.JsonRpcProvider(config.rpcUrl);
|
|
1191
|
+
this.wallet = new import_ethers4.ethers.Wallet(config.privateKey, provider);
|
|
1192
|
+
}
|
|
1193
|
+
async get(url, opts) {
|
|
1194
|
+
return this.request(url, { ...opts, method: "GET" });
|
|
1195
|
+
}
|
|
1196
|
+
async post(url, body, opts) {
|
|
1197
|
+
return this.request(url, {
|
|
1198
|
+
...opts,
|
|
1199
|
+
method: "POST",
|
|
1200
|
+
body: body ? JSON.stringify(body) : void 0,
|
|
1201
|
+
headers: { "Content-Type": "application/json", ...opts?.headers }
|
|
1202
|
+
});
|
|
1203
|
+
}
|
|
1204
|
+
getAddress() {
|
|
1205
|
+
return this.wallet.address;
|
|
1206
|
+
}
|
|
1207
|
+
// ──────────── Core request / 402-retry loop ────────────
|
|
1208
|
+
async request(url, options) {
|
|
1209
|
+
try {
|
|
1210
|
+
console.log(" [1/4] Calling resource server\u2026");
|
|
1211
|
+
const response = await fetch(url, {
|
|
1212
|
+
...options,
|
|
1213
|
+
headers: {
|
|
1214
|
+
...options?.headers,
|
|
1215
|
+
"X-Agent-Id": this.config.agentId || ""
|
|
1216
|
+
}
|
|
1217
|
+
});
|
|
1218
|
+
if (response.ok) {
|
|
1219
|
+
const data = await response.json();
|
|
1220
|
+
return { success: true, data };
|
|
1221
|
+
}
|
|
1222
|
+
if (response.status !== 402) {
|
|
1223
|
+
return { success: false, error: `HTTP ${response.status}: ${await response.text()}` };
|
|
1224
|
+
}
|
|
1225
|
+
console.log(" [2/4] 402 received \u2014 parsing payment requirements\u2026");
|
|
1226
|
+
const parsed = await this.parsePaymentRequired(response);
|
|
1227
|
+
if (!parsed) {
|
|
1228
|
+
return { success: false, error: "Could not parse payment requirements from 402 response" };
|
|
1229
|
+
}
|
|
1230
|
+
const { requirements, resource } = parsed;
|
|
1231
|
+
console.log(` scheme : ${requirements.scheme}`);
|
|
1232
|
+
console.log(` network : ${requirements.network}`);
|
|
1233
|
+
console.log(` amount : ${requirements.amount} (atomic)`);
|
|
1234
|
+
console.log(` asset : ${requirements.asset}`);
|
|
1235
|
+
console.log(` payTo : ${requirements.payTo}`);
|
|
1236
|
+
console.log(" [3/4] Signing EIP-3009 transferWithAuthorization\u2026");
|
|
1237
|
+
const paymentPayload = await this.buildPaymentPayload(requirements, resource, url);
|
|
1238
|
+
const paymentB64 = Buffer.from(JSON.stringify(paymentPayload)).toString("base64");
|
|
1239
|
+
await this.riskCheck(paymentPayload, requirements);
|
|
1240
|
+
console.log(" [4/4] Retrying with PAYMENT-SIGNATURE header\u2026");
|
|
1241
|
+
const paidResponse = await fetch(url, {
|
|
1242
|
+
...options,
|
|
1243
|
+
headers: {
|
|
1244
|
+
...options?.headers,
|
|
1245
|
+
"X-Agent-Id": this.config.agentId || "",
|
|
1246
|
+
// v2 header
|
|
1247
|
+
"PAYMENT-SIGNATURE": paymentB64,
|
|
1248
|
+
// v1 compat header (some servers still use this)
|
|
1249
|
+
"X-PAYMENT": paymentB64
|
|
1250
|
+
}
|
|
1251
|
+
});
|
|
1252
|
+
if (paidResponse.ok) {
|
|
1253
|
+
const data = await paidResponse.json();
|
|
1254
|
+
const settlementHeader = paidResponse.headers.get("PAYMENT-RESPONSE") || paidResponse.headers.get("X-PAYMENT-RESPONSE");
|
|
1255
|
+
let txHash;
|
|
1256
|
+
if (settlementHeader) {
|
|
1257
|
+
try {
|
|
1258
|
+
const settlement = JSON.parse(Buffer.from(settlementHeader, "base64").toString("utf-8"));
|
|
1259
|
+
txHash = settlement.transaction;
|
|
1260
|
+
} catch {
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
return {
|
|
1264
|
+
success: true,
|
|
1265
|
+
data,
|
|
1266
|
+
paymentInfo: {
|
|
1267
|
+
amount: requirements.amount,
|
|
1268
|
+
asset: requirements.extra?.name || "USDC",
|
|
1269
|
+
network: requirements.network,
|
|
1270
|
+
txHash
|
|
1271
|
+
}
|
|
1272
|
+
};
|
|
1273
|
+
}
|
|
1274
|
+
const errBody = await paidResponse.text();
|
|
1275
|
+
return { success: false, error: `Payment rejected (HTTP ${paidResponse.status}): ${errBody}` };
|
|
1276
|
+
} catch (error) {
|
|
1277
|
+
return { success: false, error: `Request failed: ${error instanceof Error ? error.message : String(error)}` };
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
// ──────────── Parse 402 response ────────────
|
|
1281
|
+
async parsePaymentRequired(response) {
|
|
1282
|
+
const prHeader = response.headers.get("PAYMENT-REQUIRED") || response.headers.get("x-payment-required");
|
|
1283
|
+
if (prHeader) {
|
|
1284
|
+
try {
|
|
1285
|
+
const decoded = JSON.parse(Buffer.from(prHeader, "base64").toString("utf-8"));
|
|
1286
|
+
if (decoded.accepts?.length) {
|
|
1287
|
+
return { requirements: decoded.accepts[0], resource: decoded.resource };
|
|
1288
|
+
}
|
|
1289
|
+
} catch {
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
try {
|
|
1293
|
+
const body = await response.json();
|
|
1294
|
+
if (body.accepts && Array.isArray(body.accepts) && body.accepts.length > 0) {
|
|
1295
|
+
return { requirements: body.accepts[0], resource: body.resource };
|
|
1296
|
+
}
|
|
1297
|
+
if (body.paymentRequirements) {
|
|
1298
|
+
const pr = Array.isArray(body.paymentRequirements) ? body.paymentRequirements[0] : body.paymentRequirements;
|
|
1299
|
+
return { requirements: pr, resource: body.resource };
|
|
1300
|
+
}
|
|
1301
|
+
if (body.scheme && body.network) {
|
|
1302
|
+
return { requirements: body, resource: body.resource };
|
|
1303
|
+
}
|
|
1304
|
+
} catch {
|
|
1305
|
+
}
|
|
1306
|
+
const wwwAuth = response.headers.get("WWW-Authenticate");
|
|
1307
|
+
if (wwwAuth) {
|
|
1308
|
+
const m = wwwAuth.match(/x402[^"]*"([^"]+)"/);
|
|
1309
|
+
if (m) {
|
|
1310
|
+
try {
|
|
1311
|
+
const decoded = JSON.parse(Buffer.from(m[1], "base64").toString("utf-8"));
|
|
1312
|
+
const reqs = Array.isArray(decoded) ? decoded[0] : decoded;
|
|
1313
|
+
return { requirements: reqs };
|
|
1314
|
+
} catch {
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1318
|
+
return null;
|
|
1319
|
+
}
|
|
1320
|
+
// ──────────── Build x402 v2 PaymentPayload with EIP-3009 ────────────
|
|
1321
|
+
//
|
|
1322
|
+
// If an AgentAccount is configured, we use it as the `from` address
|
|
1323
|
+
// (smart wallet pays directly). The AgentAccount implements EIP-1271
|
|
1324
|
+
// so USDC's transferWithAuthorization will call isValidSignature()
|
|
1325
|
+
// to verify the owner's ECDSA signature. The facilitator detects
|
|
1326
|
+
// the >65-byte or smart-wallet case and uses the bytes overload.
|
|
1327
|
+
async buildPaymentPayload(reqs, resource, url) {
|
|
1328
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
1329
|
+
const validAfter = String(now - 60);
|
|
1330
|
+
const validBefore = String(now + (reqs.maxTimeoutSeconds || 300));
|
|
1331
|
+
const nonce = import_ethers4.ethers.hexlify(import_ethers4.ethers.randomBytes(32));
|
|
1332
|
+
const chainId = chainIdFromNetwork(reqs.network);
|
|
1333
|
+
const usdcDomain = USDC_DOMAINS[reqs.network] || USDC_DOMAINS["eip155:1"];
|
|
1334
|
+
const payerAddress = this.config.accountAddress || this.wallet.address;
|
|
1335
|
+
const isSmartWallet = !!this.config.accountAddress;
|
|
1336
|
+
const domain = {
|
|
1337
|
+
name: usdcDomain.name,
|
|
1338
|
+
version: usdcDomain.version,
|
|
1339
|
+
chainId,
|
|
1340
|
+
verifyingContract: reqs.asset || usdcDomain.address
|
|
1341
|
+
};
|
|
1342
|
+
const types = {
|
|
1343
|
+
TransferWithAuthorization: [
|
|
1344
|
+
{ name: "from", type: "address" },
|
|
1345
|
+
{ name: "to", type: "address" },
|
|
1346
|
+
{ name: "value", type: "uint256" },
|
|
1347
|
+
{ name: "validAfter", type: "uint256" },
|
|
1348
|
+
{ name: "validBefore", type: "uint256" },
|
|
1349
|
+
{ name: "nonce", type: "bytes32" }
|
|
1350
|
+
]
|
|
1351
|
+
};
|
|
1352
|
+
const value = {
|
|
1353
|
+
from: payerAddress,
|
|
1354
|
+
// AgentAccount or EOA
|
|
1355
|
+
to: reqs.payTo,
|
|
1356
|
+
value: reqs.amount,
|
|
1357
|
+
validAfter,
|
|
1358
|
+
validBefore,
|
|
1359
|
+
nonce
|
|
1360
|
+
};
|
|
1361
|
+
let signature = await this.wallet.signTypedData(domain, types, value);
|
|
1362
|
+
if (isSmartWallet) {
|
|
1363
|
+
signature = signature + "00";
|
|
1364
|
+
}
|
|
1365
|
+
if (isSmartWallet) {
|
|
1366
|
+
console.log(` \u2713 Signed for AgentAccount ${payerAddress.slice(0, 10)}\u2026 (EIP-1271, chain=${chainId})`);
|
|
1367
|
+
} else {
|
|
1368
|
+
console.log(` \u2713 Signed (from=${payerAddress.slice(0, 10)}\u2026, chain=${chainId})`);
|
|
1369
|
+
}
|
|
1370
|
+
return {
|
|
1371
|
+
x402Version: 2,
|
|
1372
|
+
resource: resource || { url, description: "", mimeType: "application/json" },
|
|
1373
|
+
accepted: {
|
|
1374
|
+
scheme: reqs.scheme,
|
|
1375
|
+
network: reqs.network,
|
|
1376
|
+
amount: reqs.amount,
|
|
1377
|
+
asset: reqs.asset,
|
|
1378
|
+
payTo: reqs.payTo,
|
|
1379
|
+
maxTimeoutSeconds: reqs.maxTimeoutSeconds,
|
|
1380
|
+
extra: reqs.extra || {}
|
|
1381
|
+
},
|
|
1382
|
+
payload: {
|
|
1383
|
+
signature,
|
|
1384
|
+
authorization: {
|
|
1385
|
+
from: payerAddress,
|
|
1386
|
+
// AgentAccount address — facilitator checks balance here
|
|
1387
|
+
to: reqs.payTo,
|
|
1388
|
+
value: reqs.amount,
|
|
1389
|
+
validAfter,
|
|
1390
|
+
validBefore,
|
|
1391
|
+
nonce
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1394
|
+
};
|
|
1395
|
+
}
|
|
1396
|
+
// ──────────── Risk check via our backend ────────────
|
|
1397
|
+
async riskCheck(paymentPayload, reqs) {
|
|
1398
|
+
try {
|
|
1399
|
+
const verifyUrl = `${this.config.backendUrl}/x402/verify`;
|
|
1400
|
+
const resp = await fetch(verifyUrl, {
|
|
1401
|
+
method: "POST",
|
|
1402
|
+
headers: {
|
|
1403
|
+
"Content-Type": "application/json",
|
|
1404
|
+
"X-Agent-Id": this.config.agentId || "",
|
|
1405
|
+
...this.config.accountAddress ? { "X-Agent-Account": this.config.accountAddress } : {}
|
|
1406
|
+
},
|
|
1407
|
+
body: JSON.stringify({
|
|
1408
|
+
x402Version: 2,
|
|
1409
|
+
paymentPayload,
|
|
1410
|
+
paymentRequirements: reqs
|
|
1411
|
+
}),
|
|
1412
|
+
signal: AbortSignal.timeout(5e3)
|
|
1413
|
+
});
|
|
1414
|
+
if (resp.ok) {
|
|
1415
|
+
const result = await resp.json();
|
|
1416
|
+
const decision = resp.headers.get("X-Risk-Decision") || (result.isValid ? "allow" : "unknown");
|
|
1417
|
+
const score = resp.headers.get("X-Risk-Score") || "?";
|
|
1418
|
+
console.log(` \u2713 Risk check: ${decision} (score=${score})`);
|
|
1419
|
+
} else {
|
|
1420
|
+
console.log(` \u26A0 Risk check failed (HTTP ${resp.status}) \u2014 continuing anyway`);
|
|
1421
|
+
}
|
|
1422
|
+
} catch {
|
|
1423
|
+
console.log(" \u26A0 Risk check unavailable \u2014 continuing");
|
|
1424
|
+
}
|
|
1425
|
+
}
|
|
1426
|
+
};
|
|
1427
|
+
|
|
1428
|
+
// src/clients/WalletClient.ts
|
|
1429
|
+
var import_ethers5 = require("ethers");
|
|
1430
|
+
var WalletClient = class {
|
|
1431
|
+
constructor(config) {
|
|
1432
|
+
this.privateKey = null;
|
|
1433
|
+
this.factoryAddress = config.factoryAddress;
|
|
1434
|
+
this.usdcAddress = config.usdcAddress || import_ethers5.ethers.ZeroAddress;
|
|
1435
|
+
this.chainId = config.chainId;
|
|
1436
|
+
this.rpcUrl = config.rpcUrl;
|
|
1437
|
+
this.provider = new import_ethers5.ethers.JsonRpcProvider(config.rpcUrl);
|
|
1438
|
+
this.privateKey = config.privateKey || null;
|
|
1439
|
+
}
|
|
1440
|
+
/**
|
|
1441
|
+
* Create a fresh signer to avoid nonce caching issues
|
|
1442
|
+
*/
|
|
1443
|
+
getFreshSigner() {
|
|
1444
|
+
if (!this.privateKey) {
|
|
1445
|
+
throw new Error("Signer not configured - provide privateKey");
|
|
1446
|
+
}
|
|
1447
|
+
const freshProvider = new import_ethers5.ethers.JsonRpcProvider(this.rpcUrl);
|
|
1448
|
+
return new import_ethers5.Wallet(this.privateKey, freshProvider);
|
|
1449
|
+
}
|
|
1450
|
+
getFactoryContract() {
|
|
1451
|
+
if (this.privateKey) {
|
|
1452
|
+
return new import_ethers5.Contract(this.factoryAddress, ACCOUNT_FACTORY_ABI, this.getFreshSigner());
|
|
1453
|
+
}
|
|
1454
|
+
return new import_ethers5.Contract(this.factoryAddress, ACCOUNT_FACTORY_ABI, this.provider);
|
|
1455
|
+
}
|
|
1456
|
+
getAccountContract(accountAddress) {
|
|
1457
|
+
if (this.privateKey) {
|
|
1458
|
+
return new import_ethers5.Contract(accountAddress, AGENT_ACCOUNT_ABI, this.getFreshSigner());
|
|
1459
|
+
}
|
|
1460
|
+
return new import_ethers5.Contract(accountAddress, AGENT_ACCOUNT_ABI, this.provider);
|
|
1461
|
+
}
|
|
1462
|
+
getChainId() {
|
|
1463
|
+
return this.chainId;
|
|
1464
|
+
}
|
|
1465
|
+
// ============ Account Factory ============
|
|
1466
|
+
async accountExists(agentId) {
|
|
1467
|
+
const factory = this.getFactoryContract();
|
|
1468
|
+
return factory.accountExists(agentId);
|
|
1469
|
+
}
|
|
1470
|
+
async getAccount(agentId) {
|
|
1471
|
+
const factory = this.getFactoryContract();
|
|
1472
|
+
const address = await factory.getAccount(agentId);
|
|
1473
|
+
if (address === import_ethers5.ethers.ZeroAddress) {
|
|
1474
|
+
return null;
|
|
1475
|
+
}
|
|
1476
|
+
return address;
|
|
1477
|
+
}
|
|
1478
|
+
async predictAddress(agentId) {
|
|
1479
|
+
const factory = this.getFactoryContract();
|
|
1480
|
+
return factory.predictAddress(agentId);
|
|
1481
|
+
}
|
|
1482
|
+
async createAccount(agentId) {
|
|
1483
|
+
if (!this.privateKey) {
|
|
1484
|
+
throw new Error("Signer not configured - provide privateKey");
|
|
1485
|
+
}
|
|
1486
|
+
const factory = this.getFactoryContract();
|
|
1487
|
+
const tx = await factory.createAccount(agentId);
|
|
1488
|
+
await tx.wait();
|
|
1489
|
+
const account = await this.getAccount(agentId);
|
|
1490
|
+
if (!account) {
|
|
1491
|
+
throw new Error("Account creation failed");
|
|
1492
|
+
}
|
|
1493
|
+
return account;
|
|
1494
|
+
}
|
|
1495
|
+
async totalAccounts() {
|
|
1496
|
+
const factory = this.getFactoryContract();
|
|
1497
|
+
return factory.totalAccounts();
|
|
1498
|
+
}
|
|
1499
|
+
// ============ Account Info ============
|
|
1500
|
+
async getWalletInfo(accountAddress) {
|
|
1501
|
+
const account = this.getAccountContract(accountAddress);
|
|
1502
|
+
const [agentId, owner, ethBalance] = await Promise.all([
|
|
1503
|
+
account.agentId(),
|
|
1504
|
+
account.owner(),
|
|
1505
|
+
account.ethBalance()
|
|
1506
|
+
]);
|
|
1507
|
+
let usdcBalance = 0n;
|
|
1508
|
+
if (this.usdcAddress !== import_ethers5.ethers.ZeroAddress) {
|
|
1509
|
+
usdcBalance = await account.balanceOf(this.usdcAddress);
|
|
1510
|
+
}
|
|
1511
|
+
return {
|
|
1512
|
+
address: accountAddress,
|
|
1513
|
+
agentId: BigInt(agentId),
|
|
1514
|
+
owner,
|
|
1515
|
+
ethBalance: BigInt(ethBalance),
|
|
1516
|
+
usdcBalance: BigInt(usdcBalance)
|
|
1517
|
+
};
|
|
1518
|
+
}
|
|
1519
|
+
async getProviderStatus(accountAddress, creditProvider) {
|
|
1520
|
+
const provider = new import_ethers5.Contract(
|
|
1521
|
+
creditProvider,
|
|
1522
|
+
CREDIT_PROVIDER_ABI,
|
|
1523
|
+
this.provider
|
|
1524
|
+
);
|
|
1525
|
+
const [isEligible, totalDebt, maxDrawable] = await Promise.all([
|
|
1526
|
+
provider.isEligible(accountAddress),
|
|
1527
|
+
provider.getTotalDebt(accountAddress),
|
|
1528
|
+
provider.maxDrawable(accountAddress)
|
|
1529
|
+
]);
|
|
1530
|
+
return {
|
|
1531
|
+
provider: creditProvider,
|
|
1532
|
+
isEligible,
|
|
1533
|
+
totalDebt: BigInt(totalDebt),
|
|
1534
|
+
maxDrawable: BigInt(maxDrawable)
|
|
1535
|
+
};
|
|
1536
|
+
}
|
|
1537
|
+
// ============ Fund / Withdraw ============
|
|
1538
|
+
async fundAccount(accountAddress, tokenAddress, amount) {
|
|
1539
|
+
if (!this.privateKey) {
|
|
1540
|
+
throw new Error("Signer not configured");
|
|
1541
|
+
}
|
|
1542
|
+
const signer = this.getFreshSigner();
|
|
1543
|
+
const token = new import_ethers5.Contract(tokenAddress, ERC20_ABI, signer);
|
|
1544
|
+
const approveTx = await token.approve(accountAddress, amount);
|
|
1545
|
+
await approveTx.wait();
|
|
1546
|
+
const signer2 = this.getFreshSigner();
|
|
1547
|
+
const account = new import_ethers5.Contract(accountAddress, AGENT_ACCOUNT_ABI, signer2);
|
|
1548
|
+
const tx = await account.fund(tokenAddress, amount);
|
|
1549
|
+
const receipt = await tx.wait();
|
|
1550
|
+
return receipt.hash;
|
|
1551
|
+
}
|
|
1552
|
+
async withdraw(accountAddress, tokenAddress, amount, to) {
|
|
1553
|
+
if (!this.privateKey) {
|
|
1554
|
+
throw new Error("Signer not configured");
|
|
1555
|
+
}
|
|
1556
|
+
const account = this.getAccountContract(accountAddress);
|
|
1557
|
+
const recipient = to || await this.getFreshSigner().getAddress();
|
|
1558
|
+
const tx = await account.withdraw(tokenAddress, amount, recipient);
|
|
1559
|
+
const receipt = await tx.wait();
|
|
1560
|
+
return receipt.hash;
|
|
1561
|
+
}
|
|
1562
|
+
// ============ Credit Operations ============
|
|
1563
|
+
async drawCredit(accountAddress, creditProvider, amount) {
|
|
1564
|
+
if (!this.privateKey) {
|
|
1565
|
+
throw new Error("Signer not configured");
|
|
1566
|
+
}
|
|
1567
|
+
const account = this.getAccountContract(accountAddress);
|
|
1568
|
+
const tx = await account.drawCredit(creditProvider, amount);
|
|
1569
|
+
const receipt = await tx.wait();
|
|
1570
|
+
return receipt.hash;
|
|
1571
|
+
}
|
|
1572
|
+
async repayCredit(accountAddress, creditProvider, amount) {
|
|
1573
|
+
if (!this.privateKey) {
|
|
1574
|
+
throw new Error("Signer not configured");
|
|
1575
|
+
}
|
|
1576
|
+
const account = this.getAccountContract(accountAddress);
|
|
1577
|
+
const tx = await account.repayCredit(creditProvider, amount);
|
|
1578
|
+
const receipt = await tx.wait();
|
|
1579
|
+
return receipt.hash;
|
|
1580
|
+
}
|
|
1581
|
+
// ============ Generic Execute ============
|
|
1582
|
+
async execute(accountAddress, target, value, data) {
|
|
1583
|
+
if (!this.privateKey) {
|
|
1584
|
+
throw new Error("Signer not configured");
|
|
1585
|
+
}
|
|
1586
|
+
const account = this.getAccountContract(accountAddress);
|
|
1587
|
+
const tx = await account.execute(target, value, data);
|
|
1588
|
+
const receipt = await tx.wait();
|
|
1589
|
+
return receipt.hash;
|
|
1590
|
+
}
|
|
1591
|
+
// ============ Utility ============
|
|
1592
|
+
generatePaymentMessageHash(accountAddress, recipient, amount, nonce, deadline, chainId) {
|
|
1593
|
+
return import_ethers5.ethers.keccak256(
|
|
1594
|
+
import_ethers5.ethers.AbiCoder.defaultAbiCoder().encode(
|
|
1595
|
+
["address", "uint256", "uint256", "uint256", "uint256", "address"],
|
|
1596
|
+
[recipient, amount, nonce, deadline, chainId, accountAddress]
|
|
1597
|
+
)
|
|
1598
|
+
);
|
|
1599
|
+
}
|
|
1600
|
+
};
|
|
1601
|
+
|
|
1602
|
+
// src/utils/format.ts
|
|
1603
|
+
function parseUnits(value, decimals = 6) {
|
|
1604
|
+
const [integer, fraction = ""] = value.split(".");
|
|
1605
|
+
const paddedFraction = fraction.padEnd(decimals, "0").slice(0, decimals);
|
|
1606
|
+
return BigInt(integer + paddedFraction);
|
|
1607
|
+
}
|
|
1608
|
+
function formatUnits(value, decimals = 6) {
|
|
1609
|
+
const str = value.toString().padStart(decimals + 1, "0");
|
|
1610
|
+
const integer = str.slice(0, -decimals) || "0";
|
|
1611
|
+
const fraction = str.slice(-decimals);
|
|
1612
|
+
return `${integer}.${fraction}`;
|
|
1613
|
+
}
|
|
1614
|
+
function formatUSD(value, decimals = 6) {
|
|
1615
|
+
const num = Number(formatUnits(value, decimals));
|
|
1616
|
+
return new Intl.NumberFormat("en-US", {
|
|
1617
|
+
style: "currency",
|
|
1618
|
+
currency: "USD"
|
|
1619
|
+
}).format(num);
|
|
1620
|
+
}
|
|
1621
|
+
function formatPercent(bps) {
|
|
1622
|
+
return `${(bps / 100).toFixed(2)}%`;
|
|
1623
|
+
}
|
|
1624
|
+
function formatAPR(bps) {
|
|
1625
|
+
return formatPercent(Number(bps));
|
|
1626
|
+
}
|
|
1627
|
+
function formatHealthFactor(factor) {
|
|
1628
|
+
const num = Number(factor) / 1e18;
|
|
1629
|
+
if (num >= 100) return "\u221E";
|
|
1630
|
+
return num.toFixed(2);
|
|
1631
|
+
}
|
|
1632
|
+
function formatAddress(address) {
|
|
1633
|
+
return `${address.slice(0, 6)}...${address.slice(-4)}`;
|
|
1634
|
+
}
|
|
1635
|
+
function formatTimestamp(timestamp) {
|
|
1636
|
+
return new Date(Number(timestamp) * 1e3).toISOString();
|
|
1637
|
+
}
|
|
1638
|
+
function bpsToRate(bps) {
|
|
1639
|
+
return Number(bps) / 1e4;
|
|
1640
|
+
}
|
|
1641
|
+
function rateToBps(rate) {
|
|
1642
|
+
return BigInt(Math.round(rate * 1e4));
|
|
1643
|
+
}
|
|
1644
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
1645
|
+
0 && (module.exports = {
|
|
1646
|
+
ACCOUNT_FACTORY_ABI,
|
|
1647
|
+
AGENT_ACCOUNT_ABI,
|
|
1648
|
+
AGENT_REPUTATION_ABI,
|
|
1649
|
+
AgentIdentityClient,
|
|
1650
|
+
AgetherClient,
|
|
1651
|
+
AgetherError,
|
|
1652
|
+
CREDIT_PROVIDER_ABI,
|
|
1653
|
+
ChainId,
|
|
1654
|
+
CreditNotActiveError,
|
|
1655
|
+
CreditStatus,
|
|
1656
|
+
ERC20_ABI,
|
|
1657
|
+
IDENTITY_REGISTRY_ABI,
|
|
1658
|
+
InsufficientCreditError,
|
|
1659
|
+
LP_VAULT_ABI,
|
|
1660
|
+
REPUTATION_CREDIT_ABI,
|
|
1661
|
+
ScoringClient,
|
|
1662
|
+
ScoringRejectedError,
|
|
1663
|
+
VALIDATION_REGISTRY_ABI,
|
|
1664
|
+
VaultClient,
|
|
1665
|
+
WalletClient,
|
|
1666
|
+
X402Client,
|
|
1667
|
+
bpsToRate,
|
|
1668
|
+
createConfig,
|
|
1669
|
+
formatAPR,
|
|
1670
|
+
formatAddress,
|
|
1671
|
+
formatHealthFactor,
|
|
1672
|
+
formatPercent,
|
|
1673
|
+
formatTimestamp,
|
|
1674
|
+
formatUSD,
|
|
1675
|
+
formatUnits,
|
|
1676
|
+
getDefaultConfig,
|
|
1677
|
+
getUSDCAddress,
|
|
1678
|
+
parseUnits,
|
|
1679
|
+
rateToBps
|
|
1680
|
+
});
|