@0xtorch/evm 0.0.122 → 0.0.123

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.
Files changed (109) hide show
  1. package/_cjs/chain/definitions/arbitrumOne.js +0 -10
  2. package/_cjs/chain/definitions/arbitrumOne.js.map +1 -1
  3. package/_cjs/chain/definitions/avalancheC.js +0 -5
  4. package/_cjs/chain/definitions/avalancheC.js.map +1 -1
  5. package/_cjs/chain/definitions/base.js +0 -5
  6. package/_cjs/chain/definitions/base.js.map +1 -1
  7. package/_cjs/chain/definitions/blast.js +0 -10
  8. package/_cjs/chain/definitions/blast.js.map +1 -1
  9. package/_cjs/chain/definitions/bsc.js +8 -13
  10. package/_cjs/chain/definitions/bsc.js.map +1 -1
  11. package/_cjs/chain/definitions/ethereum.js +1 -6
  12. package/_cjs/chain/definitions/ethereum.js.map +1 -1
  13. package/_cjs/chain/definitions/fantom.js +0 -10
  14. package/_cjs/chain/definitions/fantom.js.map +1 -1
  15. package/_cjs/chain/definitions/linea.js +0 -5
  16. package/_cjs/chain/definitions/linea.js.map +1 -1
  17. package/_cjs/chain/definitions/mantaPacific.js +0 -5
  18. package/_cjs/chain/definitions/mantaPacific.js.map +1 -1
  19. package/_cjs/chain/definitions/opBnb.js +2 -2
  20. package/_cjs/chain/definitions/opBnb.js.map +1 -1
  21. package/_cjs/chain/definitions/optimism.js +2 -22
  22. package/_cjs/chain/definitions/optimism.js.map +1 -1
  23. package/_cjs/chain/definitions/polygonPos.js +2 -7
  24. package/_cjs/chain/definitions/polygonPos.js.map +1 -1
  25. package/_cjs/chain/definitions/polygonZkEvm.js +0 -5
  26. package/_cjs/chain/definitions/polygonZkEvm.js.map +1 -1
  27. package/_cjs/chain/definitions/ronin.js +0 -10
  28. package/_cjs/chain/definitions/ronin.js.map +1 -1
  29. package/_cjs/chain/definitions/scroll.js +2 -7
  30. package/_cjs/chain/definitions/scroll.js.map +1 -1
  31. package/_cjs/chain/definitions/zkSyncEra.js +0 -10
  32. package/_cjs/chain/definitions/zkSyncEra.js.map +1 -1
  33. package/_cjs/client/create.js +120 -67
  34. package/_cjs/client/create.js.map +1 -1
  35. package/_esm/chain/definitions/arbitrumOne.js +12 -10
  36. package/_esm/chain/definitions/arbitrumOne.js.map +1 -1
  37. package/_esm/chain/definitions/avalancheC.js +6 -5
  38. package/_esm/chain/definitions/avalancheC.js.map +1 -1
  39. package/_esm/chain/definitions/base.js +6 -5
  40. package/_esm/chain/definitions/base.js.map +1 -1
  41. package/_esm/chain/definitions/blast.js +12 -10
  42. package/_esm/chain/definitions/blast.js.map +1 -1
  43. package/_esm/chain/definitions/bsc.js +14 -13
  44. package/_esm/chain/definitions/bsc.js.map +1 -1
  45. package/_esm/chain/definitions/ethereum.js +8 -7
  46. package/_esm/chain/definitions/ethereum.js.map +1 -1
  47. package/_esm/chain/definitions/fantom.js +12 -10
  48. package/_esm/chain/definitions/fantom.js.map +1 -1
  49. package/_esm/chain/definitions/linea.js +6 -5
  50. package/_esm/chain/definitions/linea.js.map +1 -1
  51. package/_esm/chain/definitions/mantaPacific.js +6 -5
  52. package/_esm/chain/definitions/mantaPacific.js.map +1 -1
  53. package/_esm/chain/definitions/opBnb.js +2 -2
  54. package/_esm/chain/definitions/opBnb.js.map +1 -1
  55. package/_esm/chain/definitions/optimism.js +26 -22
  56. package/_esm/chain/definitions/optimism.js.map +1 -1
  57. package/_esm/chain/definitions/polygonPos.js +8 -7
  58. package/_esm/chain/definitions/polygonPos.js.map +1 -1
  59. package/_esm/chain/definitions/polygonZkEvm.js +6 -5
  60. package/_esm/chain/definitions/polygonZkEvm.js.map +1 -1
  61. package/_esm/chain/definitions/ronin.js +12 -10
  62. package/_esm/chain/definitions/ronin.js.map +1 -1
  63. package/_esm/chain/definitions/scroll.js +8 -7
  64. package/_esm/chain/definitions/scroll.js.map +1 -1
  65. package/_esm/chain/definitions/zkSyncEra.js +12 -10
  66. package/_esm/chain/definitions/zkSyncEra.js.map +1 -1
  67. package/_esm/client/create.js +121 -67
  68. package/_esm/client/create.js.map +1 -1
  69. package/_types/chain/definitions/arbitrumOne.d.ts.map +1 -1
  70. package/_types/chain/definitions/avalancheC.d.ts.map +1 -1
  71. package/_types/chain/definitions/base.d.ts.map +1 -1
  72. package/_types/chain/definitions/blast.d.ts.map +1 -1
  73. package/_types/chain/definitions/bsc.d.ts.map +1 -1
  74. package/_types/chain/definitions/ethereum.d.ts.map +1 -1
  75. package/_types/chain/definitions/fantom.d.ts.map +1 -1
  76. package/_types/chain/definitions/linea.d.ts.map +1 -1
  77. package/_types/chain/definitions/mantaPacific.d.ts.map +1 -1
  78. package/_types/chain/definitions/optimism.d.ts.map +1 -1
  79. package/_types/chain/definitions/polygonPos.d.ts.map +1 -1
  80. package/_types/chain/definitions/polygonZkEvm.d.ts.map +1 -1
  81. package/_types/chain/definitions/ronin.d.ts.map +1 -1
  82. package/_types/chain/definitions/scroll.d.ts.map +1 -1
  83. package/_types/chain/definitions/zkSyncEra.d.ts.map +1 -1
  84. package/_types/client/create.d.ts.map +1 -1
  85. package/chain/definitions/arbitrumOne.ts +12 -10
  86. package/chain/definitions/avalancheC.ts +6 -5
  87. package/chain/definitions/base.ts +6 -5
  88. package/chain/definitions/blast.ts +12 -10
  89. package/chain/definitions/bsc.ts +14 -13
  90. package/chain/definitions/ethereum.ts +8 -7
  91. package/chain/definitions/fantom.ts +12 -10
  92. package/chain/definitions/linea.ts +6 -5
  93. package/chain/definitions/mantaPacific.ts +6 -5
  94. package/chain/definitions/opBnb.ts +2 -2
  95. package/chain/definitions/optimism.ts +26 -22
  96. package/chain/definitions/polygonPos.ts +8 -7
  97. package/chain/definitions/polygonZkEvm.ts +6 -5
  98. package/chain/definitions/ronin.ts +12 -10
  99. package/chain/definitions/scroll.ts +8 -7
  100. package/chain/definitions/zkSyncEra.ts +12 -10
  101. package/client/create.ts +161 -76
  102. package/package.json +1 -1
  103. package/_cjs/client/rpcManager.js +0 -94
  104. package/_cjs/client/rpcManager.js.map +0 -1
  105. package/_esm/client/rpcManager.js +0 -90
  106. package/_esm/client/rpcManager.js.map +0 -1
  107. package/_types/client/rpcManager.d.ts +0 -20
  108. package/_types/client/rpcManager.d.ts.map +0 -1
  109. package/client/rpcManager.ts +0 -135
