@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/dist/userop.js
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Signet UserOperation pipeline.
|
|
3
|
+
*
|
|
4
|
+
* Framework-agnostic orchestration of the full ERC-4337 flow:
|
|
5
|
+
* build → (paymaster stub) → estimate → (paymaster real) → hash → FROST sign → submit → confirm
|
|
6
|
+
*
|
|
7
|
+
* The caller provides an already-encoded callData (the app-specific part);
|
|
8
|
+
* everything else is generic Signet protocol logic.
|
|
9
|
+
*/
|
|
10
|
+
import { encodeFunctionData, encodeAbiParameters, keccak256, concat, createPublicClient, http, } from "viem";
|
|
11
|
+
import { signSignRequest } from "./request";
|
|
12
|
+
import { sendUserOp as bundlerSendUserOp, getUserOpReceipt as bundlerGetUserOpReceipt, estimateUserOpGas, getPaymasterStubData, getPaymasterData, applyPaymasterSponsorship, } from "./bundler";
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
// Main pipeline
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
/**
|
|
17
|
+
* Submit a UserOperation through the full Signet pipeline.
|
|
18
|
+
*
|
|
19
|
+
* Ordering is strict — see CLAUDE.md "Write flow ordering" for rationale:
|
|
20
|
+
* 1. Build unsigned UserOp (with initCode if account not deployed)
|
|
21
|
+
* 2. (if paymaster) Attach stub paymasterAndData for gas estimation
|
|
22
|
+
* 3. Estimate gas via bundler
|
|
23
|
+
* 4. (if paymaster) Replace stub with real signed paymaster blob
|
|
24
|
+
* 5. Compute UserOp hash
|
|
25
|
+
* 6. FROST threshold sign via bootstrap group
|
|
26
|
+
* 7. Submit to bundler
|
|
27
|
+
* 8. Poll for receipt
|
|
28
|
+
*/
|
|
29
|
+
export async function submitUserOp(config, params) {
|
|
30
|
+
const { onStatus } = params;
|
|
31
|
+
// 1. Build the UserOperation
|
|
32
|
+
onStatus?.("building");
|
|
33
|
+
const nonce = await fetchNonce(config.rpcUrl, config.entryPointAddress, params.account);
|
|
34
|
+
const initCode = await buildInitCode(config, params.account, params.groupPublicKey);
|
|
35
|
+
let userOp = buildUserOp({
|
|
36
|
+
sender: params.account,
|
|
37
|
+
nonce,
|
|
38
|
+
initCode,
|
|
39
|
+
dest: params.dest,
|
|
40
|
+
value: params.value,
|
|
41
|
+
callData: params.callData,
|
|
42
|
+
});
|
|
43
|
+
// 2. (optional) Attach paymaster stub before gas estimation
|
|
44
|
+
if (config.usePaymaster) {
|
|
45
|
+
onStatus?.("sponsoring-stub");
|
|
46
|
+
const stub = await getPaymasterStubData(config.bundlerProxyUrl, config.entryPointAddress, config.chainId, userOp, config.paymasterContext);
|
|
47
|
+
userOp = applyPaymasterSponsorship(userOp, stub);
|
|
48
|
+
}
|
|
49
|
+
// 3. Estimate gas
|
|
50
|
+
onStatus?.("estimating");
|
|
51
|
+
const gasEstimate = await estimateUserOpGas(config.bundlerProxyUrl, config.entryPointAddress, userOp);
|
|
52
|
+
userOp.accountGasLimits =
|
|
53
|
+
`0x${BigInt(gasEstimate.verificationGasLimit).toString(16).padStart(32, "0")}${BigInt(gasEstimate.callGasLimit).toString(16).padStart(32, "0")}`;
|
|
54
|
+
userOp.preVerificationGas = BigInt(gasEstimate.preVerificationGas);
|
|
55
|
+
// 4. (optional) Replace stub with real signed paymaster blob
|
|
56
|
+
if (config.usePaymaster) {
|
|
57
|
+
onStatus?.("sponsoring");
|
|
58
|
+
const real = await getPaymasterData(config.bundlerProxyUrl, config.entryPointAddress, config.chainId, userOp, config.paymasterContext);
|
|
59
|
+
userOp = applyPaymasterSponsorship(userOp, real);
|
|
60
|
+
}
|
|
61
|
+
// 5. Hash + 6. FROST threshold sign
|
|
62
|
+
onStatus?.("signing");
|
|
63
|
+
const opHash = getUserOpHash(userOp, config.entryPointAddress, config.chainId);
|
|
64
|
+
const messageHash = hexToBytes(opHash);
|
|
65
|
+
const signReq = await signSignRequest(params.sessionKeypair, params.claims, config.bootstrapGroup, messageHash);
|
|
66
|
+
const signRes = await fetch(config.nodeProxyUrl, {
|
|
67
|
+
method: "POST",
|
|
68
|
+
headers: {
|
|
69
|
+
"Content-Type": "application/json",
|
|
70
|
+
"x-node-url": config.bootstrapNodes[0],
|
|
71
|
+
"x-node-path": "/v1/sign",
|
|
72
|
+
},
|
|
73
|
+
body: JSON.stringify(signReq),
|
|
74
|
+
});
|
|
75
|
+
if (!signRes.ok) {
|
|
76
|
+
const body = await signRes.text();
|
|
77
|
+
throw new Error(`Threshold signing failed: ${signRes.status} — ${body}`);
|
|
78
|
+
}
|
|
79
|
+
const { ethereum_signature } = await signRes.json();
|
|
80
|
+
userOp.signature = ethereum_signature;
|
|
81
|
+
// 7. Submit to bundler
|
|
82
|
+
onStatus?.("submitting");
|
|
83
|
+
const { userOpHash } = await bundlerSendUserOp(config.bundlerProxyUrl, config.entryPointAddress, userOp);
|
|
84
|
+
// 8. Poll for receipt
|
|
85
|
+
onStatus?.("confirming");
|
|
86
|
+
let receipt = null;
|
|
87
|
+
for (let i = 0; i < 60; i++) {
|
|
88
|
+
await new Promise((r) => setTimeout(r, 2000));
|
|
89
|
+
receipt = await bundlerGetUserOpReceipt(config.bundlerProxyUrl, userOpHash);
|
|
90
|
+
if (receipt)
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
if (!receipt)
|
|
94
|
+
throw new Error("Transaction confirmation timed out");
|
|
95
|
+
if (!receipt.success)
|
|
96
|
+
throw new Error("UserOperation reverted on-chain");
|
|
97
|
+
return { userOpHash, transactionHash: receipt.transactionHash };
|
|
98
|
+
}
|
|
99
|
+
// ---------------------------------------------------------------------------
|
|
100
|
+
// Utilities
|
|
101
|
+
// ---------------------------------------------------------------------------
|
|
102
|
+
/**
|
|
103
|
+
* Build an unsigned UserOperation for a SignetAccount.execute call.
|
|
104
|
+
*/
|
|
105
|
+
export function buildUserOp(params) {
|
|
106
|
+
const executeCallData = encodeFunctionData({
|
|
107
|
+
abi: [
|
|
108
|
+
{
|
|
109
|
+
name: "execute",
|
|
110
|
+
type: "function",
|
|
111
|
+
inputs: [
|
|
112
|
+
{ name: "dest", type: "address" },
|
|
113
|
+
{ name: "value", type: "uint256" },
|
|
114
|
+
{ name: "data", type: "bytes" },
|
|
115
|
+
],
|
|
116
|
+
outputs: [],
|
|
117
|
+
},
|
|
118
|
+
],
|
|
119
|
+
functionName: "execute",
|
|
120
|
+
args: [params.dest, params.value ?? 0n, params.callData],
|
|
121
|
+
});
|
|
122
|
+
return {
|
|
123
|
+
sender: params.sender,
|
|
124
|
+
nonce: params.nonce,
|
|
125
|
+
initCode: params.initCode ?? "0x",
|
|
126
|
+
callData: executeCallData,
|
|
127
|
+
accountGasLimits: "0x000000000000000000000000000f4240000000000000000000000000001e8480",
|
|
128
|
+
preVerificationGas: 50000n,
|
|
129
|
+
gasFees: "0x000000000000000000000000000000010000000000000000000000003b9aca00",
|
|
130
|
+
paymasterAndData: "0x",
|
|
131
|
+
signature: "0x",
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Compute the UserOperation hash for signing.
|
|
136
|
+
*
|
|
137
|
+
* Matches EntryPoint v0.7 packed format:
|
|
138
|
+
* keccak256(abi.encode(keccak256(packedFields), entryPoint, chainId))
|
|
139
|
+
*/
|
|
140
|
+
export function getUserOpHash(userOp, entryPoint, chainId) {
|
|
141
|
+
const packedHash = keccak256(encodeAbiParameters([
|
|
142
|
+
{ type: "address" },
|
|
143
|
+
{ type: "uint256" },
|
|
144
|
+
{ type: "bytes32" },
|
|
145
|
+
{ type: "bytes32" },
|
|
146
|
+
{ type: "bytes32" },
|
|
147
|
+
{ type: "uint256" },
|
|
148
|
+
{ type: "bytes32" },
|
|
149
|
+
{ type: "bytes32" },
|
|
150
|
+
], [
|
|
151
|
+
userOp.sender,
|
|
152
|
+
userOp.nonce,
|
|
153
|
+
keccak256(userOp.initCode),
|
|
154
|
+
keccak256(userOp.callData),
|
|
155
|
+
userOp.accountGasLimits,
|
|
156
|
+
userOp.preVerificationGas,
|
|
157
|
+
userOp.gasFees,
|
|
158
|
+
keccak256(userOp.paymasterAndData),
|
|
159
|
+
]));
|
|
160
|
+
return keccak256(encodeAbiParameters([{ type: "bytes32" }, { type: "address" }, { type: "uint256" }], [packedHash, entryPoint, BigInt(chainId)]));
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Fetch the current nonce for an account from the EntryPoint.
|
|
164
|
+
*/
|
|
165
|
+
export async function fetchNonce(rpcUrl, entryPointAddress, account) {
|
|
166
|
+
const client = createPublicClient({ transport: http(rpcUrl) });
|
|
167
|
+
return client.readContract({
|
|
168
|
+
address: entryPointAddress,
|
|
169
|
+
abi: [{
|
|
170
|
+
name: "getNonce",
|
|
171
|
+
type: "function",
|
|
172
|
+
inputs: [
|
|
173
|
+
{ name: "sender", type: "address" },
|
|
174
|
+
{ name: "key", type: "uint192" },
|
|
175
|
+
],
|
|
176
|
+
outputs: [{ type: "uint256" }],
|
|
177
|
+
stateMutability: "view",
|
|
178
|
+
}],
|
|
179
|
+
functionName: "getNonce",
|
|
180
|
+
args: [account, 0n],
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Check if a SignetAccount is deployed at the given address.
|
|
185
|
+
*/
|
|
186
|
+
export async function isAccountDeployed(rpcUrl, account) {
|
|
187
|
+
const client = createPublicClient({ transport: http(rpcUrl) });
|
|
188
|
+
const code = await client.getCode({ address: account });
|
|
189
|
+
return !!code && code !== "0x";
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Build initCode for deploying a SignetAccount via the account factory.
|
|
193
|
+
* Returns "0x" if the account is already deployed.
|
|
194
|
+
*/
|
|
195
|
+
export async function buildInitCode(config, account, groupPublicKey) {
|
|
196
|
+
const deployed = await isAccountDeployed(config.rpcUrl, account);
|
|
197
|
+
if (deployed)
|
|
198
|
+
return "0x";
|
|
199
|
+
const factoryCallData = encodeFunctionData({
|
|
200
|
+
abi: config.accountFactoryAbi,
|
|
201
|
+
functionName: "createAccount",
|
|
202
|
+
args: [config.entryPointAddress, groupPublicKey, 0n],
|
|
203
|
+
});
|
|
204
|
+
return concat([config.accountFactoryAddress, factoryCallData]);
|
|
205
|
+
}
|
|
206
|
+
// ---------------------------------------------------------------------------
|
|
207
|
+
// Internal helpers
|
|
208
|
+
// ---------------------------------------------------------------------------
|
|
209
|
+
function hexToBytes(hex) {
|
|
210
|
+
return new Uint8Array((hex.slice(2).match(/.{2}/g) ?? []).map((b) => parseInt(b, 16)));
|
|
211
|
+
}
|
|
212
|
+
//# sourceMappingURL=userop.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"userop.js","sourceRoot":"","sources":["../src/userop.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAGL,kBAAkB,EAClB,mBAAmB,EACnB,SAAS,EACT,MAAM,EACN,kBAAkB,EAClB,IAAI,GACL,MAAM,MAAM,CAAC;AAEd,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EACL,UAAU,IAAI,iBAAiB,EAC/B,gBAAgB,IAAI,uBAAuB,EAC3C,iBAAiB,EACjB,oBAAoB,EACpB,gBAAgB,EAChB,yBAAyB,GAE1B,MAAM,WAAW,CAAC;AAgEnB,8EAA8E;AAC9E,gBAAgB;AAChB,8EAA8E;AAE9E;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,MAAyB,EACzB,MAAyB;IAEzB,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAC;IAE5B,6BAA6B;IAC7B,QAAQ,EAAE,CAAC,UAAU,CAAC,CAAC;IACvB,MAAM,KAAK,GAAG,MAAM,UAAU,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,iBAAiB,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IACxF,MAAM,QAAQ,GAAG,MAAM,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,cAAc,CAAC,CAAC;IAEpF,IAAI,MAAM,GAAG,WAAW,CAAC;QACvB,MAAM,EAAE,MAAM,CAAC,OAAO;QACtB,KAAK;QACL,QAAQ;QACR,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,QAAQ,EAAE,MAAM,CAAC,QAAQ;KAC1B,CAAC,CAAC;IAEH,4DAA4D;IAC5D,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC;QACxB,QAAQ,EAAE,CAAC,iBAAiB,CAAC,CAAC;QAC9B,MAAM,IAAI,GAAG,MAAM,oBAAoB,CACrC,MAAM,CAAC,eAAe,EAAE,MAAM,CAAC,iBAAiB,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,EACxE,MAAM,CAAC,gBAAgB,CACxB,CAAC;QACF,MAAM,GAAG,yBAAyB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACnD,CAAC;IAED,kBAAkB;IAClB,QAAQ,EAAE,CAAC,YAAY,CAAC,CAAC;IACzB,MAAM,WAAW,GAAG,MAAM,iBAAiB,CACzC,MAAM,CAAC,eAAe,EAAE,MAAM,CAAC,iBAAiB,EAAE,MAAM,CACzD,CAAC;IACF,MAAM,CAAC,gBAAgB;QACrB,KAAK,MAAM,CAAC,WAAW,CAAC,oBAAoB,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,EAAE,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,EAAE,EAAE,GAAG,CAAC,EAAS,CAAC;IAC1J,MAAM,CAAC,kBAAkB,GAAG,MAAM,CAAC,WAAW,CAAC,kBAAkB,CAAC,CAAC;IAEnE,6DAA6D;IAC7D,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC;QACxB,QAAQ,EAAE,CAAC,YAAY,CAAC,CAAC;QACzB,MAAM,IAAI,GAAG,MAAM,gBAAgB,CACjC,MAAM,CAAC,eAAe,EAAE,MAAM,CAAC,iBAAiB,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,EACxE,MAAM,CAAC,gBAAgB,CACxB,CAAC;QACF,MAAM,GAAG,yBAAyB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACnD,CAAC;IAED,oCAAoC;IACpC,QAAQ,EAAE,CAAC,SAAS,CAAC,CAAC;IACtB,MAAM,MAAM,GAAG,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,iBAAiB,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IAC/E,MAAM,WAAW,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;IAEvC,MAAM,OAAO,GAAG,MAAM,eAAe,CACnC,MAAM,CAAC,cAAc,EACrB,MAAM,CAAC,MAAM,EACb,MAAM,CAAC,cAAc,EACrB,WAAW,CACZ,CAAC;IAEF,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,YAAY,EAAE;QAC/C,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACP,cAAc,EAAE,kBAAkB;YAClC,YAAY,EAAE,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC;YACtC,aAAa,EAAE,UAAU;SAC1B;QACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;KAC9B,CAAC,CAAC;IAEH,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC;QAChB,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,IAAI,EAAE,CAAC;QAClC,MAAM,IAAI,KAAK,CAAC,6BAA6B,OAAO,CAAC,MAAM,MAAM,IAAI,EAAE,CAAC,CAAC;IAC3E,CAAC;IAED,MAAM,EAAE,kBAAkB,EAAE,GAAG,MAAM,OAAO,CAAC,IAAI,EAAE,CAAC;IACpD,MAAM,CAAC,SAAS,GAAG,kBAAyB,CAAC;IAE7C,uBAAuB;IACvB,QAAQ,EAAE,CAAC,YAAY,CAAC,CAAC;IACzB,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,iBAAiB,CAC5C,MAAM,CAAC,eAAe,EAAE,MAAM,CAAC,iBAAiB,EAAE,MAAM,CACzD,CAAC;IAEF,sBAAsB;IACtB,QAAQ,EAAE,CAAC,YAAY,CAAC,CAAC;IACzB,IAAI,OAAO,GAAG,IAAI,CAAC;IACnB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;QAC5B,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;QAC9C,OAAO,GAAG,MAAM,uBAAuB,CAAC,MAAM,CAAC,eAAe,EAAE,UAAU,CAAC,CAAC;QAC5E,IAAI,OAAO;YAAE,MAAM;IACrB,CAAC;IAED,IAAI,CAAC,OAAO;QAAE,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;IACpE,IAAI,CAAC,OAAO,CAAC,OAAO;QAAE,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;IAEzE,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,OAAO,CAAC,eAAe,EAAE,CAAC;AAClE,CAAC;AAED,8EAA8E;AAC9E,YAAY;AACZ,8EAA8E;AAE9E;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,MAO3B;IACC,MAAM,eAAe,GAAG,kBAAkB,CAAC;QACzC,GAAG,EAAE;YACH;gBACE,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,UAAU;gBAChB,MAAM,EAAE;oBACN,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE;oBACjC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE;oBAClC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE;iBAChC;gBACD,OAAO,EAAE,EAAE;aACZ;SACF;QACD,YAAY,EAAE,SAAS;QACvB,IAAI,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,KAAK,IAAI,EAAE,EAAE,MAAM,CAAC,QAAQ,CAAC;KACzD,CAAC,CAAC;IAEH,OAAO;QACL,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,IAAI;QACjC,QAAQ,EAAE,eAAe;QACzB,gBAAgB,EAAE,oEAAoE;QACtF,kBAAkB,EAAE,MAAM;QAC1B,OAAO,EAAE,oEAAoE;QAC7E,gBAAgB,EAAE,IAAI;QACtB,SAAS,EAAE,IAAI;KAChB,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAC3B,MAA2B,EAC3B,UAAmB,EACnB,OAAe;IAEf,MAAM,UAAU,GAAG,SAAS,CAC1B,mBAAmB,CACjB;QACE,EAAE,IAAI,EAAE,SAAS,EAAE;QACnB,EAAE,IAAI,EAAE,SAAS,EAAE;QACnB,EAAE,IAAI,EAAE,SAAS,EAAE;QACnB,EAAE,IAAI,EAAE,SAAS,EAAE;QACnB,EAAE,IAAI,EAAE,SAAS,EAAE;QACnB,EAAE,IAAI,EAAE,SAAS,EAAE;QACnB,EAAE,IAAI,EAAE,SAAS,EAAE;QACnB,EAAE,IAAI,EAAE,SAAS,EAAE;KACpB,EACD;QACE,MAAM,CAAC,MAAM;QACb,MAAM,CAAC,KAAK;QACZ,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC;QAC1B,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC;QAC1B,MAAM,CAAC,gBAAuB;QAC9B,MAAM,CAAC,kBAAkB;QACzB,MAAM,CAAC,OAAc;QACrB,SAAS,CAAC,MAAM,CAAC,gBAAgB,CAAC;KACnC,CACF,CACF,CAAC;IAEF,OAAO,SAAS,CACd,mBAAmB,CACjB,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,EAC/D,CAAC,UAAU,EAAE,UAAU,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,CAC1C,CACF,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,MAAc,EACd,iBAA0B,EAC1B,OAAgB;IAEhB,MAAM,MAAM,GAAG,kBAAkB,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAC/D,OAAO,MAAM,CAAC,YAAY,CAAC;QACzB,OAAO,EAAE,iBAAiB;QAC1B,GAAG,EAAE,CAAC;gBACJ,IAAI,EAAE,UAAU;gBAChB,IAAI,EAAE,UAAU;gBAChB,MAAM,EAAE;oBACN,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE;oBACnC,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE;iBACjC;gBACD,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;gBAC9B,eAAe,EAAE,MAAM;aACxB,CAAC;QACF,YAAY,EAAE,UAAU;QACxB,IAAI,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC;KACpB,CAAoB,CAAC;AACxB,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,MAAc,EACd,OAAgB;IAEhB,MAAM,MAAM,GAAG,kBAAkB,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAC/D,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;IACxD,OAAO,CAAC,CAAC,IAAI,IAAI,IAAI,KAAK,IAAI,CAAC;AACjC,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,MAA+G,EAC/G,OAAgB,EAChB,cAAmB;IAEnB,MAAM,QAAQ,GAAG,MAAM,iBAAiB,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjE,IAAI,QAAQ;QAAE,OAAO,IAAI,CAAC;IAE1B,MAAM,eAAe,GAAG,kBAAkB,CAAC;QACzC,GAAG,EAAE,MAAM,CAAC,iBAAiB;QAC7B,YAAY,EAAE,eAAe;QAC7B,IAAI,EAAE,CAAC,MAAM,CAAC,iBAAiB,EAAE,cAAc,EAAE,EAAE,CAAC;KACT,CAAC,CAAC;IAE/C,OAAO,MAAM,CAAC,CAAC,MAAM,CAAC,qBAAqB,EAAE,eAAe,CAAC,CAAC,CAAC;AACjE,CAAC;AAED,8EAA8E;AAC9E,mBAAmB;AACnB,8EAA8E;AAE9E,SAAS,UAAU,CAAC,GAAQ;IAC1B,OAAO,IAAI,UAAU,CACnB,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAChE,CAAC;AACJ,CAAC"}
|
package/dist/x402.d.ts
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
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
|
+
export interface PaymentRequirements {
|
|
11
|
+
scheme: string;
|
|
12
|
+
network: string;
|
|
13
|
+
asset: string;
|
|
14
|
+
amount: string;
|
|
15
|
+
payTo: string;
|
|
16
|
+
maxTimeoutSeconds: number;
|
|
17
|
+
extra: Record<string, unknown>;
|
|
18
|
+
}
|
|
19
|
+
export interface PaymentRequired {
|
|
20
|
+
x402Version: number;
|
|
21
|
+
error?: string;
|
|
22
|
+
resource: {
|
|
23
|
+
url: string;
|
|
24
|
+
description?: string;
|
|
25
|
+
mimeType?: string;
|
|
26
|
+
};
|
|
27
|
+
accepts: PaymentRequirements[];
|
|
28
|
+
extensions?: Record<string, unknown>;
|
|
29
|
+
}
|
|
30
|
+
export interface PaymentPayload {
|
|
31
|
+
x402Version: number;
|
|
32
|
+
resource?: {
|
|
33
|
+
url: string;
|
|
34
|
+
};
|
|
35
|
+
accepted: PaymentRequirements;
|
|
36
|
+
payload: Record<string, unknown>;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Parse the `payment-required` header from a 402 response.
|
|
40
|
+
*/
|
|
41
|
+
export declare function parsePaymentRequired(headerValue: string): PaymentRequired;
|
|
42
|
+
/**
|
|
43
|
+
* Find an EVM payment option (Base USDC by default).
|
|
44
|
+
*/
|
|
45
|
+
export declare function findEvmPaymentOption(required: PaymentRequired, preferredNetwork?: string): PaymentRequirements | null;
|
|
46
|
+
/**
|
|
47
|
+
* Build EIP-712 typed data for TransferWithAuthorization (EIP-3009).
|
|
48
|
+
*
|
|
49
|
+
* @param from - The sender's Ethereum address (sub-key's address)
|
|
50
|
+
* @param payTo - Recipient address (from payment requirements)
|
|
51
|
+
* @param amount - Amount in smallest unit (e.g. "10000" for $0.01 USDC)
|
|
52
|
+
* @param asset - Token contract address
|
|
53
|
+
* @param chainId - Chain ID (e.g. 8453 for Base)
|
|
54
|
+
* @param tokenName - Token EIP-712 domain name (e.g. "USD Coin")
|
|
55
|
+
* @param tokenVersion - Token EIP-712 domain version (e.g. "2")
|
|
56
|
+
* @param validAfter - Unix timestamp (default: now - 60s)
|
|
57
|
+
* @param validBefore - Unix timestamp (default: now + 300s)
|
|
58
|
+
*/
|
|
59
|
+
export declare function buildTransferAuthorization(from: string, payTo: string, amount: string, asset: string, chainId: number, tokenName: string, tokenVersion: string, validAfter?: number, validBefore?: number): {
|
|
60
|
+
domain: {
|
|
61
|
+
name: string;
|
|
62
|
+
version: string;
|
|
63
|
+
chainId: number;
|
|
64
|
+
verifyingContract: string;
|
|
65
|
+
};
|
|
66
|
+
types: {
|
|
67
|
+
EIP712Domain: {
|
|
68
|
+
name: string;
|
|
69
|
+
type: string;
|
|
70
|
+
}[];
|
|
71
|
+
TransferWithAuthorization: {
|
|
72
|
+
name: string;
|
|
73
|
+
type: string;
|
|
74
|
+
}[];
|
|
75
|
+
};
|
|
76
|
+
primaryType: "TransferWithAuthorization";
|
|
77
|
+
message: {
|
|
78
|
+
from: string;
|
|
79
|
+
to: string;
|
|
80
|
+
value: string;
|
|
81
|
+
validAfter: string;
|
|
82
|
+
validBefore: string;
|
|
83
|
+
nonce: string;
|
|
84
|
+
};
|
|
85
|
+
};
|
|
86
|
+
/**
|
|
87
|
+
* Build the x402 PaymentPayload from a signed TransferWithAuthorization.
|
|
88
|
+
*
|
|
89
|
+
* @param accepted - The payment option we're fulfilling
|
|
90
|
+
* @param authorization - The TransferWithAuthorization message fields
|
|
91
|
+
* @param signature - The ECDSA signature (0x-prefixed, 65 bytes)
|
|
92
|
+
* @param resourceUrl - The URL of the resource being paid for
|
|
93
|
+
*/
|
|
94
|
+
export declare function buildPaymentPayload(accepted: PaymentRequirements, authorization: {
|
|
95
|
+
from: string;
|
|
96
|
+
to: string;
|
|
97
|
+
value: string;
|
|
98
|
+
validAfter: string;
|
|
99
|
+
validBefore: string;
|
|
100
|
+
nonce: string;
|
|
101
|
+
}, signature: string, resourceUrl?: string): string;
|
|
102
|
+
export interface X402FetchOptions {
|
|
103
|
+
/** The sub-key's Ethereum address (from) */
|
|
104
|
+
signerAddress: string;
|
|
105
|
+
/** Preferred network (default: "eip155:8453" for Base) */
|
|
106
|
+
preferredNetwork?: string;
|
|
107
|
+
/** Called to sign the EIP-712 typed data. Returns the ECDSA signature. */
|
|
108
|
+
signTypedData: (typedData: ReturnType<typeof buildTransferAuthorization>) => Promise<string>;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Make an HTTP request with automatic x402 payment handling.
|
|
112
|
+
*
|
|
113
|
+
* If the server returns 402, automatically builds a payment authorization,
|
|
114
|
+
* signs it, and retries the request with the Payment-Signature header.
|
|
115
|
+
*
|
|
116
|
+
* @returns The successful response (after payment if needed)
|
|
117
|
+
*/
|
|
118
|
+
export declare function x402Fetch(url: string, init: RequestInit, options: X402FetchOptions): Promise<{
|
|
119
|
+
response: Response;
|
|
120
|
+
paid: boolean;
|
|
121
|
+
paymentDetails?: {
|
|
122
|
+
amount: string;
|
|
123
|
+
network: string;
|
|
124
|
+
asset: string;
|
|
125
|
+
};
|
|
126
|
+
}>;
|
|
127
|
+
//# sourceMappingURL=x402.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"x402.d.ts","sourceRoot":"","sources":["../src/x402.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,iBAAiB,EAAE,MAAM,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAED,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE;QACR,GAAG,EAAE,MAAM,CAAC;QACZ,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,OAAO,EAAE,mBAAmB,EAAE,CAAC;IAC/B,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAED,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3B,QAAQ,EAAE,mBAAmB,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAMD;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,eAAe,CAGzE;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,eAAe,EACzB,gBAAgB,SAAgB,GAC/B,mBAAmB,GAAG,IAAI,CAI5B;AAMD;;;;;;;;;;;;GAYG;AACH,wBAAgB,0BAA0B,CACxC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EACpB,UAAU,CAAC,EAAE,MAAM,EACnB,WAAW,CAAC,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;EAuCrB;AAMD;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,mBAAmB,EAC7B,aAAa,EAAE;IACb,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;CACf,EACD,SAAS,EAAE,MAAM,EACjB,WAAW,CAAC,EAAE,MAAM,GACnB,MAAM,CAoBR;AAMD,MAAM,WAAW,gBAAgB;IAC/B,4CAA4C;IAC5C,aAAa,EAAE,MAAM,CAAC;IACtB,0DAA0D;IAC1D,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,0EAA0E;IAC1E,aAAa,EAAE,CAAC,SAAS,EAAE,UAAU,CAAC,OAAO,0BAA0B,CAAC,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CAC9F;AAED;;;;;;;GAOG;AACH,wBAAsB,SAAS,CAC7B,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,WAAW,EACjB,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,OAAO,CAAC;IAAC,cAAc,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAAC,CAqErH"}
|
package/dist/x402.js
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
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
|
+
// Parse 402 response
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
/**
|
|
14
|
+
* Parse the `payment-required` header from a 402 response.
|
|
15
|
+
*/
|
|
16
|
+
export function parsePaymentRequired(headerValue) {
|
|
17
|
+
const json = atob(headerValue);
|
|
18
|
+
return JSON.parse(json);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Find an EVM payment option (Base USDC by default).
|
|
22
|
+
*/
|
|
23
|
+
export function findEvmPaymentOption(required, preferredNetwork = "eip155:8453") {
|
|
24
|
+
return required.accepts.find((a) => a.scheme === "exact" && a.network === preferredNetwork) ?? null;
|
|
25
|
+
}
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
// Build EIP-3009 TransferWithAuthorization
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
/**
|
|
30
|
+
* Build EIP-712 typed data for TransferWithAuthorization (EIP-3009).
|
|
31
|
+
*
|
|
32
|
+
* @param from - The sender's Ethereum address (sub-key's address)
|
|
33
|
+
* @param payTo - Recipient address (from payment requirements)
|
|
34
|
+
* @param amount - Amount in smallest unit (e.g. "10000" for $0.01 USDC)
|
|
35
|
+
* @param asset - Token contract address
|
|
36
|
+
* @param chainId - Chain ID (e.g. 8453 for Base)
|
|
37
|
+
* @param tokenName - Token EIP-712 domain name (e.g. "USD Coin")
|
|
38
|
+
* @param tokenVersion - Token EIP-712 domain version (e.g. "2")
|
|
39
|
+
* @param validAfter - Unix timestamp (default: now - 60s)
|
|
40
|
+
* @param validBefore - Unix timestamp (default: now + 300s)
|
|
41
|
+
*/
|
|
42
|
+
export function buildTransferAuthorization(from, payTo, amount, asset, chainId, tokenName, tokenVersion, validAfter, validBefore) {
|
|
43
|
+
const now = Math.floor(Date.now() / 1000);
|
|
44
|
+
const nonce = "0x" + Array.from(crypto.getRandomValues(new Uint8Array(32)))
|
|
45
|
+
.map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
46
|
+
return {
|
|
47
|
+
domain: {
|
|
48
|
+
name: tokenName,
|
|
49
|
+
version: tokenVersion,
|
|
50
|
+
chainId,
|
|
51
|
+
verifyingContract: asset,
|
|
52
|
+
},
|
|
53
|
+
types: {
|
|
54
|
+
EIP712Domain: [
|
|
55
|
+
{ name: "name", type: "string" },
|
|
56
|
+
{ name: "version", type: "string" },
|
|
57
|
+
{ name: "chainId", type: "uint256" },
|
|
58
|
+
{ name: "verifyingContract", type: "address" },
|
|
59
|
+
],
|
|
60
|
+
TransferWithAuthorization: [
|
|
61
|
+
{ name: "from", type: "address" },
|
|
62
|
+
{ name: "to", type: "address" },
|
|
63
|
+
{ name: "value", type: "uint256" },
|
|
64
|
+
{ name: "validAfter", type: "uint256" },
|
|
65
|
+
{ name: "validBefore", type: "uint256" },
|
|
66
|
+
{ name: "nonce", type: "bytes32" },
|
|
67
|
+
],
|
|
68
|
+
},
|
|
69
|
+
primaryType: "TransferWithAuthorization",
|
|
70
|
+
message: {
|
|
71
|
+
from,
|
|
72
|
+
to: payTo,
|
|
73
|
+
value: amount,
|
|
74
|
+
validAfter: String(validAfter ?? now - 60),
|
|
75
|
+
validBefore: String(validBefore ?? now + 300),
|
|
76
|
+
nonce,
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
// ---------------------------------------------------------------------------
|
|
81
|
+
// Build x402 PaymentPayload
|
|
82
|
+
// ---------------------------------------------------------------------------
|
|
83
|
+
/**
|
|
84
|
+
* Build the x402 PaymentPayload from a signed TransferWithAuthorization.
|
|
85
|
+
*
|
|
86
|
+
* @param accepted - The payment option we're fulfilling
|
|
87
|
+
* @param authorization - The TransferWithAuthorization message fields
|
|
88
|
+
* @param signature - The ECDSA signature (0x-prefixed, 65 bytes)
|
|
89
|
+
* @param resourceUrl - The URL of the resource being paid for
|
|
90
|
+
*/
|
|
91
|
+
export function buildPaymentPayload(accepted, authorization, signature, resourceUrl) {
|
|
92
|
+
const payload = {
|
|
93
|
+
x402Version: 2,
|
|
94
|
+
resource: resourceUrl ? { url: resourceUrl } : undefined,
|
|
95
|
+
accepted,
|
|
96
|
+
payload: {
|
|
97
|
+
signature,
|
|
98
|
+
authorization: {
|
|
99
|
+
from: authorization.from,
|
|
100
|
+
to: authorization.to,
|
|
101
|
+
value: authorization.value,
|
|
102
|
+
validAfter: authorization.validAfter,
|
|
103
|
+
validBefore: authorization.validBefore,
|
|
104
|
+
nonce: authorization.nonce,
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
// Base64-encode the payload for the Payment-Signature header
|
|
109
|
+
return btoa(JSON.stringify(payload));
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Make an HTTP request with automatic x402 payment handling.
|
|
113
|
+
*
|
|
114
|
+
* If the server returns 402, automatically builds a payment authorization,
|
|
115
|
+
* signs it, and retries the request with the Payment-Signature header.
|
|
116
|
+
*
|
|
117
|
+
* @returns The successful response (after payment if needed)
|
|
118
|
+
*/
|
|
119
|
+
export async function x402Fetch(url, init, options) {
|
|
120
|
+
// First attempt
|
|
121
|
+
const res = await fetch(url, init);
|
|
122
|
+
if (res.status !== 402) {
|
|
123
|
+
return { response: res, paid: false };
|
|
124
|
+
}
|
|
125
|
+
// Parse 402 payment requirements
|
|
126
|
+
const paymentHeader = res.headers.get("payment-required");
|
|
127
|
+
if (!paymentHeader) {
|
|
128
|
+
throw new Error("402 response missing payment-required header");
|
|
129
|
+
}
|
|
130
|
+
const required = parsePaymentRequired(paymentHeader);
|
|
131
|
+
const accepted = findEvmPaymentOption(required, options.preferredNetwork);
|
|
132
|
+
if (!accepted) {
|
|
133
|
+
throw new Error(`No compatible EVM payment option found (preferred: ${options.preferredNetwork ?? "eip155:8453"})`);
|
|
134
|
+
}
|
|
135
|
+
// Extract chain ID from network string (e.g. "eip155:8453" → 8453)
|
|
136
|
+
const chainId = parseInt(accepted.network.split(":")[1]);
|
|
137
|
+
const tokenName = accepted.extra?.name ?? "USD Coin";
|
|
138
|
+
const tokenVersion = accepted.extra?.version ?? "2";
|
|
139
|
+
// Build TransferWithAuthorization
|
|
140
|
+
const typedData = buildTransferAuthorization(options.signerAddress, accepted.payTo, accepted.amount, accepted.asset, chainId, tokenName, tokenVersion);
|
|
141
|
+
// Sign via Signet
|
|
142
|
+
const signature = await options.signTypedData(typedData);
|
|
143
|
+
// Build payment payload
|
|
144
|
+
const paymentSignature = buildPaymentPayload(accepted, typedData.message, signature, required.resource.url);
|
|
145
|
+
// Retry with payment
|
|
146
|
+
const paidRes = await fetch(url, {
|
|
147
|
+
...init,
|
|
148
|
+
headers: {
|
|
149
|
+
...(() => {
|
|
150
|
+
const h = {};
|
|
151
|
+
new Headers(init.headers).forEach((v, k) => { h[k] = v; });
|
|
152
|
+
return h;
|
|
153
|
+
})(),
|
|
154
|
+
"Payment-Signature": paymentSignature,
|
|
155
|
+
},
|
|
156
|
+
});
|
|
157
|
+
return {
|
|
158
|
+
response: paidRes,
|
|
159
|
+
paid: true,
|
|
160
|
+
paymentDetails: {
|
|
161
|
+
amount: accepted.amount,
|
|
162
|
+
network: accepted.network,
|
|
163
|
+
asset: accepted.asset,
|
|
164
|
+
},
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
//# sourceMappingURL=x402.js.map
|
package/dist/x402.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"x402.js","sourceRoot":"","sources":["../src/x402.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAmCH,8EAA8E;AAC9E,qBAAqB;AACrB,8EAA8E;AAE9E;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAAC,WAAmB;IACtD,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC;IAC/B,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAClC,QAAyB,EACzB,gBAAgB,GAAG,aAAa;IAEhC,OAAO,QAAQ,CAAC,OAAO,CAAC,IAAI,CAC1B,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,OAAO,IAAI,CAAC,CAAC,OAAO,KAAK,gBAAgB,CAC9D,IAAI,IAAI,CAAC;AACZ,CAAC;AAED,8EAA8E;AAC9E,2CAA2C;AAC3C,8EAA8E;AAE9E;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,0BAA0B,CACxC,IAAY,EACZ,KAAa,EACb,MAAc,EACd,KAAa,EACb,OAAe,EACf,SAAiB,EACjB,YAAoB,EACpB,UAAmB,EACnB,WAAoB;IAEpB,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;IAC1C,MAAM,KAAK,GAAG,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC;SACxE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAExD,OAAO;QACL,MAAM,EAAE;YACN,IAAI,EAAE,SAAS;YACf,OAAO,EAAE,YAAY;YACrB,OAAO;YACP,iBAAiB,EAAE,KAAK;SACzB;QACD,KAAK,EAAE;YACL,YAAY,EAAE;gBACZ,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE;gBAChC,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE;gBACnC,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE;gBACpC,EAAE,IAAI,EAAE,mBAAmB,EAAE,IAAI,EAAE,SAAS,EAAE;aAC/C;YACD,yBAAyB,EAAE;gBACzB,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE;gBACjC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE;gBAC/B,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE;gBAClC,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,SAAS,EAAE;gBACvC,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,SAAS,EAAE;gBACxC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE;aACnC;SACF;QACD,WAAW,EAAE,2BAAoC;QACjD,OAAO,EAAE;YACP,IAAI;YACJ,EAAE,EAAE,KAAK;YACT,KAAK,EAAE,MAAM;YACb,UAAU,EAAE,MAAM,CAAC,UAAU,IAAI,GAAG,GAAG,EAAE,CAAC;YAC1C,WAAW,EAAE,MAAM,CAAC,WAAW,IAAI,GAAG,GAAG,GAAG,CAAC;YAC7C,KAAK;SACN;KACF,CAAC;AACJ,CAAC;AAED,8EAA8E;AAC9E,4BAA4B;AAC5B,8EAA8E;AAE9E;;;;;;;GAOG;AACH,MAAM,UAAU,mBAAmB,CACjC,QAA6B,EAC7B,aAOC,EACD,SAAiB,EACjB,WAAoB;IAEpB,MAAM,OAAO,GAAmB;QAC9B,WAAW,EAAE,CAAC;QACd,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,SAAS;QACxD,QAAQ;QACR,OAAO,EAAE;YACP,SAAS;YACT,aAAa,EAAE;gBACb,IAAI,EAAE,aAAa,CAAC,IAAI;gBACxB,EAAE,EAAE,aAAa,CAAC,EAAE;gBACpB,KAAK,EAAE,aAAa,CAAC,KAAK;gBAC1B,UAAU,EAAE,aAAa,CAAC,UAAU;gBACpC,WAAW,EAAE,aAAa,CAAC,WAAW;gBACtC,KAAK,EAAE,aAAa,CAAC,KAAK;aAC3B;SACF;KACF,CAAC;IAEF,6DAA6D;IAC7D,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;AACvC,CAAC;AAeD;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,GAAW,EACX,IAAiB,EACjB,OAAyB;IAEzB,gBAAgB;IAChB,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IAEnC,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;QACvB,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;IACxC,CAAC;IAED,iCAAiC;IACjC,MAAM,aAAa,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;IAC1D,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;IAClE,CAAC;IAED,MAAM,QAAQ,GAAG,oBAAoB,CAAC,aAAa,CAAC,CAAC;IACrD,MAAM,QAAQ,GAAG,oBAAoB,CAAC,QAAQ,EAAE,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAC1E,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,sDAAsD,OAAO,CAAC,gBAAgB,IAAI,aAAa,GAAG,CAAC,CAAC;IACtH,CAAC;IAED,mEAAmE;IACnE,MAAM,OAAO,GAAG,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACzD,MAAM,SAAS,GAAI,QAAQ,CAAC,KAAK,EAAE,IAAe,IAAI,UAAU,CAAC;IACjE,MAAM,YAAY,GAAI,QAAQ,CAAC,KAAK,EAAE,OAAkB,IAAI,GAAG,CAAC;IAEhE,kCAAkC;IAClC,MAAM,SAAS,GAAG,0BAA0B,CAC1C,OAAO,CAAC,aAAa,EACrB,QAAQ,CAAC,KAAK,EACd,QAAQ,CAAC,MAAM,EACf,QAAQ,CAAC,KAAK,EACd,OAAO,EACP,SAAS,EACT,YAAY,CACb,CAAC;IAEF,kBAAkB;IAClB,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;IAEzD,wBAAwB;IACxB,MAAM,gBAAgB,GAAG,mBAAmB,CAC1C,QAAQ,EACR,SAAS,CAAC,OAAO,EACjB,SAAS,EACT,QAAQ,CAAC,QAAQ,CAAC,GAAG,CACtB,CAAC;IAEF,qBAAqB;IACrB,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;QAC/B,GAAG,IAAI;QACP,OAAO,EAAE;YACP,GAAG,CAAC,GAA2B,EAAE;gBAC/B,MAAM,CAAC,GAA2B,EAAE,CAAA;gBACpC,IAAI,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA,CAAC,CAAC,CAAC,CAAA;gBACzD,OAAO,CAAC,CAAA;YACV,CAAC,CAAC,EAAE;YACJ,mBAAmB,EAAE,gBAAgB;SACtC;KACF,CAAC,CAAC;IAEH,OAAO;QACL,QAAQ,EAAE,OAAO;QACjB,IAAI,EAAE,IAAI;QACV,cAAc,EAAE;YACd,MAAM,EAAE,QAAQ,CAAC,MAAM;YACvB,OAAO,EAAE,QAAQ,CAAC,OAAO;YACzB,KAAK,EAAE,QAAQ,CAAC,KAAK;SACtB;KACF,CAAC;AACJ,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@oleary-labs/signet-sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Signet DKMS SDK — threshold signing, key management, delegation, and x402 payments",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": { "import": "./dist/index.js", "types": "./dist/index.d.ts" },
|
|
10
|
+
"./session": { "import": "./dist/session.js", "types": "./dist/session.d.ts" },
|
|
11
|
+
"./request": { "import": "./dist/request.js", "types": "./dist/request.d.ts" },
|
|
12
|
+
"./keygen": { "import": "./dist/keygen.js", "types": "./dist/keygen.d.ts" },
|
|
13
|
+
"./types": { "import": "./dist/types.js", "types": "./dist/types.d.ts" },
|
|
14
|
+
"./jwks": { "import": "./dist/jwks.js", "types": "./dist/jwks.d.ts" },
|
|
15
|
+
"./oauth": { "import": "./dist/oauth.js", "types": "./dist/oauth.d.ts" },
|
|
16
|
+
"./bootstrap": { "import": "./dist/bootstrap.js", "types": "./dist/bootstrap.d.ts" },
|
|
17
|
+
"./authkey-session": { "import": "./dist/authkey-session.js", "types": "./dist/authkey-session.d.ts" },
|
|
18
|
+
"./proof": { "import": "./dist/proof.js", "types": "./dist/proof.d.ts" },
|
|
19
|
+
"./server-prover": { "import": "./dist/server-prover.js", "types": "./dist/server-prover.d.ts" },
|
|
20
|
+
"./witness": { "import": "./dist/witness.js", "types": "./dist/witness.d.ts" },
|
|
21
|
+
"./jwt": { "import": "./dist/jwt.js", "types": "./dist/jwt.d.ts" },
|
|
22
|
+
"./admin": { "import": "./dist/admin.js", "types": "./dist/admin.d.ts" },
|
|
23
|
+
"./delegate": { "import": "./dist/delegate.js", "types": "./dist/delegate.d.ts" },
|
|
24
|
+
"./scopedSign": { "import": "./dist/scopedSign.js", "types": "./dist/scopedSign.d.ts" },
|
|
25
|
+
"./frostVerify": { "import": "./dist/frostVerify.js", "types": "./dist/frostVerify.d.ts" },
|
|
26
|
+
"./x402": { "import": "./dist/x402.js", "types": "./dist/x402.d.ts" },
|
|
27
|
+
"./userop": { "import": "./dist/userop.js", "types": "./dist/userop.d.ts" },
|
|
28
|
+
"./bundler": { "import": "./dist/bundler.js", "types": "./dist/bundler.d.ts" }
|
|
29
|
+
},
|
|
30
|
+
"files": [
|
|
31
|
+
"dist",
|
|
32
|
+
"src"
|
|
33
|
+
],
|
|
34
|
+
"scripts": {
|
|
35
|
+
"build": "tsc",
|
|
36
|
+
"typecheck": "tsc --noEmit",
|
|
37
|
+
"prepublishOnly": "bun run build"
|
|
38
|
+
},
|
|
39
|
+
"peerDependencies": {
|
|
40
|
+
"viem": ">=2.0.0",
|
|
41
|
+
"@noir-lang/noir_js": ">=1.0.0-beta.0",
|
|
42
|
+
"@aztec/bb.js": ">=0.80.0",
|
|
43
|
+
"@oleary-labs/signet-circuits": ">=0.1.0"
|
|
44
|
+
},
|
|
45
|
+
"peerDependenciesMeta": {
|
|
46
|
+
"@noir-lang/noir_js": { "optional": true },
|
|
47
|
+
"@aztec/bb.js": { "optional": true },
|
|
48
|
+
"@oleary-labs/signet-circuits": { "optional": true }
|
|
49
|
+
},
|
|
50
|
+
"dependencies": {
|
|
51
|
+
"@noble/curves": "^1.9.0",
|
|
52
|
+
"@noble/hashes": "^1.8.0",
|
|
53
|
+
"@noble/secp256k1": "^3.0.0"
|
|
54
|
+
},
|
|
55
|
+
"devDependencies": {
|
|
56
|
+
"typescript": "^5.0.0",
|
|
57
|
+
"viem": "^2.48.0"
|
|
58
|
+
},
|
|
59
|
+
"license": "MIT",
|
|
60
|
+
"repository": {
|
|
61
|
+
"type": "git",
|
|
62
|
+
"url": "https://github.com/oleary-labs/signet-sdk"
|
|
63
|
+
}
|
|
64
|
+
}
|