@agether/sdk 1.5.0 → 1.5.2
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/MorphoClient-3UAKN2VR.mjs +6 -0
- package/dist/X402Client-PY4FOTQC.mjs +6 -0
- package/dist/chunk-GAFDBPDW.mjs +835 -0
- package/dist/chunk-PTXYOTCG.mjs +257 -0
- package/dist/cli.d.mts +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +3 -8
- package/dist/cli.mjs +680 -0
- package/dist/index.js +3 -8
- package/dist/index.mjs +31 -1089
- package/package.json +1 -1
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
// src/clients/X402Client.ts
|
|
2
|
+
import { ethers } from "ethers";
|
|
3
|
+
var USDC_DOMAINS = {
|
|
4
|
+
"eip155:1": { name: "USD Coin", version: "2", address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" },
|
|
5
|
+
"eip155:8453": { name: "USD Coin", version: "2", address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913" },
|
|
6
|
+
"eip155:84532": { name: "USD Coin", version: "2", address: "0x036CbD53842c5426634e7929541eC2318f3dCF7e" },
|
|
7
|
+
"eip155:42161": { name: "USD Coin", version: "2", address: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831" },
|
|
8
|
+
"eip155:10": { name: "USD Coin", version: "2", address: "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85" }
|
|
9
|
+
};
|
|
10
|
+
function chainIdFromNetwork(network) {
|
|
11
|
+
const m = network.match(/^eip155:(\d+)$/);
|
|
12
|
+
return m ? Number(m[1]) : 1;
|
|
13
|
+
}
|
|
14
|
+
var X402Client = class {
|
|
15
|
+
constructor(config) {
|
|
16
|
+
this.config = config;
|
|
17
|
+
const provider = new ethers.JsonRpcProvider(config.rpcUrl);
|
|
18
|
+
this.wallet = new ethers.Wallet(config.privateKey, provider);
|
|
19
|
+
}
|
|
20
|
+
async get(url, opts) {
|
|
21
|
+
return this.request(url, { ...opts, method: "GET" });
|
|
22
|
+
}
|
|
23
|
+
async post(url, body, opts) {
|
|
24
|
+
return this.request(url, {
|
|
25
|
+
...opts,
|
|
26
|
+
method: "POST",
|
|
27
|
+
body: body ? JSON.stringify(body) : void 0,
|
|
28
|
+
headers: { "Content-Type": "application/json", ...opts?.headers }
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
getAddress() {
|
|
32
|
+
return this.wallet.address;
|
|
33
|
+
}
|
|
34
|
+
// ──────────── Core request / 402-retry loop ────────────
|
|
35
|
+
async request(url, options) {
|
|
36
|
+
try {
|
|
37
|
+
console.log(" [1/4] Calling resource server\u2026");
|
|
38
|
+
const response = await fetch(url, {
|
|
39
|
+
...options,
|
|
40
|
+
headers: {
|
|
41
|
+
...options?.headers,
|
|
42
|
+
"X-Agent-Id": this.config.agentId || ""
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
if (response.ok) {
|
|
46
|
+
const data = await response.json();
|
|
47
|
+
return { success: true, data };
|
|
48
|
+
}
|
|
49
|
+
if (response.status !== 402) {
|
|
50
|
+
return { success: false, error: `HTTP ${response.status}: ${await response.text()}` };
|
|
51
|
+
}
|
|
52
|
+
console.log(" [2/4] 402 received \u2014 parsing payment requirements\u2026");
|
|
53
|
+
const parsed = await this.parsePaymentRequired(response);
|
|
54
|
+
if (!parsed) {
|
|
55
|
+
return { success: false, error: "Could not parse payment requirements from 402 response" };
|
|
56
|
+
}
|
|
57
|
+
const { requirements, resource } = parsed;
|
|
58
|
+
console.log(` scheme : ${requirements.scheme}`);
|
|
59
|
+
console.log(` network : ${requirements.network}`);
|
|
60
|
+
console.log(` amount : ${requirements.amount} (atomic)`);
|
|
61
|
+
console.log(` asset : ${requirements.asset}`);
|
|
62
|
+
console.log(` payTo : ${requirements.payTo}`);
|
|
63
|
+
console.log(" [3/4] Signing EIP-3009 transferWithAuthorization\u2026");
|
|
64
|
+
const paymentPayload = await this.buildPaymentPayload(requirements, resource, url);
|
|
65
|
+
const paymentB64 = Buffer.from(JSON.stringify(paymentPayload)).toString("base64");
|
|
66
|
+
await this.riskCheck(paymentPayload, requirements);
|
|
67
|
+
console.log(" [4/4] Retrying with PAYMENT-SIGNATURE header\u2026");
|
|
68
|
+
const paidResponse = await fetch(url, {
|
|
69
|
+
...options,
|
|
70
|
+
headers: {
|
|
71
|
+
...options?.headers,
|
|
72
|
+
"X-Agent-Id": this.config.agentId || "",
|
|
73
|
+
// v2 header
|
|
74
|
+
"PAYMENT-SIGNATURE": paymentB64,
|
|
75
|
+
// v1 compat header (some servers still use this)
|
|
76
|
+
"X-PAYMENT": paymentB64
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
if (paidResponse.ok) {
|
|
80
|
+
const data = await paidResponse.json();
|
|
81
|
+
const settlementHeader = paidResponse.headers.get("PAYMENT-RESPONSE") || paidResponse.headers.get("X-PAYMENT-RESPONSE");
|
|
82
|
+
let txHash;
|
|
83
|
+
if (settlementHeader) {
|
|
84
|
+
try {
|
|
85
|
+
const settlement = JSON.parse(Buffer.from(settlementHeader, "base64").toString("utf-8"));
|
|
86
|
+
txHash = settlement.transaction;
|
|
87
|
+
} catch {
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return {
|
|
91
|
+
success: true,
|
|
92
|
+
data,
|
|
93
|
+
paymentInfo: {
|
|
94
|
+
amount: requirements.amount,
|
|
95
|
+
asset: requirements.extra?.name || "USDC",
|
|
96
|
+
network: requirements.network,
|
|
97
|
+
txHash
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
const errBody = await paidResponse.text();
|
|
102
|
+
return { success: false, error: `Payment rejected (HTTP ${paidResponse.status}): ${errBody}` };
|
|
103
|
+
} catch (error) {
|
|
104
|
+
return { success: false, error: `Request failed: ${error instanceof Error ? error.message : String(error)}` };
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
// ──────────── Parse 402 response ────────────
|
|
108
|
+
async parsePaymentRequired(response) {
|
|
109
|
+
const prHeader = response.headers.get("PAYMENT-REQUIRED") || response.headers.get("x-payment-required");
|
|
110
|
+
if (prHeader) {
|
|
111
|
+
try {
|
|
112
|
+
const decoded = JSON.parse(Buffer.from(prHeader, "base64").toString("utf-8"));
|
|
113
|
+
if (decoded.accepts?.length) {
|
|
114
|
+
return { requirements: decoded.accepts[0], resource: decoded.resource };
|
|
115
|
+
}
|
|
116
|
+
} catch {
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
try {
|
|
120
|
+
const body = await response.json();
|
|
121
|
+
if (body.accepts && Array.isArray(body.accepts) && body.accepts.length > 0) {
|
|
122
|
+
return { requirements: body.accepts[0], resource: body.resource };
|
|
123
|
+
}
|
|
124
|
+
if (body.paymentRequirements) {
|
|
125
|
+
const pr = Array.isArray(body.paymentRequirements) ? body.paymentRequirements[0] : body.paymentRequirements;
|
|
126
|
+
return { requirements: pr, resource: body.resource };
|
|
127
|
+
}
|
|
128
|
+
if (body.scheme && body.network) {
|
|
129
|
+
return { requirements: body, resource: body.resource };
|
|
130
|
+
}
|
|
131
|
+
} catch {
|
|
132
|
+
}
|
|
133
|
+
const wwwAuth = response.headers.get("WWW-Authenticate");
|
|
134
|
+
if (wwwAuth) {
|
|
135
|
+
const m = wwwAuth.match(/x402[^"]*"([^"]+)"/);
|
|
136
|
+
if (m) {
|
|
137
|
+
try {
|
|
138
|
+
const decoded = JSON.parse(Buffer.from(m[1], "base64").toString("utf-8"));
|
|
139
|
+
const reqs = Array.isArray(decoded) ? decoded[0] : decoded;
|
|
140
|
+
return { requirements: reqs };
|
|
141
|
+
} catch {
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
// ──────────── Build x402 v2 PaymentPayload with EIP-3009 ────────────
|
|
148
|
+
//
|
|
149
|
+
// If an AgentAccount is configured, we use it as the `from` address
|
|
150
|
+
// (smart wallet pays directly). The AgentAccount implements EIP-1271
|
|
151
|
+
// so USDC's transferWithAuthorization will call isValidSignature()
|
|
152
|
+
// to verify the owner's ECDSA signature. The facilitator detects
|
|
153
|
+
// the >65-byte or smart-wallet case and uses the bytes overload.
|
|
154
|
+
async buildPaymentPayload(reqs, resource, url) {
|
|
155
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
156
|
+
const validAfter = String(now - 60);
|
|
157
|
+
const validBefore = String(now + (reqs.maxTimeoutSeconds || 300));
|
|
158
|
+
const nonce = ethers.hexlify(ethers.randomBytes(32));
|
|
159
|
+
const chainId = chainIdFromNetwork(reqs.network);
|
|
160
|
+
const usdcDomain = USDC_DOMAINS[reqs.network] || USDC_DOMAINS["eip155:1"];
|
|
161
|
+
const payerAddress = this.config.accountAddress || this.wallet.address;
|
|
162
|
+
const isSmartWallet = !!this.config.accountAddress;
|
|
163
|
+
const domain = {
|
|
164
|
+
name: usdcDomain.name,
|
|
165
|
+
version: usdcDomain.version,
|
|
166
|
+
chainId,
|
|
167
|
+
verifyingContract: reqs.asset || usdcDomain.address
|
|
168
|
+
};
|
|
169
|
+
const types = {
|
|
170
|
+
TransferWithAuthorization: [
|
|
171
|
+
{ name: "from", type: "address" },
|
|
172
|
+
{ name: "to", type: "address" },
|
|
173
|
+
{ name: "value", type: "uint256" },
|
|
174
|
+
{ name: "validAfter", type: "uint256" },
|
|
175
|
+
{ name: "validBefore", type: "uint256" },
|
|
176
|
+
{ name: "nonce", type: "bytes32" }
|
|
177
|
+
]
|
|
178
|
+
};
|
|
179
|
+
const value = {
|
|
180
|
+
from: payerAddress,
|
|
181
|
+
// AgentAccount or EOA
|
|
182
|
+
to: reqs.payTo,
|
|
183
|
+
value: reqs.amount,
|
|
184
|
+
validAfter,
|
|
185
|
+
validBefore,
|
|
186
|
+
nonce
|
|
187
|
+
};
|
|
188
|
+
let signature = await this.wallet.signTypedData(domain, types, value);
|
|
189
|
+
if (isSmartWallet) {
|
|
190
|
+
signature = signature + "00";
|
|
191
|
+
}
|
|
192
|
+
if (isSmartWallet) {
|
|
193
|
+
console.log(` \u2713 Signed for AgentAccount ${payerAddress.slice(0, 10)}\u2026 (EIP-1271, chain=${chainId})`);
|
|
194
|
+
} else {
|
|
195
|
+
console.log(` \u2713 Signed (from=${payerAddress.slice(0, 10)}\u2026, chain=${chainId})`);
|
|
196
|
+
}
|
|
197
|
+
return {
|
|
198
|
+
x402Version: 2,
|
|
199
|
+
resource: resource || { url, description: "", mimeType: "application/json" },
|
|
200
|
+
accepted: {
|
|
201
|
+
scheme: reqs.scheme,
|
|
202
|
+
network: reqs.network,
|
|
203
|
+
amount: reqs.amount,
|
|
204
|
+
asset: reqs.asset,
|
|
205
|
+
payTo: reqs.payTo,
|
|
206
|
+
maxTimeoutSeconds: reqs.maxTimeoutSeconds,
|
|
207
|
+
extra: reqs.extra || {}
|
|
208
|
+
},
|
|
209
|
+
payload: {
|
|
210
|
+
signature,
|
|
211
|
+
authorization: {
|
|
212
|
+
from: payerAddress,
|
|
213
|
+
// AgentAccount address — facilitator checks balance here
|
|
214
|
+
to: reqs.payTo,
|
|
215
|
+
value: reqs.amount,
|
|
216
|
+
validAfter,
|
|
217
|
+
validBefore,
|
|
218
|
+
nonce
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
// ──────────── Risk check via our backend ────────────
|
|
224
|
+
async riskCheck(paymentPayload, reqs) {
|
|
225
|
+
try {
|
|
226
|
+
const verifyUrl = `${this.config.backendUrl}/x402/verify`;
|
|
227
|
+
const resp = await fetch(verifyUrl, {
|
|
228
|
+
method: "POST",
|
|
229
|
+
headers: {
|
|
230
|
+
"Content-Type": "application/json",
|
|
231
|
+
"X-Agent-Id": this.config.agentId || "",
|
|
232
|
+
...this.config.accountAddress ? { "X-Agent-Account": this.config.accountAddress } : {}
|
|
233
|
+
},
|
|
234
|
+
body: JSON.stringify({
|
|
235
|
+
x402Version: 2,
|
|
236
|
+
paymentPayload,
|
|
237
|
+
paymentRequirements: reqs
|
|
238
|
+
}),
|
|
239
|
+
signal: AbortSignal.timeout(5e3)
|
|
240
|
+
});
|
|
241
|
+
if (resp.ok) {
|
|
242
|
+
const result = await resp.json();
|
|
243
|
+
const decision = resp.headers.get("X-Risk-Decision") || (result.isValid ? "allow" : "unknown");
|
|
244
|
+
const score = resp.headers.get("X-Risk-Score") || "?";
|
|
245
|
+
console.log(` \u2713 Risk check: ${decision} (score=${score})`);
|
|
246
|
+
} else {
|
|
247
|
+
console.log(` \u26A0 Risk check failed (HTTP ${resp.status}) \u2014 continuing anyway`);
|
|
248
|
+
}
|
|
249
|
+
} catch {
|
|
250
|
+
console.log(" \u26A0 Risk check unavailable \u2014 continuing");
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
export {
|
|
256
|
+
X402Client
|
|
257
|
+
};
|
package/dist/cli.d.mts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/cli.js
CHANGED
|
@@ -148,9 +148,9 @@ var init_config = __esm({
|
|
|
148
148
|
morphoBlue: "0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb"
|
|
149
149
|
},
|
|
150
150
|
[8453 /* Base */]: {
|
|
151
|
-
accountFactory: "
|
|
152
|
-
validationRegistry: "
|
|
153
|
-
agentReputation: "
|
|
151
|
+
accountFactory: "0x7D5D56416bAEA06a9DCBe3092eF335724C6320a0",
|
|
152
|
+
validationRegistry: "0xd196C32D2149270F56E209ba7aEE67CE9ceD2001",
|
|
153
|
+
agentReputation: "0x65c9cA1211809D3CF3A2707558198eb2b2bE623c",
|
|
154
154
|
usdc: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
155
155
|
identityRegistry: "0x8004A169FB4a3325136EB29fA0ceB6D2e539a432",
|
|
156
156
|
morphoBlue: "0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb"
|
|
@@ -274,11 +274,6 @@ var init_MorphoClient = __esm({
|
|
|
274
274
|
let agentId;
|
|
275
275
|
if (balance > 0n && this.agentId) {
|
|
276
276
|
agentId = BigInt(this.agentId);
|
|
277
|
-
} else if (balance > 0n) {
|
|
278
|
-
throw new AgetherError(
|
|
279
|
-
"Wallet already has an ERC-8004 identity but agentId is unknown. Pass agentId in config.",
|
|
280
|
-
"AGENT_ID_UNKNOWN"
|
|
281
|
-
);
|
|
282
277
|
} else {
|
|
283
278
|
const regTx = await this.identityRegistry.register();
|
|
284
279
|
const regReceipt = await regTx.wait();
|