@@ -59,11 +59,12 @@ export const createFantomChainCustom = ({
59
59
  })
60
60
 
61
61
  export const fantomHttpRpcs: HttpRpc[] = [
62
- {
63
- url: 'https://rpc.ankr.com/fantom/',
64
- getLogsIsUsable: true,
65
- getLogsMaxBlockRange: 3000n,
66
- },
62
+ // Endpoint is not working
63
+ // {
64
+ // url: 'https://rpc.ankr.com/fantom/',
65
+ // getLogsIsUsable: true,
66
+ // getLogsMaxBlockRange: 3000n,
67
+ // },
67
68
  {
68
69
  url: 'https://rpcapi.fantom.network',
69
70
  getLogsIsUsable: true,
@@ -84,11 +85,12 @@ export const fantomHttpRpcs: HttpRpc[] = [
84
85
  getLogsIsUsable: true,
85
86
  getLogsMaxBlockRange: 40_000n,
86
87
  },
87
- {
88
- url: 'https://fantom.blockpi.network/v1/rpc/public',
89
- getLogsIsUsable: true,
90
- getLogsMaxBlockRange: 1024n,
91
- },
88
+ // Endpoint is not working
89
+ // {
90
+ // url: 'https://fantom.blockpi.network/v1/rpc/public',
91
+ // getLogsIsUsable: true,
92
+ // getLogsMaxBlockRange: 1024n,
93
+ // },
92
94
  {
93
95
  url: 'https://fantom.drpc.org/',
94
96
  getLogsIsUsable: true,
@@ -59,11 +59,12 @@ export const createLineaChainCustom = ({
59
59
  })
60
60
 
61
61
  export const lineaHttpRpcs: HttpRpc[] = [
62
- {
63
- url: 'https://linea.blockpi.network/v1/rpc/public',
64
- getLogsIsUsable: true,
65
- getLogsMaxBlockRange: 1024n,
66
- },
62
+ // Endpoint is not working
63
+ // {
64
+ // url: 'https://linea.blockpi.network/v1/rpc/public',
65
+ // getLogsIsUsable: true,
66
+ // getLogsMaxBlockRange: 1024n,
67
+ // },
67
68
  {
68
69
  url: 'https://1rpc.io/linea',
69
70
  getLogsIsUsable: true,
@@ -68,11 +68,12 @@ export const mantaPacificHttpRpcs: HttpRpc[] = [
68
68
  getLogsIsUsable: true,
69
69
  getLogsMaxBlockRange: 20_000n,
70
70
  },
71
- {
72
- url: 'https://www.tencentcloud-rpc.com/v2/manta/manta-rpc',
73
- getLogsIsUsable: false,
74
- getLogsMaxBlockRange: 0n,
75
- },
71
+ // Endpoint is not working
72
+ // {
73
+ // url: 'https://www.tencentcloud-rpc.com/v2/manta/manta-rpc',
74
+ // getLogsIsUsable: false,
75
+ // getLogsMaxBlockRange: 0n,
76
+ // },
76
77
  {
77
78
  url: 'https://r1.pacific.manta.systems/http',
78
79
  getLogsIsUsable: true,
@@ -81,8 +81,8 @@ export const opBnbHttpRpcs: HttpRpc[] = [
81
81
  },
82
82
  {
83
83
  url: 'https://opbnb-mainnet.4everland.org/v1/37fa9972c1b1cd5fab542c7bdd4cde2f',
84
- getLogsIsUsable: true,
85
- getLogsMaxBlockRange: 10_000n,
84
+ getLogsIsUsable: false,
85
+ getLogsMaxBlockRange: 0n,
86
86
  },
87
87
  {
88
88
  url: 'https://opbnb-mainnet.nodereal.io/v1/64a9df0874fb4a93b9d0a3849de012d3',
@@ -95,11 +95,12 @@ export const optimismHttpRpcs: HttpRpc[] = [
95
95
  getLogsIsUsable: true,
96
96
  getLogsMaxBlockRange: 1024n,
97
97
  },
98
- {
99
- url: 'https://endpoints.omniatech.io/v1/op/mainnet/public',
100
- getLogsIsUsable: true,
101
- getLogsMaxBlockRange: 3000n,
102
- },
98
+ // Not archiving receipts
99
+ // {
100
+ // url: 'https://endpoints.omniatech.io/v1/op/mainnet/public',
101
+ // getLogsIsUsable: true,
102
+ // getLogsMaxBlockRange: 3000n,
103
+ // },
103
104
  {
104
105
  url: 'https://optimism.api.onfinality.io/public',
105
106
  getLogsIsUsable: true,
@@ -111,11 +112,12 @@ export const optimismHttpRpcs: HttpRpc[] = [
111
112
  // getLogsIsUsable: true,
112
113
  // getLogsMaxBlockRange: 4000n,
113
114
  // },
114
- {
115
- url: 'https://optimism-rpc.publicnode.com',
116
- getLogsIsUsable: true,
117
- getLogsMaxBlockRange: 10_000n,
118
- },
115
+ // Not archiving receipts
116
+ // {
117
+ // url: 'https://optimism-rpc.publicnode.com',
118
+ // getLogsIsUsable: true,
119
+ // getLogsMaxBlockRange: 10_000n,
120
+ // },
119
121
  // Not archiving receipts
120
122
  // {
121
123
  // url: 'https://optimism.meowrpc.com',
@@ -128,11 +130,12 @@ export const optimismHttpRpcs: HttpRpc[] = [
128
130
  // getLogsIsUsable: true,
129
131
  // getLogsMaxBlockRange: 10_000n,
130
132
  // },
131
- {
132
- url: 'https://optimism.publicnode.com',
133
- getLogsIsUsable: true,
134
- getLogsMaxBlockRange: 10_000n,
135
- },
133
+ // Not archiving receipts
134
+ // {
135
+ // url: 'https://optimism.publicnode.com',
136
+ // getLogsIsUsable: true,
137
+ // getLogsMaxBlockRange: 10_000n,
138
+ // },
136
139
  // Not archiving receipts
137
140
  // {
138
141
  // url: 'https://optimism.meowrpc.com',
@@ -174,14 +177,15 @@ export const optimismHttpRpcs: HttpRpc[] = [
174
177
  // },
175
178
  {
176
179
  url: 'https://opt-mainnet.4everland.org/v1/37fa9972c1b1cd5fab542c7bdd4cde2f',
177
- getLogsIsUsable: true,
178
- getLogsMaxBlockRange: 10_000n,
179
- },
180
- {
181
- url: 'https://optimism.rpc.subquery.network/public',
182
- getLogsIsUsable: true,
183
- getLogsMaxBlockRange: 10_000n,
180
+ getLogsIsUsable: false,
181
+ getLogsMaxBlockRange: 0n,
184
182
  },
183
+ // Not archiving receipts
184
+ // {
185
+ // url: 'https://optimism.rpc.subquery.network/public',
186
+ // getLogsIsUsable: true,
187
+ // getLogsMaxBlockRange: 10_000n,
188
+ // },
185
189
  ]
186
190
 
187
191
  export const optimismWebsocketRpcUrls: readonly string[] = [
@@ -59,11 +59,12 @@ export const createPolygonPosChainCustom = ({
59
59
  })
60
60
 
61
61
  export const polygonPosHttpRpcs: HttpRpc[] = [
62
- {
63
- url: 'https://endpoints.omniatech.io/v1/matic/mainnet/public',
64
- getLogsIsUsable: true,
65
- getLogsMaxBlockRange: 10_000n,
66
- },
62
+ // Not archiving receipts
63
+ // {
64
+ // url: 'https://endpoints.omniatech.io/v1/matic/mainnet/public',
65
+ // getLogsIsUsable: false,
66
+ // getLogsMaxBlockRange: 0n,
67
+ // },
67
68
  {
68
69
  url: 'https://polygon-rpc.com',
69
70
  getLogsIsUsable: true,
@@ -175,8 +176,8 @@ export const polygonPosHttpRpcs: HttpRpc[] = [
175
176
  },
176
177
  {
177
178
  url: 'https://polygon-mainnet.4everland.org/v1/37fa9972c1b1cd5fab542c7bdd4cde2f',
178
- getLogsIsUsable: true,
179
- getLogsMaxBlockRange: 10_000n,
179
+ getLogsIsUsable: false,
180
+ getLogsMaxBlockRange: 0n,
180
181
  },
181
182
  ]
182
183
 
@@ -75,11 +75,12 @@ export const polygonZkEvmHttpRpcs: HttpRpc[] = [
75
75
  // getLogsIsUsable: true,
76
76
  // getLogsMaxBlockRange: 10_000n,
77
77
  // },
78
- {
79
- url: 'https://polygon-zkevm.blockpi.network/v1/rpc/public',
80
- getLogsIsUsable: true,
81
- getLogsMaxBlockRange: 10_000n,
82
- },
78
+ // Endpoint is not working
79
+ // {
80
+ // url: 'https://polygon-zkevm.blockpi.network/v1/rpc/public',
81
+ // getLogsIsUsable: true,
82
+ // getLogsMaxBlockRange: 10_000n,
83
+ // },
83
84
  {
84
85
  url: 'https://polygon-zkevm-mainnet.public.blastapi.io',
85
86
  getLogsIsUsable: false,
@@ -66,16 +66,18 @@ export const roninHttpRpcs: HttpRpc[] = [
66
66
  // getLogsIsUsable: true,
67
67
  // getLogsMaxBlockRange: 20_000n,
68
68
  // },
69
- {
70
- url: 'https://api-gateway.skymavis.com/rpc?apikey=9aqYLBbxSC6LROynQJBvKkEIsioqwHmr',
71
- getLogsIsUsable: true,
72
- getLogsMaxBlockRange: 500n,
73
- },
74
- {
75
- url: 'https://ronin.drpc.org',
76
- getLogsIsUsable: true,
77
- getLogsMaxBlockRange: 10_000n,
78
- },
69
+ // Endpoint is not working
70
+ // {
71
+ // url: 'https://api-gateway.skymavis.com/rpc?apikey=9aqYLBbxSC6LROynQJBvKkEIsioqwHmr',
72
+ // getLogsIsUsable: true,
73
+ // getLogsMaxBlockRange: 500n,
74
+ // },
75
+ // Not archiving receipts
76
+ // {
77
+ // url: 'https://ronin.drpc.org',
78
+ // getLogsIsUsable: true,
79
+ // getLogsMaxBlockRange: 10_000n,
80
+ // },
79
81
  ]
80
82
 
81
83
  export const roninWebsocketRpcUrls: readonly string[] = []
@@ -80,15 +80,16 @@ export const scrollHttpRpcs: HttpRpc[] = [
80
80
  getLogsIsUsable: true,
81
81
  getLogsMaxBlockRange: 10_000n,
82
82
  },
83
- {
84
- url: 'https://scroll.blockpi.network/v1/rpc/public',
85
- getLogsIsUsable: true,
86
- getLogsMaxBlockRange: 1024n,
87
- },
83
+ // Endpoint is not working
84
+ // {
85
+ // url: 'https://scroll.blockpi.network/v1/rpc/public',
86
+ // getLogsIsUsable: true,
87
+ // getLogsMaxBlockRange: 1024n,
88
+ // },
88
89
  {
89
90
  url: 'https://1rpc.io/scroll',
90
- getLogsIsUsable: true,
91
- getLogsMaxBlockRange: 1000n,
91
+ getLogsIsUsable: false,
92
+ getLogsMaxBlockRange: 0n,
92
93
  },
93
94
  {
94
95
  url: 'https://scroll.drpc.org',
@@ -64,11 +64,12 @@ export const zksyncEraHttpRpcs: HttpRpc[] = [
64
64
  getLogsIsUsable: true,
65
65
  getLogsMaxBlockRange: 10_000n,
66
66
  },
67
- {
68
- url: 'https://zksync-era.blockpi.network/v1/rpc/public',
69
- getLogsIsUsable: true,
70
- getLogsMaxBlockRange: 1024n,
71
- },
67
+ // Endpoint is not working
68
+ // {
69
+ // url: 'https://zksync-era.blockpi.network/v1/rpc/public',
70
+ // getLogsIsUsable: true,
71
+ // getLogsMaxBlockRange: 1024n,
72
+ // },
72
73
  // Not archiving receipts
73
74
  // {
74
75
  // url: 'https://go.getblock.io/f76c09905def4618a34946bf71851542',
@@ -92,11 +93,12 @@ export const zksyncEraHttpRpcs: HttpRpc[] = [
92
93
  getLogsIsUsable: true,
93
94
  getLogsMaxBlockRange: 1000n,
94
95
  },
95
- {
96
- url: 'https://endpoints.omniatech.io/v1/zksync-era/mainnet/public',
97
- getLogsIsUsable: true,
98
- getLogsMaxBlockRange: 10_000n,
99
- },
96
+ // Endpoint is not working
97
+ // {
98
+ // url: 'https://endpoints.omniatech.io/v1/zksync-era/mainnet/public',
99
+ // getLogsIsUsable: true,
100
+ // getLogsMaxBlockRange: 10_000n,
101
+ // },
100
102
  // Not archiving receipts
101
103
  // {
102
104
  // url: 'https://api.zan.top/zksync-mainnet',
package/client/create.ts CHANGED
@@ -10,7 +10,9 @@ import {
10
10
  InvalidInputRpcError,
11
11
  JsonRpcVersionUnsupportedError,
12
12
  type MulticallParameters,
13
+ type MulticallReturnType,
13
14
  type PublicClient,
15
+ type ReadContractParameters,
14
16
  RpcRequestError,
15
17
  TransactionNotFoundError,
16
18
  TransactionReceiptNotFoundError,
@@ -21,6 +23,68 @@ import type { LowerHex } from '../types'
21
23
  import { bigIntMin } from '../utils'
22
24
  import type { Client } from './types'
23
25
 
26
+ class Semaphore {
27
+ #endpoints: readonly string[]
28
+ #usingIndexSet = new Set<number>()
29
+ #queue: Array<{
30
+ call: () => void
31
+ timeoutId: ReturnType<typeof setTimeout>
32
+ }> = []
33
+
34
+ constructor(endpoints: readonly string[]) {
35
+ this.#endpoints = endpoints
36
+ }
37
+
38
+ async acquire(timeout: number): Promise<string> {
39
+ if (this.#usingIndexSet.size < this.#endpoints.length) {
40
+ const index = this.#endpoints.findIndex(
41
+ (_, index) => !this.#usingIndexSet.has(index),
42
+ )
43
+ this.#usingIndexSet.add(index)
44
+ const endpoint = this.#endpoints[index]
45
+ return Promise.resolve(endpoint)
46
+ }
47
+
48
+ return new Promise<string>((resolve, reject) => {
49
+ const timeoutId = setTimeout(() => {
50
+ const index = this.#queue.findIndex(
51
+ (item) => item.timeoutId === timeoutId,
52
+ )
53
+ if (index !== -1) {
54
+ this.#queue.splice(index, 1)
55
+ reject(new Error('Timeout while waiting for semaphore'))
56
+ }
57
+ }, timeout)
58
+
59
+ this.#queue.push({
60
+ call: () => {
61
+ const index = this.#endpoints.findIndex(
62
+ (_, index) => !this.#usingIndexSet.has(index),
63
+ )
64
+ this.#usingIndexSet.add(index)
65
+ const endpoint = this.#endpoints[index]
66
+ resolve(endpoint)
67
+ },
68
+ timeoutId,
69
+ })
70
+ })
71
+ }
72
+
73
+ async release(endpoint: string, cooldown?: number): Promise<void> {
74
+ if (cooldown !== undefined) {
75
+ await new Promise((resolve) => setTimeout(resolve, cooldown))
76
+ }
77
+ const index = this.#endpoints.indexOf(endpoint)
78
+ this.#usingIndexSet.delete(index)
79
+ const next = this.#queue.shift()
80
+ if (next !== undefined) {
81
+ const { call, timeoutId } = next
82
+ clearTimeout(timeoutId)
83
+ call()
84
+ }
85
+ }
86
+ }
87
+
24
88
  type CreateClientParameters = {
25
89
  chain: Chain
26
90
  httpRpcs: HttpRpc[]
@@ -31,6 +95,7 @@ export const createClient = ({
31
95
  httpRpcs,
32
96
  }: CreateClientParameters): Client => {
33
97
  const endpoints = httpRpcs.map((httpRpc) => httpRpc.url)
98
+ const semaphore = new Semaphore(endpoints)
34
99
  const getLogsIsUsableEndpoints = new Set<string>()
35
100
  const endpointGetLogsMaxBlockRanges = new Map<string, bigint>()
36
101
  for (const httpRpc of httpRpcs) {
@@ -87,7 +152,8 @@ export const createClient = ({
87
152
  timeout?: number
88
153
  }): Promise<T> => {
89
154
  const start = Date.now()
90
- const endpoint = await getAvailableEndpoint(timeout)
155
+ const endpoint = await semaphore.acquire(timeout)
156
+ let cooldown: number | undefined
91
157
  console.debug(`Call ${callName ?? ''} on ${endpoint}`)
92
158
  try {
93
159
  const client = createPublicClient({
@@ -104,27 +170,19 @@ export const createClient = ({
104
170
  ])
105
171
  } catch (error) {
106
172
  if (
107
- (error instanceof HttpRequestError &&
108
- (error.status === 429 || error.status === 503)) ||
109
- (error instanceof ContractFunctionExecutionError &&
110
- (error.message.includes('Status: 429') ||
111
- error.message.includes('Status: 503'))) ||
112
- (error instanceof CallExecutionError &&
113
- (error.message.includes('429') || error.message.includes('503'))) ||
114
- error instanceof RpcRequestError ||
115
- error instanceof JsonRpcVersionUnsupportedError ||
116
- error instanceof InternalRpcError ||
173
+ isRequestError(error) ||
117
174
  (error instanceof Error &&
118
175
  (error.message.includes('The request timed out.') ||
119
176
  error.message.includes('Timeout')))
120
177
  ) {
121
178
  console.debug(error)
122
- cooldownEndpoint(endpoint)
179
+ cooldown = 60_000
123
180
  return await call({
124
181
  clientCall,
125
182
  timeout: timeout - (Date.now() - start),
126
183
  })
127
184
  }
185
+
128
186
  if (
129
187
  error instanceof TransactionNotFoundError ||
130
188
  error instanceof TransactionReceiptNotFoundError ||
@@ -132,26 +190,16 @@ export const createClient = ({
132
190
  error instanceof InvalidInputRpcError
133
191
  ) {
134
192
  console.debug(error)
135
- cooldownEndpoint(endpoint, 5000)
136
- return await call({
137
- clientCall,
138
- timeout: timeout - (Date.now() - start),
139
- })
140
- }
141
- if (
142
- error instanceof RpcRequestError &&
143
- error.details.includes('Unparsable response type')
144
- ) {
145
- console.debug(error)
146
- cooldownEndpoint(endpoint, 1000 * 60 * 60)
193
+ cooldown = 5000
147
194
  return await call({
148
195
  clientCall,
149
196
  timeout: timeout - (Date.now() - start),
150
197
  })
151
198
  }
199
+
152
200
  throw error
153
201
  } finally {
154
- busyEndpoints.delete(endpoint)
202
+ await semaphore.release(endpoint, cooldown)
155
203
  }
156
204
  }
157
205
 
@@ -206,16 +254,7 @@ export const createClient = ({
206
254
  currentFromBlock = currentToBlock + 1n
207
255
  } catch (error) {
208
256
  if (
209
- (error instanceof HttpRequestError &&
210
- (error.status === 429 || error.status === 503)) ||
211
- (error instanceof ContractFunctionExecutionError &&
212
- (error.message.includes('Status: 429') ||
213
- error.message.includes('Status: 503'))) ||
214
- (error instanceof CallExecutionError &&
215
- (error.message.includes('429') || error.message.includes('503'))) ||
216
- error instanceof RpcRequestError ||
217
- error instanceof JsonRpcVersionUnsupportedError ||
218
- error instanceof InternalRpcError ||
257
+ isRequestError(error) ||
219
258
  (error instanceof Error &&
220
259
  (error.message.includes('The request timed out.') ||
221
260
  error.message.includes('Timeout')))
@@ -224,6 +263,7 @@ export const createClient = ({
224
263
  cooldownEndpoint(endpoint)
225
264
  continue
226
265
  }
266
+
227
267
  if (
228
268
  error instanceof TransactionNotFoundError ||
229
269
  error instanceof TransactionReceiptNotFoundError ||
@@ -234,14 +274,7 @@ export const createClient = ({
234
274
  cooldownEndpoint(endpoint, 5000)
235
275
  continue
236
276
  }
237
- if (
238
- error instanceof RpcRequestError &&
239
- error.details.includes('Unparsable response type')
240
- ) {
241
- console.debug(error)
242
- cooldownEndpoint(endpoint, 1000 * 60 * 60)
243
- continue
244
- }
277
+
245
278
  throw error
246
279
  } finally {
247
280
  busyEndpoints.delete(endpoint)
@@ -256,10 +289,47 @@ export const createClient = ({
256
289
  }: {
257
290
  args: MulticallParameters<T>
258
291
  timeout?: number
259
- }) => {
292
+ }): Promise<MulticallReturnType<T>> => {
260
293
  const start = Date.now()
261
- const endpoint = await getAvailableEndpoint(timeout)
262
- console.debug('Multicall on', endpoint)
294
+
295
+ if (chain.contracts?.multicall3?.address === undefined) {
296
+ // multicall を使用しないで並列実行
297
+ if (args.contracts.length === 0) {
298
+ return [] as unknown as MulticallReturnType<T>
299
+ }
300
+ const results = await Promise.all(
301
+ args.contracts.map((contract) =>
302
+ (async () => {
303
+ try {
304
+ const result = await call({
305
+ clientCall: (client) =>
306
+ client.readContract(contract as ReadContractParameters),
307
+ timeout,
308
+ })
309
+ return {
310
+ result,
311
+ status: 'success',
312
+ }
313
+ } catch (error) {
314
+ if (
315
+ error instanceof Error &&
316
+ error.message === 'Timeout while waiting for semaphore'
317
+ ) {
318
+ throw error
319
+ }
320
+ return {
321
+ error,
322
+ status: 'failure',
323
+ }
324
+ }
325
+ })(),
326
+ ),
327
+ )
328
+ return results as MulticallReturnType<T>
329
+ }
330
+
331
+ const endpoint = await semaphore.acquire(timeout)
332
+ let cooldown: number | undefined
263
333
  try {
264
334
  const client = createPublicClient({
265
335
  chain,
@@ -281,40 +351,17 @@ export const createClient = ({
281
351
  return results
282
352
  }
283
353
  const { error } = result0
284
- if (error instanceof ContractFunctionExecutionError) {
354
+ if (isRequestError(error)) {
285
355
  throw error
286
356
  }
287
357
  return results
288
358
  } catch (error) {
289
- if (error instanceof ContractFunctionExecutionError) {
290
- if (
291
- error.message.includes('Status: 429') ||
292
- error.message.includes('Status: 503') ||
293
- error.message.includes('The request timed out.') ||
294
- error.message.includes('RPC Request failed')
295
- ) {
296
- console.debug(error)
297
- cooldownEndpoint(endpoint)
298
- return await multicall({
299
- args,
300
- timeout: timeout - (Date.now() - start),
301
- })
302
- }
303
- if (
304
- error.message.includes('Status: 404') ||
305
- error.message.includes('HTTP request failed')
306
- ) {
307
- console.debug(error)
308
- cooldownEndpoint(endpoint, 5000)
309
- return await multicall({
310
- args,
311
- timeout: timeout - (Date.now() - start),
312
- })
313
- }
314
- }
315
- if (error instanceof Error && error.message.includes('Timeout')) {
359
+ if (
360
+ isRequestError(error) ||
361
+ (error instanceof Error && error.message.includes('Timeout'))
362
+ ) {
316
363
  console.debug(error)
317
- cooldownEndpoint(endpoint)
364
+ cooldown = 60_000
318
365
  return await multicall({
319
366
  args,
320
367
  timeout: timeout - (Date.now() - start),
@@ -322,7 +369,7 @@ export const createClient = ({
322
369
  }
323
370
  throw error
324
371
  } finally {
325
- busyEndpoints.delete(endpoint)
372
+ await semaphore.release(endpoint, cooldown)
326
373
  }
327
374
  }
328
375
 
@@ -333,3 +380,41 @@ export const createClient = ({
333
380
  multicall,
334
381
  }
335
382
  }
383
+
384
+ const requestErrorMessages: readonly string[] = [
385
+ 'Failed to fetch',
386
+ 'HTTP request failed',
387
+ 'RPC Request failed',
388
+ 'Status: 404',
389
+ 'Status: 429',
390
+ 'Status: 503',
391
+ 'The request timed out.',
392
+ 'Unparsable response type',
393
+ ]
394
+
395
+ const isRequestError = (error: unknown): boolean => {
396
+ if (
397
+ error instanceof HttpRequestError ||
398
+ error instanceof RpcRequestError ||
399
+ error instanceof JsonRpcVersionUnsupportedError ||
400
+ error instanceof InternalRpcError
401
+ ) {
402
+ return true
403
+ }
404
+
405
+ if (error instanceof ContractFunctionExecutionError) {
406
+ for (const message of requestErrorMessages) {
407
+ if (error.message.includes(message)) {
408
+ return true
409
+ }
410
+ }
411
+ }
412
+
413
+ if (
414
+ error instanceof CallExecutionError &&
415
+ (error.message.includes('429') || error.message.includes('503'))
416
+ ) {
417
+ return true
418
+ }
419
+ return false
420
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@0xtorch/evm",
3
- "version": "0.0.122",
3
+ "version": "0.0.123",
4
4
  "description": "Cryptorch EVM extension",
5
5
  "keywords": [
6
6
  "cryptorch",