@faremeter/payment-evm 0.10.3 → 0.11.1

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.
@@ -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;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"}
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;AAYhC,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,CAqGhB"}
@@ -2,15 +2,17 @@ import { randomBytes } from "crypto";
2
2
  import { lookupX402Network, findAssetInfo, } from "@faremeter/info/evm";
3
3
  import { isAddress } from "viem";
4
4
  import { type } from "arktype";
5
- import { X402_EXACT_SCHEME, EIP712_TYPES, eip712Domain, } from "./constants.js";
5
+ import { EIP712_TYPES, eip712Domain, } from "./constants.js";
6
+ import { generateMatcher } from "./common.js";
6
7
  export function createPaymentHandler(wallet, opts = {}) {
7
8
  const x402Network = lookupX402Network(wallet.chain.id);
8
9
  const assetInfo = findAssetInfo(x402Network, opts.asset ?? "USDC");
9
10
  if (!assetInfo) {
10
11
  throw new Error(`Couldn't look up USDC information on network '${x402Network}'`);
11
12
  }
13
+ const { isMatchingRequirement } = generateMatcher(x402Network, assetInfo.address);
12
14
  return async function handlePayment(context, accepts) {
13
- const compatibleRequirements = accepts.filter((req) => req.scheme === X402_EXACT_SCHEME && req.network === x402Network);
15
+ const compatibleRequirements = accepts.filter(isMatchingRequirement);
14
16
  return compatibleRequirements.map((requirements) => ({
15
17
  requirements,
16
18
  exec: async () => {
@@ -15,4 +15,16 @@ export declare function generateForwarderDomain(chainId: number, domainInfo: {
15
15
  name: string;
16
16
  verifyingContract: `0x${string}`;
17
17
  };
18
+ export declare function generateMatcher(network: string, asset: string): {
19
+ matchTuple: import("arktype/internal/methods/object.ts").ObjectType<{
20
+ scheme: (In: string) => import("arktype/internal/attributes.ts").To<Lowercase<string>>;
21
+ network: (In: string) => import("arktype/internal/attributes.ts").To<Lowercase<string>>;
22
+ asset: (In: string) => import("arktype/internal/attributes.ts").To<Lowercase<string>>;
23
+ }, {}>;
24
+ isMatchingRequirement: (req: {
25
+ scheme: string;
26
+ network: string;
27
+ asset: string;
28
+ }) => boolean;
29
+ };
18
30
  //# 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;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"}
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;AAQ9C,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;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;;;;;;;;;;;EAE7D"}
@@ -1,4 +1,5 @@
1
- import { TRANSFER_WITH_AUTHORIZATION_ABI } from "./constants.js";
1
+ import { generateRequirementsMatcher } from "@faremeter/types/x402";
2
+ import { TRANSFER_WITH_AUTHORIZATION_ABI, X402_EXACT_SCHEME, } from "./constants.js";
2
3
  export async function generateDomain(publicClient, chainId, asset) {
3
4
  // Read domain parameters from chain
4
5
  let tokenName;
@@ -34,3 +35,6 @@ export function generateForwarderDomain(chainId, domainInfo) {
34
35
  chainId,
35
36
  };
36
37
  }
38
+ export function generateMatcher(network, asset) {
39
+ return generateRequirementsMatcher([X402_EXACT_SCHEME], [network], [asset]);
40
+ }
@@ -1,10 +1,11 @@
1
+ import { type ChainInfo } from "@faremeter/types/evm";
1
2
  import { type FacilitatorHandler } from "@faremeter/types/facilitator";
2
- import type { Chain, Transport } from "viem";
3
+ import type { Transport } from "viem";
3
4
  import { type KnownX402Network, type AssetNameOrContractInfo } from "@faremeter/info/evm";
4
5
  type CreateFacilitatorHandlerOpts = {
5
6
  network?: KnownX402Network;
6
7
  transport?: Transport;
7
8
  };
8
- export declare function createFacilitatorHandler(chain: Chain, privateKey: string, assetNameOrInfo: AssetNameOrContractInfo, opts?: CreateFacilitatorHandlerOpts): Promise<FacilitatorHandler>;
9
+ export declare function createFacilitatorHandler(chain: ChainInfo, privateKey: string, assetNameOrInfo: AssetNameOrContractInfo, opts?: CreateFacilitatorHandlerOpts): Promise<FacilitatorHandler>;
9
10
  export {};
10
11
  //# sourceMappingURL=facilitator.d.ts.map
@@ -1 +1 @@
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
+ {"version":3,"file":"facilitator.d.ts","sourceRoot":"","sources":["../../../src/exact/facilitator.ts"],"names":[],"mappings":"AAOA,OAAO,EAAgB,KAAK,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACpE,OAAO,EAAE,KAAK,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAGvE,OAAO,KAAK,EAAgB,SAAS,EAAE,MAAM,MAAM,CAAC;AAYpD,OAAO,EAEL,KAAK,gBAAgB,EAErB,KAAK,uBAAuB,EAC7B,MAAM,qBAAqB,CAAC;AAgC7B,KAAK,4BAA4B,GAAG;IAClC,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAC3B,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB,CAAC;AACF,wBAAsB,wBAAwB,CAC5C,KAAK,EAAE,SAAS,EAChB,UAAU,EAAE,MAAM,EAClB,eAAe,EAAE,uBAAuB,EACxC,IAAI,GAAE,4BAAiC,GACtC,OAAO,CAAC,kBAAkB,CAAC,CA0R7B"}
@@ -1,4 +1,3 @@
1
- import { isValidationError, caseInsensitiveLiteral } from "@faremeter/types";
2
1
  import { isPrivateKey } from "@faremeter/types/evm";
3
2
  import {} from "@faremeter/types/facilitator";
4
3
  import { type } from "arktype";
@@ -6,7 +5,7 @@ import { createPublicClient, createWalletClient, http, verifyTypedData, encodeFu
6
5
  import { privateKeyToAccount } from "viem/accounts";
7
6
  import { lookupX402Network, findAssetInfo, } from "@faremeter/info/evm";
8
7
  import { X402_EXACT_SCHEME, TRANSFER_WITH_AUTHORIZATION_ABI, EIP712_TYPES, x402ExactPayload, } from "./constants.js";
9
- import { generateDomain, generateForwarderDomain } from "./common.js";
8
+ import { generateMatcher, generateDomain, generateForwarderDomain, } from "./common.js";
10
9
  function errorResponse(msg) {
11
10
  return {
12
11
  success: false,
@@ -15,7 +14,6 @@ function errorResponse(msg) {
15
14
  networkId: null,
16
15
  };
17
16
  }
18
- const usedNonces = new Set();
19
17
  function parseSignature(signature) {
20
18
  const sig = signature.slice(2); // Remove 0x
21
19
  const r = `0x${sig.slice(0, 64)}`;
@@ -38,12 +36,10 @@ export async function createFacilitatorHandler(chain, privateKey, assetNameOrInf
38
36
  const transport = opts.transport ?? http(chain.rpcUrls.default.http[0]);
39
37
  const account = privateKeyToAccount(privateKey);
40
38
  const publicClient = createPublicClient({
41
- chain,
42
39
  transport,
43
40
  });
44
41
  const walletClient = createWalletClient({
45
42
  account,
46
- chain,
47
43
  transport,
48
44
  });
49
45
  let domain;
@@ -69,13 +65,7 @@ export async function createFacilitatorHandler(chain, privateKey, assetNameOrInf
69
65
  throw new Error(`On chain contract name (${domain.name}) doesn't match configured asset name (${assetInfo.contractName})`);
70
66
  }
71
67
  }
72
- const checkTuple = type({
73
- scheme: caseInsensitiveLiteral(X402_EXACT_SCHEME),
74
- network: caseInsensitiveLiteral(network),
75
- });
76
- const checkTupleAndAsset = checkTuple.and({
77
- asset: caseInsensitiveLiteral(asset),
78
- });
68
+ const { isMatchingRequirement } = generateMatcher(network, asset);
79
69
  const getSupported = () => {
80
70
  return [
81
71
  Promise.resolve({
@@ -86,9 +76,7 @@ export async function createFacilitatorHandler(chain, privateKey, assetNameOrInf
86
76
  ];
87
77
  };
88
78
  const getRequirements = async (req) => {
89
- return req
90
- .filter((x) => !isValidationError(checkTupleAndAsset(x)))
91
- .map((x) => ({
79
+ return req.filter(isMatchingRequirement).map((x) => ({
92
80
  ...x,
93
81
  asset,
94
82
  maxTimeoutSeconds: 300,
@@ -102,8 +90,7 @@ export async function createFacilitatorHandler(chain, privateKey, assetNameOrInf
102
90
  }));
103
91
  };
104
92
  const handleSettle = async (requirements, payment) => {
105
- const tupleMatches = checkTuple(payment);
106
- if (isValidationError(tupleMatches)) {
93
+ if (!isMatchingRequirement(requirements)) {
107
94
  return null; // Not for us, let another handler try
108
95
  }
109
96
  // For the exact scheme with EIP-3009, validate the authorization payload
@@ -134,11 +121,6 @@ export async function createFacilitatorHandler(chain, privateKey, assetNameOrInf
134
121
  if (!isAddress(authorization.from)) {
135
122
  return errorResponse("Invalid from address");
136
123
  }
137
- // Check nonce hasn't been used (local check)
138
- const nonceKey = `${authorization.from}-${authorization.nonce}`;
139
- if (usedNonces.has(nonceKey)) {
140
- return errorResponse("Nonce already used");
141
- }
142
124
  // Check on-chain nonce status
143
125
  let onChainUsed;
144
126
  try {
@@ -235,7 +217,7 @@ export async function createFacilitatorHandler(chain, privateKey, assetNameOrInf
235
217
  to: useForwarder ? domain.verifyingContract : asset,
236
218
  data,
237
219
  account: acct,
238
- chain: undefined,
220
+ chain: null,
239
221
  });
240
222
  const serializedTransaction = await walletClient.signTransaction(request);
241
223
  const txHash = await publicClient.sendRawTransaction({
@@ -247,7 +229,6 @@ export async function createFacilitatorHandler(chain, privateKey, assetNameOrInf
247
229
  if (receipt.status !== "success") {
248
230
  return errorResponse("Transaction failed");
249
231
  }
250
- usedNonces.add(nonceKey);
251
232
  return {
252
233
  success: true,
253
234
  error: null,