@1delta/providers 0.0.40 → 0.0.42

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/src/index.ts CHANGED
@@ -1 +1 @@
1
- export * from "./evm"
1
+ export * from './evm'
@@ -0,0 +1,253 @@
1
+ import {
2
+ BaseError,
3
+ ContractFunctionExecutionError,
4
+ ContractFunctionRevertedError,
5
+ } from 'viem'
6
+ import lodash from 'lodash'
7
+ import { LIST_OVERRIDES } from '../rpc/rpcOverrides'
8
+ import { getEvmClientWithCustomRpcsUniversal } from '../client/client'
9
+ import { DEFAULT_BATCH_SIZE, deepCompare } from '../utils/utils'
10
+
11
+ const { isArray } = lodash
12
+
13
+ /** Return true if it is a revert case */
14
+ function isContractRevert(e: unknown): boolean {
15
+ if (!(e instanceof BaseError)) return false
16
+
17
+ // Walk the cause chain
18
+ let err: BaseError | null = e
19
+ while (err) {
20
+ // Strong signal
21
+ if (err instanceof ContractFunctionRevertedError) return true
22
+
23
+ // Weaker but common signal
24
+ if (
25
+ err.name === 'ContractFunctionRevertedError' ||
26
+ err.message?.toLowerCase().includes('execution reverted')
27
+ ) {
28
+ return true
29
+ }
30
+
31
+ err = err.cause instanceof BaseError ? err.cause : null
32
+ }
33
+
34
+ return false
35
+ }
36
+
37
+ export interface MulticallRetryParams {
38
+ chain: string
39
+ calls: any[]
40
+ abi: any
41
+ batchSize?: number
42
+ maxRetries?: number
43
+ providerId?: number
44
+ allowFailure?: boolean
45
+ overrdies?: Record<string, string[]>
46
+ logErrors?: boolean
47
+ }
48
+
49
+ export function createMulticallRetry(
50
+ customRpcs: Record<string, string[]> = LIST_OVERRIDES,
51
+ ) {
52
+ return async function multicallRetry(
53
+ chain: string,
54
+ calls: any[],
55
+ abi: any,
56
+ batchSize = DEFAULT_BATCH_SIZE,
57
+ maxRetries = 3,
58
+ providerId = 0,
59
+ allowFailure = true,
60
+ logErrors = false,
61
+ revertedIndices: Set<number> = new Set(),
62
+ ): Promise<any[]> {
63
+ const abiIsArray = isArray(abi[0])
64
+
65
+ try {
66
+ const nonRevertedIndices = calls
67
+ .map((_, i) => i)
68
+ .filter((i) => !revertedIndices.has(i))
69
+
70
+ const filteredCalls = nonRevertedIndices.map((i) => calls[i])
71
+ const filteredAbi = abiIsArray
72
+ ? nonRevertedIndices.map((i) => abi[i])
73
+ : abi
74
+
75
+ const provider = getEvmClientWithCustomRpcsUniversal({
76
+ chain,
77
+ rpcId: providerId,
78
+ customRpcs,
79
+ })
80
+ const data = await provider.multicall({
81
+ batchSize,
82
+ contracts: filteredCalls.map((call, i) => ({
83
+ abi: abiIsArray ? filteredAbi[i] : filteredAbi,
84
+ address: call.address as any,
85
+ functionName: call.name,
86
+ args: call.args ?? call.params ?? [],
87
+ })),
88
+ allowFailure: false,
89
+ })
90
+
91
+ if (revertedIndices.size > 0) {
92
+ const finalResults: any[] = []
93
+ let filteredIndex = 0
94
+
95
+ for (let i = 0; i < calls.length; i++) {
96
+ if (revertedIndices.has(i)) {
97
+ finalResults.push('0x')
98
+ } else {
99
+ finalResults.push(data[filteredIndex++])
100
+ }
101
+ }
102
+ return finalResults
103
+ }
104
+
105
+ return data
106
+ } catch (e) {
107
+ if (isContractRevert(e)) {
108
+ const error = e as ContractFunctionExecutionError
109
+ const errorAddress = (error as any).contractAddress?.toLowerCase()
110
+ const errorFunctionName = error.functionName
111
+ const errorArgs = (error as any).args
112
+
113
+ const nonRevertedIndices = calls
114
+ .map((_, i) => i)
115
+ .filter((i) => !revertedIndices.has(i))
116
+
117
+ const matchingIndices: number[] = []
118
+ for (let i = 0; i < nonRevertedIndices.length; i++) {
119
+ const originalIndex = nonRevertedIndices[i]
120
+ const call = calls[originalIndex]
121
+ const callAddress = call.address?.toLowerCase()
122
+ const callFunctionName = call.name
123
+ const callArgs = call.args ?? call.params ?? []
124
+
125
+ const addressMatch = errorAddress && callAddress === errorAddress
126
+ const functionMatch = errorFunctionName === callFunctionName
127
+ const argsMatch = deepCompare(errorArgs, callArgs)
128
+
129
+ if (addressMatch && functionMatch && argsMatch) {
130
+ matchingIndices.push(originalIndex)
131
+ }
132
+ }
133
+
134
+ if (matchingIndices.length > 0) {
135
+ const newRevertedIndices = new Set(revertedIndices)
136
+ matchingIndices.forEach((idx) => newRevertedIndices.add(idx))
137
+
138
+ if (newRevertedIndices.size === calls.length) {
139
+ return Array(calls.length).fill('0x')
140
+ }
141
+
142
+ return await multicallRetry(
143
+ chain,
144
+ calls,
145
+ abi,
146
+ batchSize,
147
+ maxRetries,
148
+ providerId,
149
+ allowFailure,
150
+ logErrors,
151
+ newRevertedIndices,
152
+ )
153
+ }
154
+ }
155
+
156
+ if (maxRetries === 0) {
157
+ if (!allowFailure) throw e
158
+ if (logErrors) console.debug(e)
159
+ return Array(calls.length).fill('0x')
160
+ }
161
+
162
+ if (logErrors) console.debug(e)
163
+
164
+ return await multicallRetry(
165
+ chain,
166
+ calls,
167
+ abi,
168
+ batchSize,
169
+ maxRetries - 1,
170
+ providerId + 1,
171
+ allowFailure,
172
+ logErrors,
173
+ revertedIndices,
174
+ )
175
+ }
176
+ }
177
+ }
178
+
179
+ async function multicallRetryInternal(
180
+ chain: string,
181
+ calls: any[],
182
+ abi: any,
183
+ batchSize = DEFAULT_BATCH_SIZE,
184
+ maxRetries = 5,
185
+ providerId = 0,
186
+ allowFailure = false,
187
+ overrdies: Record<string, string[]> = LIST_OVERRIDES,
188
+ logErrors = false,
189
+ ) {
190
+ const defaultMulticallRetry = createMulticallRetry(overrdies)
191
+ return defaultMulticallRetry(
192
+ chain,
193
+ calls,
194
+ abi,
195
+ batchSize,
196
+ maxRetries,
197
+ providerId,
198
+ allowFailure,
199
+ logErrors,
200
+ )
201
+ }
202
+
203
+ /**
204
+ * @deprecated use multicallRetryUniversal instead
205
+ * @see multicallRetryUniversal
206
+ */
207
+ export async function multicallRetry(
208
+ chain: string,
209
+ calls: any[],
210
+ abi: any,
211
+ batchSize = DEFAULT_BATCH_SIZE,
212
+ maxRetries = 5,
213
+ providerId = 0,
214
+ allowFailure = false,
215
+ overrdies: Record<string, string[]> = LIST_OVERRIDES,
216
+ logErrors = false,
217
+ ) {
218
+ return multicallRetryInternal(
219
+ chain,
220
+ calls,
221
+ abi,
222
+ batchSize,
223
+ maxRetries,
224
+ providerId,
225
+ allowFailure,
226
+ overrdies,
227
+ logErrors,
228
+ )
229
+ }
230
+
231
+ export async function multicallRetryUniversal({
232
+ chain,
233
+ calls,
234
+ abi,
235
+ batchSize = DEFAULT_BATCH_SIZE,
236
+ maxRetries = 5,
237
+ providerId = 0,
238
+ allowFailure = false,
239
+ overrdies = LIST_OVERRIDES,
240
+ logErrors = false,
241
+ }: MulticallRetryParams) {
242
+ return multicallRetryInternal(
243
+ chain,
244
+ calls,
245
+ abi,
246
+ batchSize,
247
+ maxRetries,
248
+ providerId,
249
+ allowFailure,
250
+ overrdies,
251
+ logErrors,
252
+ )
253
+ }
@@ -0,0 +1,248 @@
1
+ import { Chain } from '@1delta/chain-registry'
2
+
3
+ export const LIST_OVERRIDES: Record<string, string[]> = {
4
+ [Chain.BASE]: [
5
+ 'https://base-rpc.publicnode.com',
6
+ 'https://base.llamarpc.com',
7
+ 'https://base.public.blockpi.network/v1/rpc/public',
8
+ 'https://1rpc.io/base',
9
+ 'https://base-pokt.nodies.app',
10
+ 'https://base.meowrpc.com',
11
+ 'https://developer-access-mainnet.base.org',
12
+ 'https://base.drpc.org',
13
+ 'https://base.api.onfinality.io/public',
14
+ 'https://base.rpc.subquery.network/public',
15
+ 'https://api.zan.top/base-mainnet',
16
+ 'https://endpoints.omniatech.io/v1/base/mainnet/public',
17
+ 'https://base.lava.build',
18
+ 'https://0xrpc.io/base',
19
+ 'https://base.therpc.io',
20
+ ],
21
+ [Chain.POLYGON_MAINNET]: [
22
+ 'https://polygon-bor-rpc.publicnode.com',
23
+ 'https://polygon.lava.build',
24
+ 'https://polygon.drpc.org',
25
+ 'https://gateway.tenderly.co/public/polygon',
26
+ 'https://endpoints.omniatech.io/v1/matic/mainnet/public',
27
+ 'https://polygon.therpc.io',
28
+ 'https://rpc-mainnet.matic.quiknode.pro',
29
+ 'https://polygon-pokt.nodies.app',
30
+ 'https://polygon.gateway.tenderly.co',
31
+ 'https://polygon-rpc.com',
32
+ 'https://polygon.api.onfinality.io/public',
33
+ 'https://api.zan.top/polygon-mainnet',
34
+ 'https://polygon.rpc.subquery.network/public',
35
+ 'https://polygon-mainnet.nodereal.io/v1/f510fc4d083b49d1ab383d25246cc7de',
36
+ 'wss://polygon-mainnet.nodereal.io/ws/v1/f510fc4d083b49d1ab383d25246cc7de',
37
+ ],
38
+ [Chain.HEMI_NETWORK]: ['https://rpc.hemi.network/rpc'],
39
+ [Chain.MANTLE]: [
40
+ 'https://rpc.mantle.xyz',
41
+ 'https://1rpc.io/mantle',
42
+ 'https://api.zan.top/mantle-mainnet',
43
+ 'https://mantle-public.nodies.app',
44
+ 'https://mantle.drpc.org',
45
+ ],
46
+ [Chain.XDC_NETWORK]: [
47
+ 'https://rpc.ankr.com/xdc',
48
+ 'https://earpc.xinfin.network',
49
+ 'https://rpc.xinfin.network',
50
+ 'https://rpc.xdc.org',
51
+ 'https://rpc.xdc.network',
52
+ 'https://erpc.xdcrpc.com',
53
+ ],
54
+ [Chain.ETHEREUM_MAINNET]: [
55
+ 'https://eth.llamarpc.com',
56
+ 'https://api.zan.top/eth-mainnet',
57
+ 'https://rpc.flashbots.net/fast',
58
+ 'https://rpc.owlracle.info/eth/70d38ce1826c4a60bb2a8e05a6c8b20f',
59
+ 'https://eth.merkle.io',
60
+ 'https://eth-mainnet.nodereal.io/v1/1659dfb40aa24bbb8153a677b98064d7',
61
+ 'wss://eth-mainnet.nodereal.io/ws/v1/1659dfb40aa24bbb8153a677b98064d7',
62
+ 'https://rpc.payload.de',
63
+ 'https://ethereum-rpc.publicnode.com',
64
+ 'https://eth-mainnet.g.alchemy.com/v2/demo',
65
+ 'https://go.getblock.io/aefd01aa907c4805ba3c00a9e5b48c6b',
66
+ 'https://rpc.flashbots.net',
67
+ 'https://public-eth.nownodes.io',
68
+ 'https://ethereum-json-rpc.stakely.io',
69
+ 'https://eth.blockrazor.xyz',
70
+ 'https://eth.drpc.org',
71
+ 'https://ethereum.public.blockpi.network/v1/rpc/public',
72
+ 'https://ethereum-public.nodies.app',
73
+ 'https://0xrpc.io/eth',
74
+ ],
75
+ [Chain.PLASMA_MAINNET]: ['https://rpc.plasma.to', 'https://plasma.drpc.org'],
76
+ [Chain.SCROLL]: [
77
+ 'https://rpc.scroll.io',
78
+ 'https://1rpc.io/scroll',
79
+ 'https://scroll.drpc.org',
80
+ 'https://scroll.api.onfinality.io/public',
81
+ 'https://endpoints.omniatech.io/v1/scroll/mainnet/public',
82
+ 'https://scroll-rpc.publicnode.com',
83
+ 'https://scroll.therpc.io',
84
+ ],
85
+ [Chain.SONIC_MAINNET]: [
86
+ 'https://sonic.api.onfinality.io/public',
87
+ 'https://sonic-rpc.publicnode.com',
88
+ 'https://rpc.soniclabs.com',
89
+ 'https://sonic.therpc.io',
90
+ 'https://sonic.drpc.org',
91
+ 'https://sonic-json-rpc.stakely.io',
92
+ ],
93
+ [Chain.KAIA_MAINNET]: [
94
+ 'https://public-en.node.kaia.io',
95
+ 'https://klaytn.api.onfinality.io/public',
96
+ 'https://kaia-mainnet.gateway.tatum.io',
97
+ 'https://kaia-public.nodies.app',
98
+ 'https://kaia.blockpi.network/v1/rpc/public',
99
+ 'https://rpc.ankr.com/kaia',
100
+ 'https://klaytn.drpc.org',
101
+ 'https://1rpc.io/klay',
102
+ ],
103
+ [Chain.MOONBEAM]: [
104
+ 'https://moonbeam.unitedbloc.com',
105
+ 'https://1rpc.io/glmr',
106
+ 'https://moonbeam-rpc.dwellir.com',
107
+ 'https://moonbeam-rpc.publicnode.com',
108
+ 'https://moonbeam.drpc.org',
109
+ 'https://endpoints.omniatech.io/v1/moonbeam/mainnet/public',
110
+ 'https://rpc.api.moonbeam.network',
111
+ 'https://rpc.poolz.finance/moonbeam',
112
+ 'https://moonbeam.rpc.grove.city/v1/01fdb492',
113
+ 'https://moonbeam.api.onfinality.io/public',
114
+ ],
115
+ [Chain.OP_MAINNET]: [
116
+ 'https://optimism.public.blockpi.network/v1/rpc/public',
117
+ 'https://optimism-rpc.publicnode.com',
118
+ 'https://optimism.drpc.org',
119
+ 'https://0xrpc.io/op',
120
+ 'https://1rpc.io/op',
121
+ 'wss://optimism-rpc.publicnode.com',
122
+ 'wss://0xrpc.io/op',
123
+ 'wss://optimism.drpc.org',
124
+ 'https://optimism.api.onfinality.io/public',
125
+ 'https://api.zan.top/opt-mainnet',
126
+ ],
127
+ [Chain.BNB_SMART_CHAIN_MAINNET]: [
128
+ 'https://bsc-dataseed.bnbchain.org',
129
+ 'https://binance.nodereal.io',
130
+ 'https://bsc-mainnet.nodereal.io/v1/64a9df0874fb4a93b9d0a3849de012d3',
131
+ 'wss://bsc-mainnet.nodereal.io/ws/v1/64a9df0874fb4a93b9d0a3849de012d3',
132
+ 'https://bsc-dataseed.binance.org',
133
+ 'https://bsc-dataseed1.binance.org',
134
+ 'https://bsc-dataseed1.defibit.io',
135
+ 'https://bsc-dataseed2.defibit.io',
136
+ 'https://bsc-dataseed3.defibit.io',
137
+ 'https://bsc-dataseed4.defibit.io',
138
+ 'https://1rpc.io/bnb',
139
+ 'https://bsc-rpc.publicnode.com',
140
+ 'https://bsc.drpc.org',
141
+ 'https://bsc.api.onfinality.io/public',
142
+ ],
143
+ [Chain.ARBITRUM_ONE]: [
144
+ 'https://arb1.lava.build',
145
+ 'https://arb1.arbitrum.io/rpc',
146
+ 'https://arbitrum-one-rpc.publicnode.com',
147
+ 'https://arbitrum.drpc.org',
148
+ 'https://arbitrum.public.blockpi.network/v1/rpc/public',
149
+ 'https://1rpc.io/arb',
150
+ 'https://arbitrum.api.onfinality.io/public',
151
+ 'https://0xrpc.io/arb',
152
+ 'https://arbitrum.therpc.io',
153
+ ],
154
+ [Chain.LINEA]: [
155
+ 'https://rpc.linea.build',
156
+ 'https://1rpc.io/linea',
157
+ 'https://linea.drpc.org',
158
+ 'https://linea-rpc.publicnode.com',
159
+ 'https://linea.decubate.com',
160
+ 'https://linea.api.onfinality.io/public',
161
+ ],
162
+ [Chain.AVALANCHE_C_CHAIN]: [
163
+ 'https://avalanche.drpc.org',
164
+ 'https://1rpc.io/avax/c',
165
+ 'https://avalanche-c-chain-rpc.publicnode.com',
166
+ 'https://avalanche.api.onfinality.io/public/ext/bc/C/rpc',
167
+ 'https://api.avax.network/ext/bc/C/rpc',
168
+ 'https://avalanche.public-rpc.com',
169
+ 'https://avax-rpc.gateway.pokt.network',
170
+ ],
171
+ [Chain.CELO_MAINNET]: [
172
+ 'https://forno.celo.org',
173
+ 'https://1rpc.io/celo',
174
+ 'https://celo.drpc.org',
175
+ 'https://celo-rpc.publicnode.com',
176
+ ],
177
+ [Chain.BLAST]: [
178
+ 'https://rpc.blast.io',
179
+ 'https://blast.drpc.org',
180
+ 'https://blast-rpc.publicnode.com',
181
+ ],
182
+ [Chain.TAIKO_ALETHIA]: [
183
+ 'https://rpc.taiko.xyz',
184
+ 'https://rpc.ankr.com/taiko',
185
+ 'https://rpc.mainnet.taiko.xyz',
186
+ 'https://taiko-rpc.publicnode.com',
187
+ ],
188
+ [Chain.GNOSIS]: [
189
+ 'https://gnosis.oat.farm',
190
+ 'https://rpc.gnosischain.com',
191
+ 'https://gnosis.drpc.org',
192
+ 'https://gnosis-rpc.publicnode.com',
193
+ 'https://1rpc.io/gnosis',
194
+ ],
195
+ [Chain.CORE_BLOCKCHAIN_MAINNET]: [
196
+ 'https://rpc.coredao.org',
197
+ 'https://core.drpc.org',
198
+ 'https://core-rpc.publicnode.com',
199
+ ],
200
+ [Chain.MODE]: [
201
+ 'https://mainnet.mode.network',
202
+ 'https://mode.drpc.org',
203
+ 'https://mode-rpc.publicnode.com',
204
+ ],
205
+ [Chain.METIS_ANDROMEDA_MAINNET]: [
206
+ 'https://andromeda.metis.io/?owner=1088',
207
+ 'https://metis.drpc.org',
208
+ 'https://metis-rpc.publicnode.com',
209
+ 'https://metis.api.onfinality.io/public',
210
+ ],
211
+ [Chain.FANTOM_OPERA]: [
212
+ 'https://rpc.fantom.network',
213
+ 'https://fantom.drpc.org',
214
+ 'https://fantom-rpc.publicnode.com',
215
+ 'https://1rpc.io/ftm',
216
+ 'https://fantom.api.onfinality.io/public',
217
+ ],
218
+ [Chain.OPBNB_MAINNET]: [
219
+ 'https://opbnb-mainnet.nodereal.io/v1/64a9df0874fb4a93b9d0a3849de012d3',
220
+ 'wss://opbnb-mainnet.nodereal.io/ws/v1/64a9df0874fb4a93b9d0a3849de012d3',
221
+ ],
222
+ [Chain.X_LAYER_MAINNET]: ['https://xlayerrpc.okx.com'],
223
+ [Chain.MANTA_PACIFIC_MAINNET]: [
224
+ 'https://manta.nirvanalabs.xyz/mantapublic',
225
+ 'https://manta-pacific-gascap.calderachain.xyz/http',
226
+ 'https://manta-pacific.calderachain.xyz/http',
227
+ 'https://pacific-rpc.manta.network/http',
228
+ 'https://r1.pacific.manta.systems/http',
229
+ 'wss://manta-pacific.calderachain.xyz/ws',
230
+ 'https://1rpc.io/manta',
231
+ ],
232
+ [Chain.SEI_NETWORK]: [
233
+ 'https://evm-rpc.sei-apis.com',
234
+ 'https://sei.drpc.org',
235
+ 'https://sei-evm-rpc.stakeme.pro',
236
+ 'https://sei-public.nodies.app',
237
+ 'wss://sei.drpc.org',
238
+ 'wss://evm-ws.sei-apis.com',
239
+ ],
240
+ [Chain.MONAD_MAINNET]: [
241
+ 'https://rpc-mainnet.monadinfra.com',
242
+ 'https://rpc.monad.xyz',
243
+ 'https://rpc1.monad.xyz',
244
+ 'https://rpc2.monad.xyz',
245
+ 'https://rpc3.monad.xyz',
246
+ 'https://rpc4.monad.xyz',
247
+ ],
248
+ }
@@ -0,0 +1,17 @@
1
+ import { http, webSocket } from 'viem'
2
+
3
+ export function createTransport(url: string, config?: any) {
4
+ if (!url) throw new Error('URL is required for transport')
5
+ const retryConfig = {
6
+ ...config,
7
+ retryCount: config?.retryCount ?? 0, // this is critical, especially for multicall failures where the reason for failure is rpc realted issues
8
+ }
9
+ if (url.startsWith('wss://')) {
10
+ return webSocket(url, retryConfig)
11
+ }
12
+ return http(url, retryConfig)
13
+ }
14
+
15
+ export function getTransport(url: string) {
16
+ return createTransport(url)
17
+ }
@@ -0,0 +1,47 @@
1
+ export const DEFAULT_BATCH_SIZE = 4096
2
+
3
+ export function trimTrailingSlash(url?: string) {
4
+ if (!url) return undefined
5
+ return url.endsWith('/') ? url.slice(0, -1) : url
6
+ }
7
+
8
+ export function deepCompare(a: any, b: any): boolean {
9
+ if (a === b) return true
10
+
11
+ if (a == null || b == null) return false
12
+
13
+ const typeA = typeof a
14
+ const typeB = typeof b
15
+
16
+ if (typeA !== typeB) return false
17
+
18
+ if (typeA === 'bigint') return false
19
+
20
+ if (typeA !== 'object') return false
21
+
22
+ const isArrayA = Array.isArray(a)
23
+ const isArrayB = Array.isArray(b)
24
+
25
+ if (isArrayA !== isArrayB) return false
26
+
27
+ if (isArrayA) {
28
+ if (a.length !== b.length) return false
29
+ for (let i = 0; i < a.length; i++) {
30
+ if (!deepCompare(a[i], b[i])) return false
31
+ }
32
+ return true
33
+ }
34
+
35
+ const keysA = Object.keys(a)
36
+ const keysB = Object.keys(b)
37
+
38
+ if (keysA.length !== keysB.length) return false
39
+
40
+ for (let i = 0; i < keysA.length; i++) {
41
+ const key = keysA[i]
42
+ if (!Object.prototype.hasOwnProperty.call(b, key)) return false
43
+ if (!deepCompare(a[key], b[key])) return false
44
+ }
45
+
46
+ return true
47
+ }