@oleary-labs/signet-sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/admin.d.ts +38 -0
- package/dist/admin.d.ts.map +1 -0
- package/dist/admin.js +112 -0
- package/dist/admin.js.map +1 -0
- package/dist/authkey-session.d.ts +64 -0
- package/dist/authkey-session.d.ts.map +1 -0
- package/dist/authkey-session.js +164 -0
- package/dist/authkey-session.js.map +1 -0
- package/dist/bootstrap.d.ts +30 -0
- package/dist/bootstrap.d.ts.map +1 -0
- package/dist/bootstrap.js +60 -0
- package/dist/bootstrap.js.map +1 -0
- package/dist/bundler.d.ts +85 -0
- package/dist/bundler.d.ts.map +1 -0
- package/dist/bundler.js +160 -0
- package/dist/bundler.js.map +1 -0
- package/dist/delegate.d.ts +57 -0
- package/dist/delegate.d.ts.map +1 -0
- package/dist/delegate.js +111 -0
- package/dist/delegate.js.map +1 -0
- package/dist/frostVerify.d.ts +23 -0
- package/dist/frostVerify.d.ts.map +1 -0
- package/dist/frostVerify.js +69 -0
- package/dist/frostVerify.js.map +1 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +38 -0
- package/dist/index.js.map +1 -0
- package/dist/jwks.d.ts +28 -0
- package/dist/jwks.d.ts.map +1 -0
- package/dist/jwks.js +81 -0
- package/dist/jwks.js.map +1 -0
- package/dist/jwt.d.ts +27 -0
- package/dist/jwt.d.ts.map +1 -0
- package/dist/jwt.js +50 -0
- package/dist/jwt.js.map +1 -0
- package/dist/keygen.d.ts +26 -0
- package/dist/keygen.d.ts.map +1 -0
- package/dist/keygen.js +60 -0
- package/dist/keygen.js.map +1 -0
- package/dist/oauth.d.ts +34 -0
- package/dist/oauth.d.ts.map +1 -0
- package/dist/oauth.js +119 -0
- package/dist/oauth.js.map +1 -0
- package/dist/request.d.ts +42 -0
- package/dist/request.d.ts.map +1 -0
- package/dist/request.js +115 -0
- package/dist/request.js.map +1 -0
- package/dist/scopedSign.d.ts +82 -0
- package/dist/scopedSign.d.ts.map +1 -0
- package/dist/scopedSign.js +130 -0
- package/dist/scopedSign.js.map +1 -0
- package/dist/server-prover.d.ts +29 -0
- package/dist/server-prover.d.ts.map +1 -0
- package/dist/server-prover.js +54 -0
- package/dist/server-prover.js.map +1 -0
- package/dist/session.d.ts +14 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +29 -0
- package/dist/session.js.map +1 -0
- package/dist/types.d.ts +56 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/dist/userop.d.ts +104 -0
- package/dist/userop.d.ts.map +1 -0
- package/dist/userop.js +212 -0
- package/dist/userop.js.map +1 -0
- package/dist/x402.d.ts +127 -0
- package/dist/x402.d.ts.map +1 -0
- package/dist/x402.js +167 -0
- package/dist/x402.js.map +1 -0
- package/package.json +64 -0
- package/src/admin.ts +178 -0
- package/src/authkey-session.ts +241 -0
- package/src/bootstrap.ts +106 -0
- package/src/bundler.ts +256 -0
- package/src/delegate.ts +163 -0
- package/src/frostVerify.ts +79 -0
- package/src/generate-inputs.ts +158 -0
- package/src/index.ts +43 -0
- package/src/jwks.ts +92 -0
- package/src/jwt.ts +74 -0
- package/src/keygen.ts +89 -0
- package/src/oauth.ts +157 -0
- package/src/partial-sha.ts +99 -0
- package/src/proof.ts +99 -0
- package/src/request.ts +174 -0
- package/src/scopedSign.ts +184 -0
- package/src/server-prover.ts +76 -0
- package/src/session.ts +33 -0
- package/src/types.ts +63 -0
- package/src/userop.ts +368 -0
- package/src/witness.ts +132 -0
- package/src/x402.ts +275 -0
package/src/x402.ts
ADDED
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* x402 payment protocol client.
|
|
3
|
+
*
|
|
4
|
+
* Handles the HTTP 402 payment flow:
|
|
5
|
+
* 1. Parse `payment-required` header from 402 response
|
|
6
|
+
* 2. Build EIP-3009 TransferWithAuthorization typed data
|
|
7
|
+
* 3. Construct PaymentPayload with signature
|
|
8
|
+
* 4. Encode for `Payment-Signature` header
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
// Types (matching x402 protocol spec)
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
|
|
15
|
+
export interface PaymentRequirements {
|
|
16
|
+
scheme: string;
|
|
17
|
+
network: string;
|
|
18
|
+
asset: string;
|
|
19
|
+
amount: string;
|
|
20
|
+
payTo: string;
|
|
21
|
+
maxTimeoutSeconds: number;
|
|
22
|
+
extra: Record<string, unknown>;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface PaymentRequired {
|
|
26
|
+
x402Version: number;
|
|
27
|
+
error?: string;
|
|
28
|
+
resource: {
|
|
29
|
+
url: string;
|
|
30
|
+
description?: string;
|
|
31
|
+
mimeType?: string;
|
|
32
|
+
};
|
|
33
|
+
accepts: PaymentRequirements[];
|
|
34
|
+
extensions?: Record<string, unknown>;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface PaymentPayload {
|
|
38
|
+
x402Version: number;
|
|
39
|
+
resource?: { url: string };
|
|
40
|
+
accepted: PaymentRequirements;
|
|
41
|
+
payload: Record<string, unknown>;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// ---------------------------------------------------------------------------
|
|
45
|
+
// Parse 402 response
|
|
46
|
+
// ---------------------------------------------------------------------------
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Parse the `payment-required` header from a 402 response.
|
|
50
|
+
*/
|
|
51
|
+
export function parsePaymentRequired(headerValue: string): PaymentRequired {
|
|
52
|
+
const json = atob(headerValue);
|
|
53
|
+
return JSON.parse(json);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Find an EVM payment option (Base USDC by default).
|
|
58
|
+
*/
|
|
59
|
+
export function findEvmPaymentOption(
|
|
60
|
+
required: PaymentRequired,
|
|
61
|
+
preferredNetwork = "eip155:8453",
|
|
62
|
+
): PaymentRequirements | null {
|
|
63
|
+
return required.accepts.find(
|
|
64
|
+
(a) => a.scheme === "exact" && a.network === preferredNetwork,
|
|
65
|
+
) ?? null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// ---------------------------------------------------------------------------
|
|
69
|
+
// Build EIP-3009 TransferWithAuthorization
|
|
70
|
+
// ---------------------------------------------------------------------------
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Build EIP-712 typed data for TransferWithAuthorization (EIP-3009).
|
|
74
|
+
*
|
|
75
|
+
* @param from - The sender's Ethereum address (sub-key's address)
|
|
76
|
+
* @param payTo - Recipient address (from payment requirements)
|
|
77
|
+
* @param amount - Amount in smallest unit (e.g. "10000" for $0.01 USDC)
|
|
78
|
+
* @param asset - Token contract address
|
|
79
|
+
* @param chainId - Chain ID (e.g. 8453 for Base)
|
|
80
|
+
* @param tokenName - Token EIP-712 domain name (e.g. "USD Coin")
|
|
81
|
+
* @param tokenVersion - Token EIP-712 domain version (e.g. "2")
|
|
82
|
+
* @param validAfter - Unix timestamp (default: now - 60s)
|
|
83
|
+
* @param validBefore - Unix timestamp (default: now + 300s)
|
|
84
|
+
*/
|
|
85
|
+
export function buildTransferAuthorization(
|
|
86
|
+
from: string,
|
|
87
|
+
payTo: string,
|
|
88
|
+
amount: string,
|
|
89
|
+
asset: string,
|
|
90
|
+
chainId: number,
|
|
91
|
+
tokenName: string,
|
|
92
|
+
tokenVersion: string,
|
|
93
|
+
validAfter?: number,
|
|
94
|
+
validBefore?: number,
|
|
95
|
+
) {
|
|
96
|
+
const now = Math.floor(Date.now() / 1000);
|
|
97
|
+
const nonce = "0x" + Array.from(crypto.getRandomValues(new Uint8Array(32)))
|
|
98
|
+
.map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
99
|
+
|
|
100
|
+
return {
|
|
101
|
+
domain: {
|
|
102
|
+
name: tokenName,
|
|
103
|
+
version: tokenVersion,
|
|
104
|
+
chainId,
|
|
105
|
+
verifyingContract: asset,
|
|
106
|
+
},
|
|
107
|
+
types: {
|
|
108
|
+
EIP712Domain: [
|
|
109
|
+
{ name: "name", type: "string" },
|
|
110
|
+
{ name: "version", type: "string" },
|
|
111
|
+
{ name: "chainId", type: "uint256" },
|
|
112
|
+
{ name: "verifyingContract", type: "address" },
|
|
113
|
+
],
|
|
114
|
+
TransferWithAuthorization: [
|
|
115
|
+
{ name: "from", type: "address" },
|
|
116
|
+
{ name: "to", type: "address" },
|
|
117
|
+
{ name: "value", type: "uint256" },
|
|
118
|
+
{ name: "validAfter", type: "uint256" },
|
|
119
|
+
{ name: "validBefore", type: "uint256" },
|
|
120
|
+
{ name: "nonce", type: "bytes32" },
|
|
121
|
+
],
|
|
122
|
+
},
|
|
123
|
+
primaryType: "TransferWithAuthorization" as const,
|
|
124
|
+
message: {
|
|
125
|
+
from,
|
|
126
|
+
to: payTo,
|
|
127
|
+
value: amount,
|
|
128
|
+
validAfter: String(validAfter ?? now - 60),
|
|
129
|
+
validBefore: String(validBefore ?? now + 300),
|
|
130
|
+
nonce,
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// ---------------------------------------------------------------------------
|
|
136
|
+
// Build x402 PaymentPayload
|
|
137
|
+
// ---------------------------------------------------------------------------
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Build the x402 PaymentPayload from a signed TransferWithAuthorization.
|
|
141
|
+
*
|
|
142
|
+
* @param accepted - The payment option we're fulfilling
|
|
143
|
+
* @param authorization - The TransferWithAuthorization message fields
|
|
144
|
+
* @param signature - The ECDSA signature (0x-prefixed, 65 bytes)
|
|
145
|
+
* @param resourceUrl - The URL of the resource being paid for
|
|
146
|
+
*/
|
|
147
|
+
export function buildPaymentPayload(
|
|
148
|
+
accepted: PaymentRequirements,
|
|
149
|
+
authorization: {
|
|
150
|
+
from: string;
|
|
151
|
+
to: string;
|
|
152
|
+
value: string;
|
|
153
|
+
validAfter: string;
|
|
154
|
+
validBefore: string;
|
|
155
|
+
nonce: string;
|
|
156
|
+
},
|
|
157
|
+
signature: string,
|
|
158
|
+
resourceUrl?: string,
|
|
159
|
+
): string {
|
|
160
|
+
const payload: PaymentPayload = {
|
|
161
|
+
x402Version: 2,
|
|
162
|
+
resource: resourceUrl ? { url: resourceUrl } : undefined,
|
|
163
|
+
accepted,
|
|
164
|
+
payload: {
|
|
165
|
+
signature,
|
|
166
|
+
authorization: {
|
|
167
|
+
from: authorization.from,
|
|
168
|
+
to: authorization.to,
|
|
169
|
+
value: authorization.value,
|
|
170
|
+
validAfter: authorization.validAfter,
|
|
171
|
+
validBefore: authorization.validBefore,
|
|
172
|
+
nonce: authorization.nonce,
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
// Base64-encode the payload for the Payment-Signature header
|
|
178
|
+
return btoa(JSON.stringify(payload));
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// ---------------------------------------------------------------------------
|
|
182
|
+
// Full x402 fetch wrapper
|
|
183
|
+
// ---------------------------------------------------------------------------
|
|
184
|
+
|
|
185
|
+
export interface X402FetchOptions {
|
|
186
|
+
/** The sub-key's Ethereum address (from) */
|
|
187
|
+
signerAddress: string;
|
|
188
|
+
/** Preferred network (default: "eip155:8453" for Base) */
|
|
189
|
+
preferredNetwork?: string;
|
|
190
|
+
/** Called to sign the EIP-712 typed data. Returns the ECDSA signature. */
|
|
191
|
+
signTypedData: (typedData: ReturnType<typeof buildTransferAuthorization>) => Promise<string>;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Make an HTTP request with automatic x402 payment handling.
|
|
196
|
+
*
|
|
197
|
+
* If the server returns 402, automatically builds a payment authorization,
|
|
198
|
+
* signs it, and retries the request with the Payment-Signature header.
|
|
199
|
+
*
|
|
200
|
+
* @returns The successful response (after payment if needed)
|
|
201
|
+
*/
|
|
202
|
+
export async function x402Fetch(
|
|
203
|
+
url: string,
|
|
204
|
+
init: RequestInit,
|
|
205
|
+
options: X402FetchOptions,
|
|
206
|
+
): Promise<{ response: Response; paid: boolean; paymentDetails?: { amount: string; network: string; asset: string } }> {
|
|
207
|
+
// First attempt
|
|
208
|
+
const res = await fetch(url, init);
|
|
209
|
+
|
|
210
|
+
if (res.status !== 402) {
|
|
211
|
+
return { response: res, paid: false };
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Parse 402 payment requirements
|
|
215
|
+
const paymentHeader = res.headers.get("payment-required");
|
|
216
|
+
if (!paymentHeader) {
|
|
217
|
+
throw new Error("402 response missing payment-required header");
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const required = parsePaymentRequired(paymentHeader);
|
|
221
|
+
const accepted = findEvmPaymentOption(required, options.preferredNetwork);
|
|
222
|
+
if (!accepted) {
|
|
223
|
+
throw new Error(`No compatible EVM payment option found (preferred: ${options.preferredNetwork ?? "eip155:8453"})`);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Extract chain ID from network string (e.g. "eip155:8453" → 8453)
|
|
227
|
+
const chainId = parseInt(accepted.network.split(":")[1]);
|
|
228
|
+
const tokenName = (accepted.extra?.name as string) ?? "USD Coin";
|
|
229
|
+
const tokenVersion = (accepted.extra?.version as string) ?? "2";
|
|
230
|
+
|
|
231
|
+
// Build TransferWithAuthorization
|
|
232
|
+
const typedData = buildTransferAuthorization(
|
|
233
|
+
options.signerAddress,
|
|
234
|
+
accepted.payTo,
|
|
235
|
+
accepted.amount,
|
|
236
|
+
accepted.asset,
|
|
237
|
+
chainId,
|
|
238
|
+
tokenName,
|
|
239
|
+
tokenVersion,
|
|
240
|
+
);
|
|
241
|
+
|
|
242
|
+
// Sign via Signet
|
|
243
|
+
const signature = await options.signTypedData(typedData);
|
|
244
|
+
|
|
245
|
+
// Build payment payload
|
|
246
|
+
const paymentSignature = buildPaymentPayload(
|
|
247
|
+
accepted,
|
|
248
|
+
typedData.message,
|
|
249
|
+
signature,
|
|
250
|
+
required.resource.url,
|
|
251
|
+
);
|
|
252
|
+
|
|
253
|
+
// Retry with payment
|
|
254
|
+
const paidRes = await fetch(url, {
|
|
255
|
+
...init,
|
|
256
|
+
headers: {
|
|
257
|
+
...((): Record<string, string> => {
|
|
258
|
+
const h: Record<string, string> = {}
|
|
259
|
+
new Headers(init.headers).forEach((v, k) => { h[k] = v })
|
|
260
|
+
return h
|
|
261
|
+
})(),
|
|
262
|
+
"Payment-Signature": paymentSignature,
|
|
263
|
+
},
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
return {
|
|
267
|
+
response: paidRes,
|
|
268
|
+
paid: true,
|
|
269
|
+
paymentDetails: {
|
|
270
|
+
amount: accepted.amount,
|
|
271
|
+
network: accepted.network,
|
|
272
|
+
asset: accepted.asset,
|
|
273
|
+
},
|
|
274
|
+
};
|
|
275
|
+
}
|