@envarai/envarpay 0.2.0-alpha.14 → 0.2.0-alpha.15

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.
@@ -8,6 +8,17 @@ const officialUsdc = {
8
8
  'eip155:84532': '0x036cbd53842c5426634e7929541ec2318f3dcf7e',
9
9
  'eip155:8453': '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913',
10
10
  };
11
+ function transientRpcRead(error) {
12
+ for (let cause = error, depth = 0; cause && typeof cause === 'object' && depth < 8; depth++) {
13
+ const value = cause;
14
+ if (value.name === 'TimeoutError' || [408, 429, 500, 502, 503, 504].includes(value.status ?? 0) || [-32005, -32011].includes(value.code ?? 0))
15
+ return true;
16
+ if (value.name === 'HttpRequestError' && value.status === undefined)
17
+ return true;
18
+ cause = value.cause;
19
+ }
20
+ return false;
21
+ }
11
22
  /** Checks the canonical chain receipt and exact official-token Transfer. */
12
23
  export function evmReceiptVerifier(rpcUrls, confirmations = 2, confirmationWaitMs = 12000) {
13
24
  if (!Number.isInteger(confirmations) || confirmations < 1)
@@ -23,8 +34,6 @@ export function evmReceiptVerifier(rpcUrls, confirmations = 2, confirmationWaitM
23
34
  if (!Number.isSafeInteger(chainId) || !/^0x[0-9a-fA-F]{64}$/.test(receipt.transaction) || receipt.network !== requirements.network)
24
35
  return false;
25
36
  const client = createPublicClient({ transport: http(rpc, { timeout: 15000, retryCount: 0 }) });
26
- if (await client.getChainId() !== chainId)
27
- return false;
28
37
  const deadline = Date.now() + confirmationWaitMs;
29
38
  const wait = async () => {
30
39
  const remaining = deadline - Date.now();
@@ -33,10 +42,25 @@ export function evmReceiptVerifier(rpcUrls, confirmations = 2, confirmationWaitM
33
42
  await new Promise(resolve => setTimeout(resolve, Math.min(1000, remaining)));
34
43
  return Date.now() < deadline;
35
44
  };
45
+ // All retries read the original transaction on the configured RPC. A rate
46
+ // limit at any verification stage must not be mistaken for chain evidence.
47
+ const read = async (operation) => {
48
+ for (;;) {
49
+ try {
50
+ return await operation();
51
+ }
52
+ catch (error) {
53
+ if (!transientRpcRead(error) || !await wait())
54
+ throw error;
55
+ }
56
+ }
57
+ };
58
+ if (await read(() => client.getChainId()) !== chainId)
59
+ return false;
36
60
  let mined;
37
61
  for (;;) {
38
62
  try {
39
- mined = await client.getTransactionReceipt({ hash: receipt.transaction });
63
+ mined = await read(() => client.getTransactionReceipt({ hash: receipt.transaction }));
40
64
  }
41
65
  catch (error) {
42
66
  if (error instanceof TransactionReceiptNotFoundError) {
@@ -48,10 +72,10 @@ export function evmReceiptVerifier(rpcUrls, confirmations = 2, confirmationWaitM
48
72
  }
49
73
  if (mined.status !== 'success' || mined.transactionHash.toLowerCase() !== receipt.transaction.toLowerCase())
50
74
  return false;
51
- const block = await client.getBlock({ blockNumber: mined.blockNumber });
75
+ const block = await read(() => client.getBlock({ blockNumber: mined.blockNumber }));
52
76
  if (block.hash !== mined.blockHash)
53
77
  return false;
54
- const latest = await client.getBlockNumber({ cacheTime: 0 });
78
+ const latest = await read(() => client.getBlockNumber({ cacheTime: 0 }));
55
79
  if (latest - mined.blockNumber + 1n >= BigInt(confirmations))
56
80
  break;
57
81
  if (!await wait())
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@envarai/envarpay",
3
- "version": "0.2.0-alpha.14",
3
+ "version": "0.2.0-alpha.15",
4
4
  "description": "Independent A2A service commerce, budgeted buyers and x402/MPP payments",
5
5
  "type": "module",
6
6
  "license": "MIT",