@faremeter/payment-evm 0.7.0 → 0.8.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 +4 -1
- package/dist/src/exact/client.d.ts.map +1 -1
- package/dist/src/exact/client.js +13 -21
- 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 +75 -25
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
|
@@ -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;AAGjC,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,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,gBAAgB,GAAG,cAAc,CAkG7E"}
|
package/dist/src/exact/client.js
CHANGED
|
@@ -1,22 +1,16 @@
|
|
|
1
1
|
import { randomBytes } from "crypto";
|
|
2
|
-
import {
|
|
2
|
+
import { lookupX402Network, lookupKnownAsset } 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
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");
|
|
7
|
+
const x402Network = lookupX402Network(wallet.chain.id);
|
|
8
|
+
const assetInfo = lookupKnownAsset(wallet.chain.id, "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 KnownNetwork, type ContractInfo } from "@faremeter/info/evm";
|
|
4
|
+
type CreateFacilitatorHandlerOpts = {
|
|
5
|
+
network?: KnownNetwork;
|
|
6
|
+
transport?: Transport;
|
|
7
|
+
};
|
|
8
|
+
export declare function createFacilitatorHandler(chain: Chain, privateKey: string, assetNameOrInfo: string | ContractInfo, 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":"AAQA,OAAO,EAAE,KAAK,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAGvE,OAAO,KAAK,EAAgB,KAAK,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AAY3D,OAAO,EAIL,KAAK,YAAY,EACjB,KAAK,YAAY,EAClB,MAAM,qBAAqB,CAAC;AA8B7B,KAAK,4BAA4B,GAAG;IAClC,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB,CAAC;AACF,wBAAsB,wBAAwB,CAC5C,KAAK,EAAE,KAAK,EACZ,UAAU,EAAE,MAAM,EAClB,eAAe,EAAE,MAAM,GAAG,YAAY,EACtC,IAAI,GAAE,4BAAiC,GACtC,OAAO,CAAC,kBAAkB,CAAC,CAsT7B"}
|
|
@@ -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 { isKnownAsset, lookupKnownAsset, lookupX402Network, } 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,61 @@ 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(`
|
|
26
|
+
export async function createFacilitatorHandler(chain, privateKey, assetNameOrInfo, opts = {}) {
|
|
27
|
+
if (!isPrivateKey(privateKey)) {
|
|
28
|
+
throw new Error(`Invalid private key: ${privateKey}`);
|
|
27
29
|
}
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
30
|
+
const network = opts.network ?? lookupX402Network(chain.id);
|
|
31
|
+
const chainId = chain.id;
|
|
32
|
+
let assetInfo;
|
|
33
|
+
if (typeof assetNameOrInfo == "string") {
|
|
34
|
+
if (!isKnownAsset(assetNameOrInfo)) {
|
|
35
|
+
throw new Error(`Unknown asset: ${assetNameOrInfo}`);
|
|
36
|
+
}
|
|
37
|
+
const t = lookupKnownAsset(network, assetNameOrInfo);
|
|
38
|
+
if (!t) {
|
|
39
|
+
throw new Error(`Couldn't look up asset ${assetNameOrInfo} on ${network}`);
|
|
40
|
+
}
|
|
41
|
+
assetInfo = t;
|
|
35
42
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
throw new Error(`Couldn't look up asset ${assetName} on ${network}`);
|
|
43
|
+
else {
|
|
44
|
+
assetInfo = assetNameOrInfo;
|
|
39
45
|
}
|
|
40
46
|
const asset = assetInfo.address;
|
|
47
|
+
const useForwarder = assetInfo.forwarder !== undefined && assetInfo.forwarderName !== undefined;
|
|
41
48
|
if (!isAddress(asset)) {
|
|
42
49
|
throw new Error(`Invalid asset address: ${asset}`);
|
|
43
50
|
}
|
|
44
|
-
|
|
45
|
-
|
|
51
|
+
const transport = opts.transport ?? http(chain.rpcUrls.default.http[0]);
|
|
52
|
+
const account = privateKeyToAccount(privateKey);
|
|
53
|
+
const publicClient = createPublicClient({
|
|
54
|
+
chain,
|
|
55
|
+
transport,
|
|
56
|
+
});
|
|
57
|
+
const walletClient = createWalletClient({
|
|
58
|
+
account,
|
|
59
|
+
chain,
|
|
60
|
+
transport,
|
|
61
|
+
});
|
|
62
|
+
let domain;
|
|
63
|
+
if (useForwarder) {
|
|
64
|
+
if (!assetInfo.forwarder) {
|
|
65
|
+
throw new Error("Missing Forwarding Contract");
|
|
66
|
+
}
|
|
67
|
+
if (!assetInfo.forwarderVersion) {
|
|
68
|
+
throw new Error("Missing Forwarding Version");
|
|
69
|
+
}
|
|
70
|
+
if (!assetInfo.forwarderName) {
|
|
71
|
+
throw new Error("Missing Forwarding Name");
|
|
72
|
+
}
|
|
73
|
+
domain = generateForwarderDomain(chainId, {
|
|
74
|
+
version: assetInfo.forwarderVersion,
|
|
75
|
+
name: assetInfo.forwarderName,
|
|
76
|
+
verifyingContract: assetInfo.forwarder,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
domain = await generateDomain(publicClient, chainId, asset);
|
|
46
81
|
if (domain.name != assetInfo.contractName) {
|
|
47
82
|
throw new Error(`On chain contract name (${domain.name}) doesn't match configured asset name (${assetInfo.contractName})`);
|
|
48
83
|
}
|
|
@@ -63,10 +98,10 @@ export async function createFacilitatorHandler(network, publicClient, walletClie
|
|
|
63
98
|
maxTimeoutSeconds: 300,
|
|
64
99
|
// Provide EIP-712 domain parameters for client signing
|
|
65
100
|
extra: {
|
|
66
|
-
name: assetInfo.contractName,
|
|
67
|
-
version: "2",
|
|
101
|
+
name: useForwarder ? assetInfo.forwarderName : assetInfo.contractName,
|
|
102
|
+
version: useForwarder ? assetInfo.forwarderVersion : "2",
|
|
68
103
|
chainId,
|
|
69
|
-
verifyingContract: asset,
|
|
104
|
+
verifyingContract: useForwarder ? assetInfo.forwarder : asset,
|
|
70
105
|
},
|
|
71
106
|
}));
|
|
72
107
|
};
|
|
@@ -112,7 +147,7 @@ export async function createFacilitatorHandler(network, publicClient, walletClie
|
|
|
112
147
|
let onChainUsed;
|
|
113
148
|
try {
|
|
114
149
|
onChainUsed = await publicClient.readContract({
|
|
115
|
-
address: asset,
|
|
150
|
+
address: assetInfo.forwarder ?? asset,
|
|
116
151
|
abi: TRANSFER_WITH_AUTHORIZATION_ABI,
|
|
117
152
|
functionName: "authorizationState",
|
|
118
153
|
args: [authorization.from, authorization.nonce],
|
|
@@ -124,7 +159,22 @@ export async function createFacilitatorHandler(network, publicClient, walletClie
|
|
|
124
159
|
if (onChainUsed) {
|
|
125
160
|
return errorResponse("Authorization already used on-chain");
|
|
126
161
|
}
|
|
127
|
-
|
|
162
|
+
let domain;
|
|
163
|
+
if (useForwarder) {
|
|
164
|
+
if (!assetInfo.forwarderVersion ||
|
|
165
|
+
!assetInfo.forwarderName ||
|
|
166
|
+
!assetInfo.forwarder) {
|
|
167
|
+
throw new Error("Secondary Forwardign Information Missing");
|
|
168
|
+
}
|
|
169
|
+
domain = generateForwarderDomain(chainId, {
|
|
170
|
+
version: assetInfo.forwarderVersion,
|
|
171
|
+
name: assetInfo.forwarderName,
|
|
172
|
+
verifyingContract: assetInfo.forwarder,
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
domain = await generateDomain(publicClient, chainId, asset);
|
|
177
|
+
}
|
|
128
178
|
const types = EIP712_TYPES;
|
|
129
179
|
const message = {
|
|
130
180
|
from: authorization.from,
|
|
@@ -155,7 +205,7 @@ export async function createFacilitatorHandler(network, publicClient, walletClie
|
|
|
155
205
|
// Verify contract supports EIP-712
|
|
156
206
|
try {
|
|
157
207
|
await publicClient.readContract({
|
|
158
|
-
address: asset,
|
|
208
|
+
address: useForwarder ? domain.verifyingContract : asset,
|
|
159
209
|
abi: TRANSFER_WITH_AUTHORIZATION_ABI,
|
|
160
210
|
functionName: "DOMAIN_SEPARATOR",
|
|
161
211
|
});
|
|
@@ -186,7 +236,7 @@ export async function createFacilitatorHandler(network, publicClient, walletClie
|
|
|
186
236
|
// Build and send the transaction
|
|
187
237
|
try {
|
|
188
238
|
const request = await walletClient.prepareTransactionRequest({
|
|
189
|
-
to: asset,
|
|
239
|
+
to: useForwarder ? domain.verifyingContract : asset,
|
|
190
240
|
data,
|
|
191
241
|
account: acct,
|
|
192
242
|
chain: undefined,
|