|
1 | | -import { createSigner, wrapFetchWithPayment } from "x402-fetch"; |
| 1 | +import { wrapFetchWithPayment } from "@x402/fetch"; |
| 2 | +import { x402Client } from "@x402/core/client"; |
| 3 | +import { UptoEvmScheme } from "@x402/evm"; |
| 4 | +import { registerExactEvmScheme } from "@x402/evm/exact/client"; |
| 5 | +import { privateKeyToAccount } from "viem/accounts"; |
2 | 6 | import type { Agent } from "undici"; |
3 | 7 | import { |
4 | 8 | ChatParams, |
@@ -34,7 +38,7 @@ export interface LLMConfig { |
34 | 38 | * `llmServerUrl` on the `Client` to override with a hardcoded URL. |
35 | 39 | */ |
36 | 40 | export class LLM { |
37 | | - private signerPromise?: Promise<unknown>; |
| 41 | + private x402ClientInstance?: x402Client; |
38 | 42 |
|
39 | 43 | constructor(private readonly config: LLMConfig) {} |
40 | 44 |
|
@@ -200,29 +204,26 @@ export class LLM { |
200 | 204 | return payload; |
201 | 205 | } |
202 | 206 |
|
203 | | - private async getSigner(): Promise<unknown> { |
204 | | - if (!this.signerPromise) { |
205 | | - this.signerPromise = createSigner( |
206 | | - this.config.network, |
207 | | - this.config.privateKey, |
208 | | - ); |
| 207 | + private getX402Client(): x402Client { |
| 208 | + if (!this.x402ClientInstance) { |
| 209 | + const account = privateKeyToAccount(this.config.privateKey); |
| 210 | + const client = new x402Client(); |
| 211 | + registerExactEvmScheme(client, { signer: account }); |
| 212 | + // The TEE may quote the "upto" scheme — register it on EVM networks too. |
| 213 | + client.register("eip155:*", new UptoEvmScheme(account)); |
| 214 | + this.x402ClientInstance = client; |
209 | 215 | } |
210 | | - return this.signerPromise; |
| 216 | + return this.x402ClientInstance; |
211 | 217 | } |
212 | 218 |
|
213 | 219 | /** |
214 | 220 | * Build a paid fetch that injects the TEE's pinned TLS dispatcher into every |
215 | 221 | * request (including x402 payment retries). |
216 | 222 | */ |
217 | | - private async buildPaidFetch(dispatcher: Agent): Promise<typeof fetch> { |
218 | | - const signer = await this.getSigner(); |
| 223 | + private buildPaidFetch(dispatcher: Agent): typeof fetch { |
219 | 224 | const baseFetch: typeof fetch = ((input: any, init?: any) => |
220 | 225 | fetch(input, { ...(init ?? {}), dispatcher } as any)) as typeof fetch; |
221 | | - return wrapFetchWithPayment( |
222 | | - baseFetch, |
223 | | - signer as any, |
224 | | - this.config.maxPaymentValue, |
225 | | - ) as typeof fetch; |
| 226 | + return wrapFetchWithPayment(baseFetch, this.getX402Client()) as typeof fetch; |
226 | 227 | } |
227 | 228 |
|
228 | 229 | /** |
@@ -261,7 +262,7 @@ export class LLM { |
261 | 262 | ): Promise<{ response: Response; tee: ActiveTEE }> { |
262 | 263 | const tee = await this.config.connection.ensureConnected(); |
263 | 264 | const url = `${trimSlash(tee.endpoint)}${path}`; |
264 | | - const paidFetch = await this.buildPaidFetch(tee.dispatcher); |
| 265 | + const paidFetch = this.buildPaidFetch(tee.dispatcher); |
265 | 266 |
|
266 | 267 | let response: Response; |
267 | 268 | try { |
|
0 commit comments