@faremeter/payment-evm 0.7.0 → 0.9.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/src/exact/client.d.ts +9 -2
- package/dist/src/exact/client.d.ts.map +1 -1
- package/dist/src/exact/client.js +14 -22
- package/dist/src/exact/common.d.ts +10 -0
- package/dist/src/exact/common.d.ts.map +1 -1
- package/dist/src/exact/common.js +6 -0
- package/dist/src/exact/facilitator.d.ts +8 -2
- package/dist/src/exact/facilitator.d.ts.map +1 -1
- package/dist/src/exact/facilitator.js +74 -27
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import type { PaymentHandler } from "@faremeter/types/client";
|
|
2
|
+
import { type AssetNameOrContractInfo } from "@faremeter/info/evm";
|
|
2
3
|
import type { Hex } from "viem";
|
|
3
4
|
interface WalletForPayment {
|
|
4
|
-
|
|
5
|
+
chain: {
|
|
6
|
+
id: number;
|
|
7
|
+
name: string;
|
|
8
|
+
};
|
|
5
9
|
address: Hex;
|
|
6
10
|
account: {
|
|
7
11
|
signTypedData: (params: {
|
|
@@ -12,6 +16,9 @@ interface WalletForPayment {
|
|
|
12
16
|
}) => Promise<Hex>;
|
|
13
17
|
};
|
|
14
18
|
}
|
|
15
|
-
export
|
|
19
|
+
export type CreatePaymentHandlerOpts = {
|
|
20
|
+
asset?: AssetNameOrContractInfo;
|
|
21
|
+
};
|
|
22
|
+
export declare function createPaymentHandler(wallet: WalletForPayment, opts?: CreatePaymentHandlerOpts): PaymentHandler;
|
|
16
23
|
export {};
|
|
17
24
|
//# sourceMappingURL=client.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/exact/client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,cAAc,EAGf,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/exact/client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,cAAc,EAGf,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAGL,KAAK,uBAAuB,EAC7B,MAAM,qBAAqB,CAAC;AAE7B,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,MAAM,CAAC;AAWhC,UAAU,gBAAgB;IACxB,KAAK,EAAE;QACL,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IACF,OAAO,EAAE,GAAG,CAAC;IACb,OAAO,EAAE;QACP,aAAa,EAAE,CAAC,MAAM,EAAE;YACtB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;YAChC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;YAC/B,WAAW,EAAE,MAAM,CAAC;YACpB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;SAClC,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;KACpB,CAAC;CACH;AAED,MAAM,MAAM,wBAAwB,GAAG;IACrC,KAAK,CAAC,EAAE,uBAAuB,CAAC;CACjC,CAAC;AAEF,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,gBAAgB,EACxB,IAAI,GAAE,wBAA6B,GAClC,cAAc,CAkGhB"}
|
package/dist/src/exact/client.js
CHANGED
|
@@ -1,22 +1,16 @@
|
|
|
1
1
|
import { randomBytes } from "crypto";
|
|
2
|
-
import {
|
|
2
|
+
import { lookupX402Network, findAssetInfo, } from "@faremeter/info/evm";
|
|
3
3
|
import { isAddress } from "viem";
|
|
4
4
|
import { type } from "arktype";
|
|
5
5
|
import { X402_EXACT_SCHEME, EIP712_TYPES, eip712Domain, } from "./constants.js";
|
|
6
|
-
export function createPaymentHandler(wallet) {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
}
|
|
10
|
-
const networkInfo = lookupKnownNetwork(wallet.network);
|
|
11
|
-
if (!networkInfo) {
|
|
12
|
-
throw new Error(`Couldn't look up network info for network '${wallet.network}'`);
|
|
13
|
-
}
|
|
14
|
-
const assetInfo = lookupKnownAsset(wallet.network, "USDC");
|
|
6
|
+
export function createPaymentHandler(wallet, opts = {}) {
|
|
7
|
+
const x402Network = lookupX402Network(wallet.chain.id);
|
|
8
|
+
const assetInfo = findAssetInfo(x402Network, opts.asset ?? "USDC");
|
|
15
9
|
if (!assetInfo) {
|
|
16
|
-
throw new Error(`Couldn't look up USDC information on network '${
|
|
10
|
+
throw new Error(`Couldn't look up USDC information on network '${x402Network}'`);
|
|
17
11
|
}
|
|
18
12
|
return async function handlePayment(context, accepts) {
|
|
19
|
-
const compatibleRequirements = accepts.filter((req) => req.scheme === X402_EXACT_SCHEME && req.network ===
|
|
13
|
+
const compatibleRequirements = accepts.filter((req) => req.scheme === X402_EXACT_SCHEME && req.network === x402Network);
|
|
20
14
|
return compatibleRequirements.map((requirements) => ({
|
|
21
15
|
requirements,
|
|
22
16
|
exec: async () => {
|
|
@@ -43,19 +37,17 @@ export function createPaymentHandler(wallet) {
|
|
|
43
37
|
if (extraResult instanceof type.errors) {
|
|
44
38
|
throw new Error(`Invalid EIP-712 domain parameters: ${extraResult.summary}`);
|
|
45
39
|
}
|
|
40
|
+
const verifyingContract = extraResult.verifyingContract ??
|
|
41
|
+
requirements.asset ??
|
|
42
|
+
assetInfo.address;
|
|
43
|
+
if (!isAddress(verifyingContract)) {
|
|
44
|
+
throw new Error(`Invalid verifying contract: ${verifyingContract}`);
|
|
45
|
+
}
|
|
46
46
|
const domain = {
|
|
47
47
|
name: extraResult.name ?? assetInfo.contractName,
|
|
48
48
|
version: extraResult.version ?? "2",
|
|
49
|
-
chainId: extraResult.chainId ??
|
|
50
|
-
verifyingContract
|
|
51
|
-
const asset = extraResult.verifyingContract ??
|
|
52
|
-
requirements.asset ??
|
|
53
|
-
assetInfo.address;
|
|
54
|
-
if (!isAddress(asset)) {
|
|
55
|
-
throw new Error(`Invalid asset address: ${asset}`);
|
|
56
|
-
}
|
|
57
|
-
return asset;
|
|
58
|
-
})(),
|
|
49
|
+
chainId: extraResult.chainId ?? wallet.chain.id,
|
|
50
|
+
verifyingContract,
|
|
59
51
|
};
|
|
60
52
|
const types = EIP712_TYPES;
|
|
61
53
|
// Message for EIP-712 signing (using BigInt for signing)
|
|
@@ -5,4 +5,14 @@ export declare function generateDomain(publicClient: PublicClient, chainId: numb
|
|
|
5
5
|
chainId: number;
|
|
6
6
|
verifyingContract: `0x${string}`;
|
|
7
7
|
}>;
|
|
8
|
+
export declare function generateForwarderDomain(chainId: number, domainInfo: {
|
|
9
|
+
version: string;
|
|
10
|
+
name: string;
|
|
11
|
+
verifyingContract: `0x${string}`;
|
|
12
|
+
}): {
|
|
13
|
+
chainId: number;
|
|
14
|
+
version: string;
|
|
15
|
+
name: string;
|
|
16
|
+
verifyingContract: `0x${string}`;
|
|
17
|
+
};
|
|
8
18
|
//# sourceMappingURL=common.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../../src/exact/common.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,MAAM,CAAC;AAI9C,wBAAsB,cAAc,CAClC,YAAY,EAAE,YAAY,EAC1B,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,GAAG;;;;;GA8BX"}
|
|
1
|
+
{"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../../src/exact/common.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,MAAM,CAAC;AAI9C,wBAAsB,cAAc,CAClC,YAAY,EAAE,YAAY,EAC1B,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,GAAG;;;;;GA8BX;AAED,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,MAAM,EACf,UAAU,EAAE;IACV,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,iBAAiB,EAAE,KAAK,MAAM,EAAE,CAAC;CAClC;;aAHU,MAAM;UACT,MAAM;uBACO,KAAK,MAAM,EAAE;EAOnC"}
|
package/dist/src/exact/common.js
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import { type FacilitatorHandler } from "@faremeter/types/facilitator";
|
|
2
|
-
import type {
|
|
3
|
-
|
|
2
|
+
import type { Chain, Transport } from "viem";
|
|
3
|
+
import { type KnownX402Network, type AssetNameOrContractInfo } from "@faremeter/info/evm";
|
|
4
|
+
type CreateFacilitatorHandlerOpts = {
|
|
5
|
+
network?: KnownX402Network;
|
|
6
|
+
transport?: Transport;
|
|
7
|
+
};
|
|
8
|
+
export declare function createFacilitatorHandler(chain: Chain, privateKey: string, assetNameOrInfo: AssetNameOrContractInfo, opts?: CreateFacilitatorHandlerOpts): Promise<FacilitatorHandler>;
|
|
9
|
+
export {};
|
|
4
10
|
//# sourceMappingURL=facilitator.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"facilitator.d.ts","sourceRoot":"","sources":["../../../src/exact/facilitator.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"facilitator.d.ts","sourceRoot":"","sources":["../../../src/exact/facilitator.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,KAAK,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAGvE,OAAO,KAAK,EAAgB,KAAK,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AAY3D,OAAO,EAEL,KAAK,gBAAgB,EAErB,KAAK,uBAAuB,EAC7B,MAAM,qBAAqB,CAAC;AA8B7B,KAAK,4BAA4B,GAAG;IAClC,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAC3B,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB,CAAC;AACF,wBAAsB,wBAAwB,CAC5C,KAAK,EAAE,KAAK,EACZ,UAAU,EAAE,MAAM,EAClB,eAAe,EAAE,uBAAuB,EACxC,IAAI,GAAE,4BAAiC,GACtC,OAAO,CAAC,kBAAkB,CAAC,CA+S7B"}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { isValidationError, caseInsensitiveLiteral } from "@faremeter/types";
|
|
2
|
+
import { isPrivateKey } from "@faremeter/types/evm";
|
|
2
3
|
import {} from "@faremeter/types/facilitator";
|
|
3
4
|
import { type } from "arktype";
|
|
4
|
-
import { verifyTypedData, encodeFunctionData, isAddress } from "viem";
|
|
5
|
-
import {
|
|
5
|
+
import { createPublicClient, createWalletClient, http, verifyTypedData, encodeFunctionData, isAddress, } from "viem";
|
|
6
|
+
import { privateKeyToAccount } from "viem/accounts";
|
|
7
|
+
import { lookupX402Network, findAssetInfo, } from "@faremeter/info/evm";
|
|
6
8
|
import { X402_EXACT_SCHEME, TRANSFER_WITH_AUTHORIZATION_ABI, EIP712_TYPES, x402ExactPayload, } from "./constants.js";
|
|
7
|
-
import { generateDomain } from "./common.js";
|
|
9
|
+
import { generateDomain, generateForwarderDomain } from "./common.js";
|
|
8
10
|
function errorResponse(msg) {
|
|
9
11
|
return {
|
|
10
12
|
success: false,
|
|
@@ -21,28 +23,48 @@ function parseSignature(signature) {
|
|
|
21
23
|
const v = parseInt(sig.slice(128, 130), 16);
|
|
22
24
|
return { v, r, s };
|
|
23
25
|
}
|
|
24
|
-
export async function createFacilitatorHandler(
|
|
25
|
-
if (!
|
|
26
|
-
throw new Error(`
|
|
27
|
-
}
|
|
28
|
-
const networkInfo = lookupKnownNetwork(network);
|
|
29
|
-
if (!networkInfo) {
|
|
30
|
-
throw new Error(`Couldn't look up information for ${network}`);
|
|
31
|
-
}
|
|
32
|
-
const { chainId } = networkInfo;
|
|
33
|
-
if (!isKnownAsset(assetName)) {
|
|
34
|
-
throw new Error(`Unknown asset: ${assetName}`);
|
|
35
|
-
}
|
|
36
|
-
const assetInfo = lookupKnownAsset(network, assetName);
|
|
37
|
-
if (!assetInfo) {
|
|
38
|
-
throw new Error(`Couldn't look up asset ${assetName} on ${network}`);
|
|
26
|
+
export async function createFacilitatorHandler(chain, privateKey, assetNameOrInfo, opts = {}) {
|
|
27
|
+
if (!isPrivateKey(privateKey)) {
|
|
28
|
+
throw new Error(`Invalid private key: ${privateKey}`);
|
|
39
29
|
}
|
|
30
|
+
const network = opts.network ?? lookupX402Network(chain.id);
|
|
31
|
+
const chainId = chain.id;
|
|
32
|
+
const assetInfo = findAssetInfo(network, assetNameOrInfo);
|
|
40
33
|
const asset = assetInfo.address;
|
|
34
|
+
const useForwarder = assetInfo.forwarder !== undefined && assetInfo.forwarderName !== undefined;
|
|
41
35
|
if (!isAddress(asset)) {
|
|
42
36
|
throw new Error(`Invalid asset address: ${asset}`);
|
|
43
37
|
}
|
|
44
|
-
|
|
45
|
-
|
|
38
|
+
const transport = opts.transport ?? http(chain.rpcUrls.default.http[0]);
|
|
39
|
+
const account = privateKeyToAccount(privateKey);
|
|
40
|
+
const publicClient = createPublicClient({
|
|
41
|
+
chain,
|
|
42
|
+
transport,
|
|
43
|
+
});
|
|
44
|
+
const walletClient = createWalletClient({
|
|
45
|
+
account,
|
|
46
|
+
chain,
|
|
47
|
+
transport,
|
|
48
|
+
});
|
|
49
|
+
let domain;
|
|
50
|
+
if (useForwarder) {
|
|
51
|
+
if (!assetInfo.forwarder) {
|
|
52
|
+
throw new Error("Missing Forwarding Contract");
|
|
53
|
+
}
|
|
54
|
+
if (!assetInfo.forwarderVersion) {
|
|
55
|
+
throw new Error("Missing Forwarding Version");
|
|
56
|
+
}
|
|
57
|
+
if (!assetInfo.forwarderName) {
|
|
58
|
+
throw new Error("Missing Forwarding Name");
|
|
59
|
+
}
|
|
60
|
+
domain = generateForwarderDomain(chainId, {
|
|
61
|
+
version: assetInfo.forwarderVersion,
|
|
62
|
+
name: assetInfo.forwarderName,
|
|
63
|
+
verifyingContract: assetInfo.forwarder,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
domain = await generateDomain(publicClient, chainId, asset);
|
|
46
68
|
if (domain.name != assetInfo.contractName) {
|
|
47
69
|
throw new Error(`On chain contract name (${domain.name}) doesn't match configured asset name (${assetInfo.contractName})`);
|
|
48
70
|
}
|
|
@@ -54,6 +76,15 @@ export async function createFacilitatorHandler(network, publicClient, walletClie
|
|
|
54
76
|
const checkTupleAndAsset = checkTuple.and({
|
|
55
77
|
asset: caseInsensitiveLiteral(asset),
|
|
56
78
|
});
|
|
79
|
+
const getSupported = () => {
|
|
80
|
+
return [
|
|
81
|
+
Promise.resolve({
|
|
82
|
+
x402Version: 1,
|
|
83
|
+
network,
|
|
84
|
+
scheme: X402_EXACT_SCHEME,
|
|
85
|
+
}),
|
|
86
|
+
];
|
|
87
|
+
};
|
|
57
88
|
const getRequirements = async (req) => {
|
|
58
89
|
return req
|
|
59
90
|
.filter((x) => !isValidationError(checkTupleAndAsset(x)))
|
|
@@ -63,10 +94,10 @@ export async function createFacilitatorHandler(network, publicClient, walletClie
|
|
|
63
94
|
maxTimeoutSeconds: 300,
|
|
64
95
|
// Provide EIP-712 domain parameters for client signing
|
|
65
96
|
extra: {
|
|
66
|
-
name: assetInfo.contractName,
|
|
67
|
-
version: "2",
|
|
97
|
+
name: useForwarder ? assetInfo.forwarderName : assetInfo.contractName,
|
|
98
|
+
version: useForwarder ? assetInfo.forwarderVersion : "2",
|
|
68
99
|
chainId,
|
|
69
|
-
verifyingContract: asset,
|
|
100
|
+
verifyingContract: useForwarder ? assetInfo.forwarder : asset,
|
|
70
101
|
},
|
|
71
102
|
}));
|
|
72
103
|
};
|
|
@@ -112,7 +143,7 @@ export async function createFacilitatorHandler(network, publicClient, walletClie
|
|
|
112
143
|
let onChainUsed;
|
|
113
144
|
try {
|
|
114
145
|
onChainUsed = await publicClient.readContract({
|
|
115
|
-
address: asset,
|
|
146
|
+
address: assetInfo.forwarder ?? asset,
|
|
116
147
|
abi: TRANSFER_WITH_AUTHORIZATION_ABI,
|
|
117
148
|
functionName: "authorizationState",
|
|
118
149
|
args: [authorization.from, authorization.nonce],
|
|
@@ -124,7 +155,22 @@ export async function createFacilitatorHandler(network, publicClient, walletClie
|
|
|
124
155
|
if (onChainUsed) {
|
|
125
156
|
return errorResponse("Authorization already used on-chain");
|
|
126
157
|
}
|
|
127
|
-
|
|
158
|
+
let domain;
|
|
159
|
+
if (useForwarder) {
|
|
160
|
+
if (!assetInfo.forwarderVersion ||
|
|
161
|
+
!assetInfo.forwarderName ||
|
|
162
|
+
!assetInfo.forwarder) {
|
|
163
|
+
throw new Error("Secondary Forwardign Information Missing");
|
|
164
|
+
}
|
|
165
|
+
domain = generateForwarderDomain(chainId, {
|
|
166
|
+
version: assetInfo.forwarderVersion,
|
|
167
|
+
name: assetInfo.forwarderName,
|
|
168
|
+
verifyingContract: assetInfo.forwarder,
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
domain = await generateDomain(publicClient, chainId, asset);
|
|
173
|
+
}
|
|
128
174
|
const types = EIP712_TYPES;
|
|
129
175
|
const message = {
|
|
130
176
|
from: authorization.from,
|
|
@@ -155,7 +201,7 @@ export async function createFacilitatorHandler(network, publicClient, walletClie
|
|
|
155
201
|
// Verify contract supports EIP-712
|
|
156
202
|
try {
|
|
157
203
|
await publicClient.readContract({
|
|
158
|
-
address: asset,
|
|
204
|
+
address: useForwarder ? domain.verifyingContract : asset,
|
|
159
205
|
abi: TRANSFER_WITH_AUTHORIZATION_ABI,
|
|
160
206
|
functionName: "DOMAIN_SEPARATOR",
|
|
161
207
|
});
|
|
@@ -186,7 +232,7 @@ export async function createFacilitatorHandler(network, publicClient, walletClie
|
|
|
186
232
|
// Build and send the transaction
|
|
187
233
|
try {
|
|
188
234
|
const request = await walletClient.prepareTransactionRequest({
|
|
189
|
-
to: asset,
|
|
235
|
+
to: useForwarder ? domain.verifyingContract : asset,
|
|
190
236
|
data,
|
|
191
237
|
account: acct,
|
|
192
238
|
chain: undefined,
|
|
@@ -214,6 +260,7 @@ export async function createFacilitatorHandler(network, publicClient, walletClie
|
|
|
214
260
|
}
|
|
215
261
|
};
|
|
216
262
|
return {
|
|
263
|
+
getSupported,
|
|
217
264
|
getRequirements,
|
|
218
265
|
handleSettle,
|
|
219
266
|
};
|