@1delta/providers 0.0.41 → 0.0.43

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.
@@ -0,0 +1,250 @@
1
+ import {
2
+ BaseError,
3
+ ContractFunctionExecutionError,
4
+ ContractFunctionRevertedError,
5
+ } from 'viem'
6
+ import { LIST_OVERRIDES } from '../rpc/rpcOverrides'
7
+ import { getEvmClientWithCustomRpcsUniversal } from '../client/client'
8
+ import { DEFAULT_BATCH_SIZE, deepCompare, isArray } from '../utils/utils'
9
+
10
+ /** Return true if it is a revert case */
11
+ function isContractRevert(e: unknown): boolean {
12
+ if (!(e instanceof BaseError)) return false
13
+
14
+ // Walk the cause chain
15
+ let err: BaseError | null = e
16
+ while (err) {
17
+ // Strong signal
18
+ if (err instanceof ContractFunctionRevertedError) return true
19
+
20
+ // Weaker but common signal
21
+ if (
22
+ err.name === 'ContractFunctionRevertedError' ||
23
+ err.message?.toLowerCase().includes('execution reverted')
24
+ ) {
25
+ return true
26
+ }
27
+
28
+ err = err.cause instanceof BaseError ? err.cause : null
29
+ }
30
+
31
+ return false
32
+ }
33
+
34
+ export interface MulticallRetryParams {
35
+ chain: string
36
+ calls: any[]
37
+ abi: any
38
+ batchSize?: number
39
+ maxRetries?: number
40
+ providerId?: number
41
+ allowFailure?: boolean
42
+ overrdies?: Record<string, string[]>
43
+ logErrors?: boolean
44
+ }
45
+
46
+ export function createMulticallRetry(
47
+ customRpcs: Record<string, string[]> = LIST_OVERRIDES,
48
+ ) {
49
+ return async function multicallRetry(
50
+ chain: string,
51
+ calls: any[],
52
+ abi: any,
53
+ batchSize = DEFAULT_BATCH_SIZE,
54
+ maxRetries = 3,
55
+ providerId = 0,
56
+ allowFailure = true,
57
+ logErrors = false,
58
+ revertedIndices: Set<number> = new Set(),
59
+ ): Promise<any[]> {
60
+ const abiIsArray = isArray(abi[0])
61
+
62
+ try {
63
+ const nonRevertedIndices = calls
64
+ .map((_, i) => i)
65
+ .filter((i) => !revertedIndices.has(i))
66
+
67
+ const filteredCalls = nonRevertedIndices.map((i) => calls[i])
68
+ const filteredAbi = abiIsArray
69
+ ? nonRevertedIndices.map((i) => abi[i])
70
+ : abi
71
+
72
+ const provider = getEvmClientWithCustomRpcsUniversal({
73
+ chain,
74
+ rpcId: providerId,
75
+ customRpcs,
76
+ })
77
+ const data = await provider.multicall({
78
+ batchSize,
79
+ contracts: filteredCalls.map((call, i) => ({
80
+ abi: abiIsArray ? filteredAbi[i] : filteredAbi,
81
+ address: call.address as any,
82
+ functionName: call.name,
83
+ args: call.args ?? call.params ?? [],
84
+ })),
85
+ allowFailure: false,
86
+ })
87
+
88
+ if (revertedIndices.size > 0) {
89
+ const finalResults: any[] = []
90
+ let filteredIndex = 0
91
+
92
+ for (let i = 0; i < calls.length; i++) {
93
+ if (revertedIndices.has(i)) {
94
+ finalResults.push('0x')
95
+ } else {
96
+ finalResults.push(data[filteredIndex++])
97
+ }
98
+ }
99
+ return finalResults
100
+ }
101
+
102
+ return data
103
+ } catch (e) {
104
+ if (isContractRevert(e)) {
105
+ const error = e as ContractFunctionExecutionError
106
+ const errorAddress = (error as any).contractAddress?.toLowerCase()
107
+ const errorFunctionName = error.functionName
108
+ const errorArgs = (error as any).args
109
+
110
+ const nonRevertedIndices = calls
111
+ .map((_, i) => i)
112
+ .filter((i) => !revertedIndices.has(i))
113
+
114
+ const matchingIndices: number[] = []
115
+ for (let i = 0; i < nonRevertedIndices.length; i++) {
116
+ const originalIndex = nonRevertedIndices[i]
117
+ const call = calls[originalIndex]
118
+ const callAddress = call.address?.toLowerCase()
119
+ const callFunctionName = call.name
120
+ const callArgs = call.args ?? call.params ?? []
121
+
122
+ const addressMatch = errorAddress && callAddress === errorAddress
123
+ const functionMatch = errorFunctionName === callFunctionName
124
+ const argsMatch = deepCompare(errorArgs, callArgs)
125
+
126
+ if (addressMatch && functionMatch && argsMatch) {
127
+ matchingIndices.push(originalIndex)
128
+ }
129
+ }
130
+
131
+ if (matchingIndices.length > 0) {
132
+ const newRevertedIndices = new Set(revertedIndices)
133
+ matchingIndices.forEach((idx) => newRevertedIndices.add(idx))
134
+
135
+ if (newRevertedIndices.size === calls.length) {
136
+ return Array(calls.length).fill('0x')
137
+ }
138
+
139
+ return await multicallRetry(
140
+ chain,
141
+ calls,
142
+ abi,
143
+ batchSize,
144
+ maxRetries,
145
+ providerId,
146
+ allowFailure,
147
+ logErrors,
148
+ newRevertedIndices,
149
+ )
150
+ }
151
+ }
152
+
153
+ if (maxRetries === 0) {
154
+ if (!allowFailure) throw e
155
+ if (logErrors) console.debug(e)
156
+ return Array(calls.length).fill('0x')
157
+ }
158
+
159
+ if (logErrors) console.debug(e)
160
+
161
+ return await multicallRetry(
162
+ chain,
163
+ calls,
164
+ abi,
165
+ batchSize,
166
+ maxRetries - 1,
167
+ providerId + 1,
168
+ allowFailure,
169
+ logErrors,
170
+ revertedIndices,
171
+ )
172
+ }
173
+ }
174
+ }
175
+
176
+ async function multicallRetryInternal(
177
+ chain: string,
178
+ calls: any[],
179
+ abi: any,
180
+ batchSize = DEFAULT_BATCH_SIZE,
181
+ maxRetries = 5,
182
+ providerId = 0,
183
+ allowFailure = false,
184
+ overrdies: Record<string, string[]> = LIST_OVERRIDES,
185
+ logErrors = false,
186
+ ) {
187
+ const defaultMulticallRetry = createMulticallRetry(overrdies)
188
+ return defaultMulticallRetry(
189
+ chain,
190
+ calls,
191
+ abi,
192
+ batchSize,
193
+ maxRetries,
194
+ providerId,
195
+ allowFailure,
196
+ logErrors,
197
+ )
198
+ }
199
+
200
+ /**
201
+ * @deprecated use multicallRetryUniversal instead
202
+ * @see multicallRetryUniversal
203
+ */
204
+ export async function multicallRetry(
205
+ chain: string,
206
+ calls: any[],
207
+ abi: any,
208
+ batchSize = DEFAULT_BATCH_SIZE,
209
+ maxRetries = 5,
210
+ providerId = 0,
211
+ allowFailure = false,
212
+ overrdies: Record<string, string[]> = LIST_OVERRIDES,
213
+ logErrors = false,
214
+ ) {
215
+ return multicallRetryInternal(
216
+ chain,
217
+ calls,
218
+ abi,
219
+ batchSize,
220
+ maxRetries,
221
+ providerId,
222
+ allowFailure,
223
+ overrdies,
224
+ logErrors,
225
+ )
226
+ }
227
+
228
+ export async function multicallRetryUniversal({
229
+ chain,
230
+ calls,
231
+ abi,
232
+ batchSize = DEFAULT_BATCH_SIZE,
233
+ maxRetries = 5,
234
+ providerId = 0,
235
+ allowFailure = false,
236
+ overrdies = LIST_OVERRIDES,
237
+ logErrors = false,
238
+ }: MulticallRetryParams) {
239
+ return multicallRetryInternal(
240
+ chain,
241
+ calls,
242
+ abi,
243
+ batchSize,
244
+ maxRetries,
245
+ providerId,
246
+ allowFailure,
247
+ overrdies,
248
+ logErrors,
249
+ )
250
+ }
@@ -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,55 @@
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
+ }
48
+
49
+ export function uniq<T>(array: T[]): T[] {
50
+ return [...new Set(array)]
51
+ }
52
+
53
+ export function isArray(value: any): boolean {
54
+ return Array.isArray(value)
55
+ }