@armory-sh/client-web3 0.2.9 → 0.2.11
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/index.d.ts +13 -156
- package/dist/index.js +79 -365
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Web3BaseWalletAccount, Web3BaseWallet } from 'web3-types';
|
|
2
|
-
import {
|
|
3
|
-
export {
|
|
2
|
+
import { NetworkConfig, CustomToken, PaymentPayloadV2, PaymentRequirementsV2, SettlementResponseV2 } from '@armory-sh/base';
|
|
3
|
+
export { EIP3009Authorization, PaymentPayloadV2, PaymentRequirementsV2, SchemePayloadV2, SettlementResponseV2 } from '@armory-sh/base';
|
|
4
4
|
|
|
5
5
|
type Web3Account = Web3BaseWalletAccount | Web3BaseWallet<Web3BaseWalletAccount>;
|
|
6
6
|
/** Token configuration - can use pre-configured tokens from @armory-sh/tokens */
|
|
@@ -8,7 +8,7 @@ type Token = CustomToken;
|
|
|
8
8
|
interface Web3ClientConfig {
|
|
9
9
|
account: Web3Account;
|
|
10
10
|
network: NetworkConfig | string;
|
|
11
|
-
version?:
|
|
11
|
+
version?: 2;
|
|
12
12
|
rpcUrl?: string;
|
|
13
13
|
/** Pre-configured token object (overrides individual fields below) */
|
|
14
14
|
token?: Token;
|
|
@@ -18,15 +18,12 @@ interface Web3ClientConfig {
|
|
|
18
18
|
domainVersion?: string;
|
|
19
19
|
}
|
|
20
20
|
interface PaymentSignatureResult {
|
|
21
|
-
v?: number;
|
|
22
|
-
r?: string;
|
|
23
|
-
s?: string;
|
|
24
21
|
signature?: {
|
|
25
22
|
v: number;
|
|
26
23
|
r: string;
|
|
27
24
|
s: string;
|
|
28
25
|
};
|
|
29
|
-
payload:
|
|
26
|
+
payload: PaymentPayloadV2;
|
|
30
27
|
}
|
|
31
28
|
interface PaymentSignOptions {
|
|
32
29
|
amount: string | bigint;
|
|
@@ -35,30 +32,24 @@ interface PaymentSignOptions {
|
|
|
35
32
|
expiry?: number;
|
|
36
33
|
validAfter?: number;
|
|
37
34
|
}
|
|
38
|
-
interface X402RequestContext {
|
|
39
|
-
url: string;
|
|
40
|
-
method: string;
|
|
41
|
-
headers: Record<string, string> | Headers;
|
|
42
|
-
body?: string | Record<string, unknown> | null;
|
|
43
|
-
version: 1 | 2;
|
|
44
|
-
}
|
|
45
35
|
interface X402TransportOptions {
|
|
46
36
|
client: Web3X402Client;
|
|
47
37
|
autoSign?: boolean;
|
|
48
38
|
maxRetries?: number;
|
|
49
39
|
}
|
|
40
|
+
interface X402Transport {
|
|
41
|
+
fetch(url: string | Request, init?: RequestInit): Promise<Response>;
|
|
42
|
+
getClient(): Web3X402Client;
|
|
43
|
+
}
|
|
50
44
|
interface Web3X402Client {
|
|
45
|
+
fetch(url: string | Request, init?: RequestInit): Promise<Response>;
|
|
51
46
|
getAccount(): Web3Account;
|
|
52
47
|
getNetwork(): NetworkConfig;
|
|
53
|
-
getVersion():
|
|
48
|
+
getVersion(): 2;
|
|
54
49
|
signPayment(options: PaymentSignOptions): Promise<PaymentSignatureResult>;
|
|
55
50
|
createPaymentHeaders(options: PaymentSignOptions): Promise<Headers>;
|
|
56
|
-
handlePaymentRequired(requirements:
|
|
57
|
-
verifySettlement(response:
|
|
58
|
-
}
|
|
59
|
-
interface X402Transport {
|
|
60
|
-
fetch(url: string | Request, init?: RequestInit): Promise<Response>;
|
|
61
|
-
getClient(): Web3X402Client;
|
|
51
|
+
handlePaymentRequired(requirements: PaymentRequirementsV2): Promise<PaymentSignatureResult>;
|
|
52
|
+
verifySettlement(response: SettlementResponseV2): boolean;
|
|
62
53
|
}
|
|
63
54
|
interface Web3TransferWithAuthorization {
|
|
64
55
|
from: string;
|
|
@@ -75,10 +66,6 @@ interface Web3EIP712Domain {
|
|
|
75
66
|
verifyingContract: string;
|
|
76
67
|
[key: string]: string | number;
|
|
77
68
|
}
|
|
78
|
-
declare const isV1Requirements: (requirements: PaymentRequirementsV1 | PaymentRequirementsV2) => requirements is PaymentRequirementsV1;
|
|
79
|
-
declare const isV2Requirements: (requirements: PaymentRequirementsV1 | PaymentRequirementsV2) => requirements is PaymentRequirementsV2;
|
|
80
|
-
declare const isV1Settlement: (response: SettlementResponseV1 | SettlementResponseV2) => response is SettlementResponseV1;
|
|
81
|
-
declare const isV2Settlement: (response: SettlementResponseV1 | SettlementResponseV2) => response is SettlementResponseV2;
|
|
82
69
|
|
|
83
70
|
declare const createX402Client: (config: Web3ClientConfig) => Web3X402Client;
|
|
84
71
|
|
|
@@ -86,137 +73,7 @@ declare const createX402Client: (config: Web3ClientConfig) => Web3X402Client;
|
|
|
86
73
|
* Create an x402 transport layer for handling payment-required responses
|
|
87
74
|
*/
|
|
88
75
|
declare const createX402Transport: (options: X402TransportOptions) => X402Transport;
|
|
89
|
-
/**
|
|
90
|
-
* Create a fetch function bound to an x402 transport
|
|
91
|
-
*/
|
|
92
|
-
declare const createFetchWithX402: (transport: X402Transport) => (url: string | Request, init?: RequestInit) => Promise<Response>;
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* X402 Protocol Detection and Parsing Functions
|
|
96
|
-
*
|
|
97
|
-
* Handles both x402 V1 and V2 protocol detection and parsing from HTTP responses.
|
|
98
|
-
*/
|
|
99
|
-
|
|
100
|
-
type X402Version = 1 | 2;
|
|
101
|
-
interface ParsedPaymentRequired {
|
|
102
|
-
version: X402Version;
|
|
103
|
-
requirements: PaymentRequirementsV1[] | PaymentRequirementsV2[];
|
|
104
|
-
raw: X402PaymentRequiredV1 | PaymentRequiredV2;
|
|
105
|
-
}
|
|
106
|
-
/**
|
|
107
|
-
* Detect x402 protocol version from response headers
|
|
108
|
-
* Returns V2 if PAYMENT-REQUIRED header exists, V1 for X-PAYMENT-REQUIRED
|
|
109
|
-
* Falls back to body detection if no headers present
|
|
110
|
-
*/
|
|
111
|
-
declare const detectX402Version: (response: Response, fallbackVersion?: X402Version) => X402Version;
|
|
112
|
-
/**
|
|
113
|
-
* Detect version from a parsed payment required object
|
|
114
|
-
*/
|
|
115
|
-
declare const detectVersionFromObject: (obj: unknown) => X402Version | null;
|
|
116
|
-
/**
|
|
117
|
-
* Parse PAYMENT-REQUIRED header or response body
|
|
118
|
-
* Handles both V1 (base64 encoded) and V2 (JSON) formats
|
|
119
|
-
*/
|
|
120
|
-
declare const parsePaymentRequired: (response: Response, version?: X402Version) => Promise<ParsedPaymentRequired>;
|
|
121
|
-
/**
|
|
122
|
-
* Parse payment required from header value
|
|
123
|
-
*/
|
|
124
|
-
declare const parsePaymentRequiredFromHeader: (header: string, version: X402Version) => ParsedPaymentRequired;
|
|
125
|
-
/**
|
|
126
|
-
* Parse payment required from response body
|
|
127
|
-
*/
|
|
128
|
-
declare const parsePaymentRequiredFromBody: (body: string, version: X402Version) => ParsedPaymentRequired;
|
|
129
|
-
/**
|
|
130
|
-
* Create x402 V1 payment payload
|
|
131
|
-
*/
|
|
132
|
-
declare const createX402V1Payment: (params: {
|
|
133
|
-
from: string;
|
|
134
|
-
to: string;
|
|
135
|
-
value: string;
|
|
136
|
-
nonce: `0x${string}`;
|
|
137
|
-
validAfter: string;
|
|
138
|
-
validBefore: string;
|
|
139
|
-
signature: `0x${string}`;
|
|
140
|
-
network: string;
|
|
141
|
-
}) => X402PaymentPayloadV1;
|
|
142
|
-
/**
|
|
143
|
-
* Create x402 V2 payment payload
|
|
144
|
-
*/
|
|
145
|
-
declare const createX402V2Payment: (params: {
|
|
146
|
-
from: string;
|
|
147
|
-
to: string;
|
|
148
|
-
value: string;
|
|
149
|
-
nonce: `0x${string}`;
|
|
150
|
-
validAfter: string;
|
|
151
|
-
validBefore: string;
|
|
152
|
-
signature: `0x${string}`;
|
|
153
|
-
accepted: PaymentRequirementsV2;
|
|
154
|
-
resource?: {
|
|
155
|
-
url: string;
|
|
156
|
-
description?: string;
|
|
157
|
-
mimeType?: string;
|
|
158
|
-
};
|
|
159
|
-
}) => PaymentPayloadV2;
|
|
160
|
-
/**
|
|
161
|
-
* Create payment header for request
|
|
162
|
-
*/
|
|
163
|
-
declare const createPaymentHeader: (payload: X402PaymentPayloadV1 | PaymentPayloadV2, version: X402Version) => string;
|
|
164
|
-
/**
|
|
165
|
-
* Get the payment header name for a version
|
|
166
|
-
*/
|
|
167
|
-
declare const getPaymentHeader: (version: X402Version) => string;
|
|
168
|
-
/**
|
|
169
|
-
* Get the payment required header name for a version
|
|
170
|
-
*/
|
|
171
|
-
declare const getPaymentRequiredHeader: (version: X402Version) => string;
|
|
172
|
-
/**
|
|
173
|
-
* Check if response indicates payment is required
|
|
174
|
-
*/
|
|
175
|
-
declare const isPaymentRequiredResponse: (response: Response) => boolean;
|
|
176
|
-
/**
|
|
177
|
-
* Extract requirements for a specific scheme from accepts array
|
|
178
|
-
* Uses type assertion to handle union types
|
|
179
|
-
*/
|
|
180
|
-
declare const selectSchemeRequirements: (requirements: PaymentRequirementsV1[] | PaymentRequirementsV2[], scheme?: string) => PaymentRequirementsV1 | PaymentRequirementsV2 | undefined;
|
|
181
76
|
|
|
182
|
-
declare const EIP712_TYPES: {
|
|
183
|
-
readonly EIP712Domain: readonly [{
|
|
184
|
-
readonly name: "name";
|
|
185
|
-
readonly type: "string";
|
|
186
|
-
}, {
|
|
187
|
-
readonly name: "version";
|
|
188
|
-
readonly type: "string";
|
|
189
|
-
}, {
|
|
190
|
-
readonly name: "chainId";
|
|
191
|
-
readonly type: "uint256";
|
|
192
|
-
}, {
|
|
193
|
-
readonly name: "verifyingContract";
|
|
194
|
-
readonly type: "address";
|
|
195
|
-
}];
|
|
196
|
-
readonly TransferWithAuthorization: readonly [{
|
|
197
|
-
readonly name: "from";
|
|
198
|
-
readonly type: "address";
|
|
199
|
-
}, {
|
|
200
|
-
readonly name: "to";
|
|
201
|
-
readonly type: "address";
|
|
202
|
-
}, {
|
|
203
|
-
readonly name: "value";
|
|
204
|
-
readonly type: "uint256";
|
|
205
|
-
}, {
|
|
206
|
-
readonly name: "validAfter";
|
|
207
|
-
readonly type: "uint256";
|
|
208
|
-
}, {
|
|
209
|
-
readonly name: "validBefore";
|
|
210
|
-
readonly type: "uint256";
|
|
211
|
-
}, {
|
|
212
|
-
readonly name: "nonce";
|
|
213
|
-
readonly type: "uint256";
|
|
214
|
-
}];
|
|
215
|
-
};
|
|
216
|
-
declare const USDC_DOMAIN: {
|
|
217
|
-
readonly NAME: "USD Coin";
|
|
218
|
-
readonly VERSION: "2";
|
|
219
|
-
};
|
|
220
77
|
declare const createEIP712Domain: (chainId: number | string, contractAddress: string, domainName?: string, domainVersion?: string) => Web3EIP712Domain;
|
|
221
78
|
declare const createTransferWithAuthorization: (params: Web3TransferWithAuthorization) => Record<string, string>;
|
|
222
79
|
declare const validateTransferWithAuthorization: (message: Web3TransferWithAuthorization) => boolean;
|
|
@@ -238,4 +95,4 @@ declare const signWithPrivateKey: (_privateKey: string, _domain: Web3EIP712Domai
|
|
|
238
95
|
s: string;
|
|
239
96
|
}>;
|
|
240
97
|
|
|
241
|
-
export {
|
|
98
|
+
export { adjustVForChainId, concatenateSignature, createEIP712Domain, createTransferWithAuthorization, createX402Client, createX402Transport, parseSignature, signTypedData, signWithPrivateKey, validateTransferWithAuthorization };
|
package/dist/index.js
CHANGED
|
@@ -2,30 +2,13 @@
|
|
|
2
2
|
import { Web3 } from "web3";
|
|
3
3
|
import {
|
|
4
4
|
getNetworkConfig,
|
|
5
|
-
encodePaymentV1,
|
|
6
5
|
encodePaymentV2,
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
networkToCaip2,
|
|
7
|
+
combineSignatureV2,
|
|
8
|
+
V2_HEADERS as V2_HEADERS2
|
|
10
9
|
} from "@armory-sh/base";
|
|
11
10
|
|
|
12
11
|
// src/eip3009.ts
|
|
13
|
-
var EIP712_TYPES = {
|
|
14
|
-
EIP712Domain: [
|
|
15
|
-
{ name: "name", type: "string" },
|
|
16
|
-
{ name: "version", type: "string" },
|
|
17
|
-
{ name: "chainId", type: "uint256" },
|
|
18
|
-
{ name: "verifyingContract", type: "address" }
|
|
19
|
-
],
|
|
20
|
-
TransferWithAuthorization: [
|
|
21
|
-
{ name: "from", type: "address" },
|
|
22
|
-
{ name: "to", type: "address" },
|
|
23
|
-
{ name: "value", type: "uint256" },
|
|
24
|
-
{ name: "validAfter", type: "uint256" },
|
|
25
|
-
{ name: "validBefore", type: "uint256" },
|
|
26
|
-
{ name: "nonce", type: "uint256" }
|
|
27
|
-
]
|
|
28
|
-
};
|
|
29
12
|
var USDC_DOMAIN = {
|
|
30
13
|
NAME: "USD Coin",
|
|
31
14
|
VERSION: "2"
|
|
@@ -123,107 +106,40 @@ var signWithPrivateKey = async (_privateKey, _domain, _message) => {
|
|
|
123
106
|
|
|
124
107
|
// src/protocol.ts
|
|
125
108
|
import {
|
|
126
|
-
V1_HEADERS,
|
|
127
109
|
V2_HEADERS,
|
|
128
|
-
|
|
129
|
-
isX402V1PaymentRequired,
|
|
130
|
-
isX402V2PaymentRequired,
|
|
131
|
-
getPaymentRequiredHeaderName,
|
|
132
|
-
getPaymentHeaderName
|
|
110
|
+
isX402V2PaymentRequired
|
|
133
111
|
} from "@armory-sh/base";
|
|
134
|
-
var detectX402Version = (
|
|
135
|
-
|
|
136
|
-
return 2;
|
|
137
|
-
}
|
|
138
|
-
if (response.headers.has(V1_HEADERS.PAYMENT_REQUIRED)) {
|
|
139
|
-
return 1;
|
|
140
|
-
}
|
|
141
|
-
if (response.headers.has("Payment-Required")) {
|
|
142
|
-
return 2;
|
|
143
|
-
}
|
|
144
|
-
return fallbackVersion;
|
|
145
|
-
};
|
|
146
|
-
var detectVersionFromObject = (obj) => {
|
|
147
|
-
if (isX402V2PaymentRequired(obj)) return 2;
|
|
148
|
-
if (isX402V1PaymentRequired(obj)) return 1;
|
|
149
|
-
return null;
|
|
150
|
-
};
|
|
151
|
-
var parsePaymentRequired = async (response, version) => {
|
|
152
|
-
const detectedVersion = version ?? detectX402Version(response);
|
|
153
|
-
const headerName = getPaymentRequiredHeaderName(detectedVersion);
|
|
154
|
-
const header = response.headers.get(headerName);
|
|
155
|
-
if (header) {
|
|
156
|
-
return parsePaymentRequiredFromHeader(header, detectedVersion);
|
|
157
|
-
}
|
|
158
|
-
const body = await response.clone().text();
|
|
159
|
-
return parsePaymentRequiredFromBody(body, detectedVersion);
|
|
112
|
+
var detectX402Version = (_response, _fallbackVersion = 2) => {
|
|
113
|
+
return 2;
|
|
160
114
|
};
|
|
161
|
-
var
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
version: 1,
|
|
166
|
-
requirements: decoded.accepts,
|
|
167
|
-
raw: decoded
|
|
168
|
-
};
|
|
115
|
+
var parsePaymentRequired = async (response, _version) => {
|
|
116
|
+
const v2Header = response.headers.get(V2_HEADERS.PAYMENT_REQUIRED);
|
|
117
|
+
if (!v2Header) {
|
|
118
|
+
throw new Error("No PAYMENT-REQUIRED header found in V2 response");
|
|
169
119
|
}
|
|
170
|
-
let parsed;
|
|
171
120
|
try {
|
|
172
|
-
parsed
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
try {
|
|
186
|
-
parsed = JSON.parse(body);
|
|
187
|
-
} catch {
|
|
188
|
-
const decoded = Buffer.from(body, "base64").toString("utf-8");
|
|
189
|
-
parsed = JSON.parse(decoded);
|
|
190
|
-
}
|
|
191
|
-
const detectedVersion = detectVersionFromObject(parsed) ?? version;
|
|
192
|
-
if (detectedVersion === 1 && isX402V1PaymentRequired(parsed)) {
|
|
121
|
+
let parsed;
|
|
122
|
+
try {
|
|
123
|
+
parsed = JSON.parse(v2Header);
|
|
124
|
+
} catch {
|
|
125
|
+
const decoded = Buffer.from(v2Header, "base64").toString("utf-8");
|
|
126
|
+
parsed = JSON.parse(decoded);
|
|
127
|
+
}
|
|
128
|
+
if (!isX402V2PaymentRequired(parsed)) {
|
|
129
|
+
throw new Error("Invalid x402 V2 payment required format");
|
|
130
|
+
}
|
|
131
|
+
if (!parsed.accepts || parsed.accepts.length === 0) {
|
|
132
|
+
throw new Error("No payment requirements found in accepts array");
|
|
133
|
+
}
|
|
193
134
|
return {
|
|
194
|
-
version:
|
|
135
|
+
version: 2,
|
|
195
136
|
requirements: parsed.accepts,
|
|
196
137
|
raw: parsed
|
|
197
138
|
};
|
|
139
|
+
} catch (error) {
|
|
140
|
+
if (error instanceof Error) throw error;
|
|
141
|
+
throw new Error(`Failed to parse V2 PAYMENT-REQUIRED header: ${error}`);
|
|
198
142
|
}
|
|
199
|
-
if (detectedVersion === 2 && isX402V2PaymentRequired(parsed)) {
|
|
200
|
-
const v2Parsed = parsed;
|
|
201
|
-
return {
|
|
202
|
-
version: 2,
|
|
203
|
-
requirements: v2Parsed.accepts,
|
|
204
|
-
raw: v2Parsed
|
|
205
|
-
};
|
|
206
|
-
}
|
|
207
|
-
throw new Error("Unable to parse payment required response");
|
|
208
|
-
};
|
|
209
|
-
var createX402V1Payment = (params) => {
|
|
210
|
-
const authorization = {
|
|
211
|
-
from: params.from,
|
|
212
|
-
to: params.to,
|
|
213
|
-
value: params.value,
|
|
214
|
-
validAfter: params.validAfter,
|
|
215
|
-
validBefore: params.validBefore,
|
|
216
|
-
nonce: params.nonce
|
|
217
|
-
};
|
|
218
|
-
return {
|
|
219
|
-
x402Version: 1,
|
|
220
|
-
scheme: "exact",
|
|
221
|
-
network: params.network,
|
|
222
|
-
payload: {
|
|
223
|
-
signature: params.signature,
|
|
224
|
-
authorization
|
|
225
|
-
}
|
|
226
|
-
};
|
|
227
143
|
};
|
|
228
144
|
var createX402V2Payment = (params) => {
|
|
229
145
|
const authorization = {
|
|
@@ -236,38 +152,22 @@ var createX402V2Payment = (params) => {
|
|
|
236
152
|
};
|
|
237
153
|
return {
|
|
238
154
|
x402Version: 2,
|
|
239
|
-
|
|
240
|
-
|
|
155
|
+
scheme: params.accepted.scheme,
|
|
156
|
+
network: params.accepted.network,
|
|
241
157
|
payload: {
|
|
242
158
|
signature: params.signature,
|
|
243
159
|
authorization
|
|
244
|
-
}
|
|
160
|
+
},
|
|
161
|
+
resource: params.resource
|
|
245
162
|
};
|
|
246
163
|
};
|
|
247
|
-
var createPaymentHeader = (payload, version) => {
|
|
248
|
-
const headerName = getPaymentHeaderName(version);
|
|
249
|
-
const encoded = Buffer.from(JSON.stringify(payload)).toString("base64");
|
|
250
|
-
return encoded;
|
|
251
|
-
};
|
|
252
|
-
var getPaymentHeader = (version) => {
|
|
253
|
-
return getPaymentHeaderName(version);
|
|
254
|
-
};
|
|
255
|
-
var getPaymentRequiredHeader = (version) => {
|
|
256
|
-
return getPaymentRequiredHeaderName(version);
|
|
257
|
-
};
|
|
258
164
|
var isPaymentRequiredResponse = (response) => {
|
|
259
165
|
if (response.status === 402) return true;
|
|
260
|
-
return response.headers.has(
|
|
261
|
-
};
|
|
262
|
-
var selectSchemeRequirements = (requirements, scheme = "exact") => {
|
|
263
|
-
return requirements.find(
|
|
264
|
-
(r) => "scheme" in r && r.scheme === scheme
|
|
265
|
-
);
|
|
166
|
+
return response.headers.has(V2_HEADERS.PAYMENT_REQUIRED);
|
|
266
167
|
};
|
|
267
168
|
|
|
268
169
|
// src/client.ts
|
|
269
170
|
var DEFAULT_EXPIRY_SECONDS = 3600;
|
|
270
|
-
var DEFAULT_VALID_AFTER = 0;
|
|
271
171
|
var extractDomainConfig = (config) => {
|
|
272
172
|
if (config.token) {
|
|
273
173
|
return {
|
|
@@ -331,34 +231,6 @@ var signTypedDataWrapper = async (account, domain, message) => {
|
|
|
331
231
|
}
|
|
332
232
|
throw new Error("Account does not support EIP-712 signing.");
|
|
333
233
|
};
|
|
334
|
-
var signPaymentV1 = async (state, params) => {
|
|
335
|
-
const { from, to, amount, nonce, expiry, validAfter } = params;
|
|
336
|
-
const { network, domainName, domainVersion } = state;
|
|
337
|
-
const domain = createEIP712Domain(network.chainId, network.usdcAddress, domainName, domainVersion);
|
|
338
|
-
const message = createTransferWithAuthorization({
|
|
339
|
-
from,
|
|
340
|
-
to,
|
|
341
|
-
value: amount,
|
|
342
|
-
validAfter: `0x${validAfter.toString(16)}`,
|
|
343
|
-
validBefore: `0x${expiry.toString(16)}`,
|
|
344
|
-
nonce: `0x${nonce}`
|
|
345
|
-
});
|
|
346
|
-
const signature = await signTypedDataWrapper(state.account, domain, message);
|
|
347
|
-
const legacyPayload = {
|
|
348
|
-
from,
|
|
349
|
-
to,
|
|
350
|
-
amount,
|
|
351
|
-
nonce,
|
|
352
|
-
expiry,
|
|
353
|
-
v: signature.v,
|
|
354
|
-
r: signature.r,
|
|
355
|
-
s: signature.s,
|
|
356
|
-
chainId: network.chainId,
|
|
357
|
-
contractAddress: network.usdcAddress,
|
|
358
|
-
network: network.name.toLowerCase().replace(" ", "-")
|
|
359
|
-
};
|
|
360
|
-
return { v: signature.v, r: signature.r, s: signature.s, payload: legacyPayload };
|
|
361
|
-
};
|
|
362
234
|
var signPaymentV2 = async (state, params) => {
|
|
363
235
|
const { from, to, amount, nonce, expiry, accepted } = params;
|
|
364
236
|
const { network, domainName, domainVersion } = state;
|
|
@@ -375,7 +247,7 @@ var signPaymentV2 = async (state, params) => {
|
|
|
375
247
|
const combinedSig = combineSignatureV2(signature.v, signature.r, signature.s);
|
|
376
248
|
const defaultAccepted = accepted ?? {
|
|
377
249
|
scheme: "exact",
|
|
378
|
-
network: network.
|
|
250
|
+
network: networkToCaip2(network.name),
|
|
379
251
|
amount,
|
|
380
252
|
asset: network.usdcAddress,
|
|
381
253
|
payTo: to,
|
|
@@ -389,6 +261,7 @@ var signPaymentV2 = async (state, params) => {
|
|
|
389
261
|
validAfter: "0x0",
|
|
390
262
|
validBefore: `0x${expiry.toString(16)}`,
|
|
391
263
|
signature: combinedSig,
|
|
264
|
+
network: defaultAccepted.network,
|
|
392
265
|
accepted: defaultAccepted
|
|
393
266
|
});
|
|
394
267
|
return {
|
|
@@ -402,7 +275,34 @@ var signPaymentV2 = async (state, params) => {
|
|
|
402
275
|
};
|
|
403
276
|
var createX402Client = (config) => {
|
|
404
277
|
const state = createClientState(config);
|
|
278
|
+
const fetch2 = async (url, init) => {
|
|
279
|
+
let response = await fetch2(url, init);
|
|
280
|
+
if (response.status === 402) {
|
|
281
|
+
const version = detectX402Version(response, state.version);
|
|
282
|
+
const parsed = await parsePaymentRequired(response, version);
|
|
283
|
+
const selectedRequirements = parsed.requirements[0];
|
|
284
|
+
if (!selectedRequirements) {
|
|
285
|
+
throw new Error("No supported payment scheme found in requirements");
|
|
286
|
+
}
|
|
287
|
+
const from = getAddress(state.account);
|
|
288
|
+
const req = selectedRequirements;
|
|
289
|
+
const to = typeof req.payTo === "string" ? req.payTo : "0x0000000000000000000000000000000000000000";
|
|
290
|
+
const result = await signPaymentV2(state, {
|
|
291
|
+
from,
|
|
292
|
+
to,
|
|
293
|
+
amount: req.amount,
|
|
294
|
+
nonce: crypto.randomUUID(),
|
|
295
|
+
expiry: Math.floor(Date.now() / 1e3) + DEFAULT_EXPIRY_SECONDS,
|
|
296
|
+
accepted: req
|
|
297
|
+
});
|
|
298
|
+
const paymentHeaders = new Headers(init?.headers);
|
|
299
|
+
paymentHeaders.set(V2_HEADERS2.PAYMENT_SIGNATURE, encodePaymentV2(result.payload));
|
|
300
|
+
response = await fetch2(url, { ...init, headers: paymentHeaders });
|
|
301
|
+
}
|
|
302
|
+
return response;
|
|
303
|
+
};
|
|
405
304
|
return {
|
|
305
|
+
fetch: fetch2,
|
|
406
306
|
getAccount: () => state.account,
|
|
407
307
|
getNetwork: () => state.network,
|
|
408
308
|
getVersion: () => state.version,
|
|
@@ -412,116 +312,46 @@ var createX402Client = (config) => {
|
|
|
412
312
|
const amount = options.amount.toString();
|
|
413
313
|
const nonce = options.nonce ?? crypto.randomUUID();
|
|
414
314
|
const expiry = options.expiry ?? Math.floor(Date.now() / 1e3) + DEFAULT_EXPIRY_SECONDS;
|
|
415
|
-
if (state.version === 1) {
|
|
416
|
-
return signPaymentV1(state, {
|
|
417
|
-
from,
|
|
418
|
-
to,
|
|
419
|
-
amount,
|
|
420
|
-
nonce,
|
|
421
|
-
expiry,
|
|
422
|
-
validAfter: options.validAfter ?? DEFAULT_VALID_AFTER
|
|
423
|
-
});
|
|
424
|
-
}
|
|
425
315
|
return signPaymentV2(state, { from, to, amount, nonce, expiry });
|
|
426
316
|
},
|
|
427
317
|
createPaymentHeaders: async (options) => {
|
|
428
|
-
const
|
|
318
|
+
const from = getAddress(state.account);
|
|
319
|
+
const to = options.to;
|
|
320
|
+
const amount = options.amount.toString();
|
|
321
|
+
const nonce = options.nonce ?? crypto.randomUUID();
|
|
322
|
+
const expiry = options.expiry ?? Math.floor(Date.now() / 1e3) + DEFAULT_EXPIRY_SECONDS;
|
|
323
|
+
const result = await signPaymentV2(state, { from, to, amount, nonce, expiry });
|
|
429
324
|
const headers = new Headers();
|
|
430
|
-
|
|
431
|
-
headers.set("X-PAYMENT", encodePaymentV1(result.payload));
|
|
432
|
-
} else {
|
|
433
|
-
headers.set("PAYMENT-SIGNATURE", encodePaymentV2(result.payload));
|
|
434
|
-
}
|
|
325
|
+
headers.set("PAYMENT-SIGNATURE", encodePaymentV2(result.payload));
|
|
435
326
|
return headers;
|
|
436
327
|
},
|
|
437
328
|
handlePaymentRequired: async (requirements) => {
|
|
438
|
-
const version = detectVersionFromRequirements(requirements);
|
|
439
|
-
if (version === 1) {
|
|
440
|
-
const req2 = requirements;
|
|
441
|
-
if (isX402V1Requirements(req2)) {
|
|
442
|
-
const x402Req = req2;
|
|
443
|
-
return signPayment({
|
|
444
|
-
amount: x402Req.maxAmountRequired,
|
|
445
|
-
to: x402Req.payTo
|
|
446
|
-
}, state);
|
|
447
|
-
}
|
|
448
|
-
const legacyReq = req2;
|
|
449
|
-
return signPayment({
|
|
450
|
-
amount: legacyReq.amount,
|
|
451
|
-
to: legacyReq.payTo,
|
|
452
|
-
expiry: legacyReq.expiry
|
|
453
|
-
}, state);
|
|
454
|
-
}
|
|
455
|
-
const req = requirements;
|
|
456
|
-
const to = typeof req.payTo === "string" ? req.payTo : "0x0000000000000000000000000000000000000000";
|
|
457
329
|
const from = getAddress(state.account);
|
|
330
|
+
const to = typeof requirements.payTo === "string" ? requirements.payTo : "0x0000000000000000000000000000000000000000";
|
|
458
331
|
return signPaymentV2(state, {
|
|
459
332
|
from,
|
|
460
333
|
to,
|
|
461
|
-
amount:
|
|
334
|
+
amount: requirements.amount,
|
|
462
335
|
nonce: crypto.randomUUID(),
|
|
463
336
|
expiry: Math.floor(Date.now() / 1e3) + DEFAULT_EXPIRY_SECONDS,
|
|
464
|
-
accepted:
|
|
337
|
+
accepted: requirements
|
|
465
338
|
});
|
|
466
339
|
},
|
|
467
340
|
verifySettlement: (response) => {
|
|
468
|
-
|
|
469
|
-
return response.success;
|
|
470
|
-
}
|
|
471
|
-
return false;
|
|
341
|
+
return response.success === true;
|
|
472
342
|
}
|
|
473
343
|
};
|
|
474
344
|
};
|
|
475
|
-
var detectVersionFromRequirements = (requirements) => {
|
|
476
|
-
if (isX402V2Requirements(requirements)) {
|
|
477
|
-
return 2;
|
|
478
|
-
}
|
|
479
|
-
if (isX402V1Requirements(requirements)) {
|
|
480
|
-
return 1;
|
|
481
|
-
}
|
|
482
|
-
if ("contractAddress" in requirements) {
|
|
483
|
-
return 1;
|
|
484
|
-
}
|
|
485
|
-
return 2;
|
|
486
|
-
};
|
|
487
|
-
var signPayment = async (options, state) => {
|
|
488
|
-
const from = getAddress(state.account);
|
|
489
|
-
if (state.version === 1) {
|
|
490
|
-
return signPaymentV1(state, {
|
|
491
|
-
from,
|
|
492
|
-
to: options.to,
|
|
493
|
-
amount: options.amount.toString(),
|
|
494
|
-
nonce: options.nonce ?? crypto.randomUUID(),
|
|
495
|
-
expiry: options.expiry ?? Math.floor(Date.now() / 1e3) + DEFAULT_EXPIRY_SECONDS,
|
|
496
|
-
validAfter: options.validAfter ?? DEFAULT_VALID_AFTER
|
|
497
|
-
});
|
|
498
|
-
}
|
|
499
|
-
return signPaymentV2(state, {
|
|
500
|
-
from,
|
|
501
|
-
to: options.to,
|
|
502
|
-
amount: options.amount.toString(),
|
|
503
|
-
nonce: options.nonce ?? crypto.randomUUID(),
|
|
504
|
-
expiry: options.expiry ?? Math.floor(Date.now() / 1e3) + DEFAULT_EXPIRY_SECONDS
|
|
505
|
-
});
|
|
506
|
-
};
|
|
507
345
|
|
|
508
346
|
// src/transport.ts
|
|
509
347
|
import {
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
encodePaymentV1 as encodePaymentV12,
|
|
513
|
-
encodePaymentV2 as encodePaymentV22,
|
|
514
|
-
isX402V1Requirements as isX402V1Requirements2,
|
|
515
|
-
isX402V2Requirements as isX402V2Requirements2
|
|
348
|
+
V2_HEADERS as V2_HEADERS3,
|
|
349
|
+
encodePaymentV2 as encodePaymentV22
|
|
516
350
|
} from "@armory-sh/base";
|
|
517
351
|
var DEFAULT_MAX_RETRIES = 3;
|
|
518
|
-
var createPaymentHeaders = (payload,
|
|
352
|
+
var createPaymentHeaders = (payload, _version) => {
|
|
519
353
|
const headers = new Headers();
|
|
520
|
-
|
|
521
|
-
headers.set(V1_HEADERS2.PAYMENT, encodePaymentV12(payload));
|
|
522
|
-
} else {
|
|
523
|
-
headers.set(V2_HEADERS2.PAYMENT_SIGNATURE, encodePaymentV22(payload));
|
|
524
|
-
}
|
|
354
|
+
headers.set(V2_HEADERS3.PAYMENT_SIGNATURE, encodePaymentV22(payload));
|
|
525
355
|
return headers;
|
|
526
356
|
};
|
|
527
357
|
var isPaymentRelatedError = (error) => error.message.includes("402") || error.message.includes("payment") || error.message.includes("signature") || error.message.includes("Payment");
|
|
@@ -533,20 +363,12 @@ var backoff = (attempt) => {
|
|
|
533
363
|
var handlePaymentRequired = async (response, client) => {
|
|
534
364
|
const version = detectX402Version(response, client.getVersion());
|
|
535
365
|
const parsed = await parsePaymentRequired(response, version);
|
|
536
|
-
const selectedRequirements =
|
|
366
|
+
const selectedRequirements = parsed.requirements[0];
|
|
537
367
|
if (!selectedRequirements) {
|
|
538
368
|
throw new Error("No supported payment scheme found in requirements");
|
|
539
369
|
}
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
const req = selectedRequirements;
|
|
543
|
-
result = await client.handlePaymentRequired(req);
|
|
544
|
-
} else if (version === 2 && isX402V2Requirements2(selectedRequirements)) {
|
|
545
|
-
const req = selectedRequirements;
|
|
546
|
-
result = await client.handlePaymentRequired(req);
|
|
547
|
-
} else {
|
|
548
|
-
result = await client.handlePaymentRequired(selectedRequirements);
|
|
549
|
-
}
|
|
370
|
+
const req = selectedRequirements;
|
|
371
|
+
const result = await client.handlePaymentRequired(req);
|
|
550
372
|
return createPaymentHeaders(result.payload, version);
|
|
551
373
|
};
|
|
552
374
|
var mergePaymentHeaders = (init = {}, paymentHeaders) => {
|
|
@@ -589,123 +411,15 @@ var createX402Transport = (options) => {
|
|
|
589
411
|
}
|
|
590
412
|
};
|
|
591
413
|
};
|
|
592
|
-
var createFetchWithX402 = (transport) => (url, init) => transport.fetch(url, init);
|
|
593
|
-
|
|
594
|
-
// src/types.ts
|
|
595
|
-
var isV1Requirements = (requirements) => "contractAddress" in requirements;
|
|
596
|
-
var isV2Requirements = (requirements) => "chainId" in requirements && "assetId" in requirements;
|
|
597
|
-
var isV1Settlement = (response) => "success" in response;
|
|
598
|
-
var isV2Settlement = (response) => "status" in response;
|
|
599
|
-
|
|
600
|
-
// src/index.ts
|
|
601
|
-
import {
|
|
602
|
-
V1_HEADERS as V1_HEADERS3,
|
|
603
|
-
V2_HEADERS as V2_HEADERS3,
|
|
604
|
-
encodePaymentV1 as encodePaymentV13,
|
|
605
|
-
decodePaymentV1,
|
|
606
|
-
encodeSettlementV1,
|
|
607
|
-
decodeSettlementV1,
|
|
608
|
-
encodePaymentV2 as encodePaymentV23,
|
|
609
|
-
decodePaymentV2,
|
|
610
|
-
encodeSettlementV2,
|
|
611
|
-
decodeSettlementV2,
|
|
612
|
-
isV1,
|
|
613
|
-
isV2,
|
|
614
|
-
getPaymentVersion,
|
|
615
|
-
getRequirementsVersion,
|
|
616
|
-
getSettlementVersion,
|
|
617
|
-
getPaymentHeaderName as getPaymentHeaderName2,
|
|
618
|
-
getPaymentResponseHeaderName,
|
|
619
|
-
getPaymentRequiredHeaderName as getPaymentRequiredHeaderName2,
|
|
620
|
-
isSettlementSuccessful,
|
|
621
|
-
getTxHash,
|
|
622
|
-
NETWORKS,
|
|
623
|
-
getNetworkConfig as getNetworkConfig2,
|
|
624
|
-
getNetworkByChainId,
|
|
625
|
-
getMainnets,
|
|
626
|
-
getTestnets,
|
|
627
|
-
isX402V1Payload,
|
|
628
|
-
isX402V2Payload,
|
|
629
|
-
isX402V1Requirements as isX402V1Requirements3,
|
|
630
|
-
isX402V2Requirements as isX402V2Requirements3,
|
|
631
|
-
isX402V1Settlement,
|
|
632
|
-
isX402V2Settlement,
|
|
633
|
-
combineSignatureV2 as combineSignatureV22,
|
|
634
|
-
parseSignatureV2,
|
|
635
|
-
createNonce as createNonce2,
|
|
636
|
-
EIP712_TYPES as EIP712_TYPES2,
|
|
637
|
-
USDC_DOMAIN as USDC_DOMAIN2,
|
|
638
|
-
createEIP712Domain as createEIP712Domain2,
|
|
639
|
-
createTransferWithAuthorization as createTransferWithAuthorization2,
|
|
640
|
-
validateTransferWithAuthorization as validateTransferWithAuthorization2
|
|
641
|
-
} from "@armory-sh/base";
|
|
642
414
|
export {
|
|
643
|
-
EIP712_TYPES2 as CORE_EIP712_TYPES,
|
|
644
|
-
USDC_DOMAIN2 as CORE_USDC_DOMAIN,
|
|
645
|
-
EIP712_TYPES,
|
|
646
|
-
NETWORKS,
|
|
647
|
-
USDC_DOMAIN,
|
|
648
|
-
V1_HEADERS3 as V1_HEADERS,
|
|
649
|
-
V2_HEADERS3 as V2_HEADERS,
|
|
650
415
|
adjustVForChainId,
|
|
651
|
-
combineSignatureV22 as combineSignatureV2,
|
|
652
416
|
concatenateSignature,
|
|
653
|
-
createEIP712Domain2 as createCoreEIP712Domain,
|
|
654
|
-
createTransferWithAuthorization2 as createCoreTransferWithAuthorization,
|
|
655
417
|
createEIP712Domain,
|
|
656
|
-
createFetchWithX402,
|
|
657
|
-
createNonce2 as createNonce,
|
|
658
|
-
createPaymentHeader,
|
|
659
418
|
createTransferWithAuthorization,
|
|
660
419
|
createX402Client,
|
|
661
420
|
createX402Transport,
|
|
662
|
-
createX402V1Payment,
|
|
663
|
-
createX402V2Payment,
|
|
664
|
-
decodePaymentV1,
|
|
665
|
-
decodePaymentV2,
|
|
666
|
-
decodeSettlementV1,
|
|
667
|
-
decodeSettlementV2,
|
|
668
|
-
detectVersionFromObject,
|
|
669
|
-
detectX402Version,
|
|
670
|
-
encodePaymentV13 as encodePaymentV1,
|
|
671
|
-
encodePaymentV23 as encodePaymentV2,
|
|
672
|
-
encodeSettlementV1,
|
|
673
|
-
encodeSettlementV2,
|
|
674
|
-
getMainnets,
|
|
675
|
-
getNetworkByChainId,
|
|
676
|
-
getNetworkConfig2 as getNetworkConfig,
|
|
677
|
-
getPaymentHeader,
|
|
678
|
-
getPaymentHeaderName2 as getPaymentHeaderName,
|
|
679
|
-
getPaymentRequiredHeader,
|
|
680
|
-
getPaymentRequiredHeaderName2 as getPaymentRequiredHeaderName,
|
|
681
|
-
getPaymentResponseHeaderName,
|
|
682
|
-
getPaymentVersion,
|
|
683
|
-
getRequirementsVersion,
|
|
684
|
-
getSettlementVersion,
|
|
685
|
-
getTestnets,
|
|
686
|
-
getTxHash,
|
|
687
|
-
isPaymentRequiredResponse,
|
|
688
|
-
isSettlementSuccessful,
|
|
689
|
-
isV1,
|
|
690
|
-
isV1Requirements,
|
|
691
|
-
isV1Settlement,
|
|
692
|
-
isV2,
|
|
693
|
-
isV2Requirements,
|
|
694
|
-
isV2Settlement,
|
|
695
|
-
isX402V1Payload,
|
|
696
|
-
isX402V1Requirements3 as isX402V1Requirements,
|
|
697
|
-
isX402V1Settlement,
|
|
698
|
-
isX402V2Payload,
|
|
699
|
-
isX402V2Requirements3 as isX402V2Requirements,
|
|
700
|
-
isX402V2Settlement,
|
|
701
|
-
parsePaymentRequired,
|
|
702
|
-
parsePaymentRequiredFromBody,
|
|
703
|
-
parsePaymentRequiredFromHeader,
|
|
704
421
|
parseSignature,
|
|
705
|
-
parseSignatureV2,
|
|
706
|
-
selectSchemeRequirements,
|
|
707
422
|
signTypedData,
|
|
708
423
|
signWithPrivateKey,
|
|
709
|
-
validateTransferWithAuthorization2 as validateCoreTransferWithAuthorization,
|
|
710
424
|
validateTransferWithAuthorization
|
|
711
425
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@armory-sh/client-web3",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.11",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "Sawyer Cutler <sawyer@dirtroad.dev>",
|
|
6
6
|
"type": "module",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"directory": "packages/client-web3"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@armory-sh/base": "^0.2.
|
|
30
|
+
"@armory-sh/base": "^0.2.14",
|
|
31
31
|
"web3": "4.16.0",
|
|
32
32
|
"web3-types": "1.10.0"
|
|
33
33
|
},
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"bun-types": "latest"
|
|
37
37
|
},
|
|
38
38
|
"scripts": {
|
|
39
|
-
"build": "tsup",
|
|
39
|
+
"build": "rm -rf dist && tsup",
|
|
40
40
|
"test": "bun test",
|
|
41
41
|
"example": "bun run examples/"
|
|
42
42
|
}
|