diff --git a/CHANGELOG.md b/CHANGELOG.md index d08cf39cde..5359ae59e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## [1.5.8] - 2023.07.10 +### Changed +- Selected Archive/Non-Archive node for Ethereum RPC calls based on method + ## [1.5.7] - 2023.07.10 ### Changed - Extended JSON stringify to see error message in case of error to Loadbalancer diff --git a/package.json b/package.json index caa7f25af9..00d4e11106 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@tatumcom/js", - "version": "1.5.7", + "version": "1.5.8", "description": "Tatum JS SDK", "author": "Tatum", "repository": "https://github.com/tatumio/tatum-js", diff --git a/src/dto/Network.ts b/src/dto/Network.ts index aaf1b7dad0..907ce5954d 100644 --- a/src/dto/Network.ts +++ b/src/dto/Network.ts @@ -190,6 +190,8 @@ export const EVM_LOAD_BALANCER_NETWORKS = [ Network.HAQQ_TESTNET, Network.ETHEREUM, Network.ETHEREUM_SEPOLIA, + Network.POLYGON, + Network.POLYGON_MUMBAI, ] export const LOAD_BALANCER_NETWORKS = [ @@ -197,45 +199,32 @@ export const LOAD_BALANCER_NETWORKS = [ ...EVM_LOAD_BALANCER_NETWORKS, ] +export const EVM_ARCHIVE_NON_ARCHIVE_LOAD_BALANCER_NETWORKS = [ + Network.ETHEREUM, + Network.ETHEREUM_SEPOLIA, +] + export const SOLANA_NETWORKS = [Network.SOLANA, Network.SOLANA_DEVNET] export const TRON_NETWORKS = [Network.TRON, Network.TRON_SHASTA] -export const isEvmBasedNetwork = (network: Network) => { - return EVM_BASED_NETWORKS.includes(network) -} +export const isEvmBasedNetwork = (network: Network) => EVM_BASED_NETWORKS.includes(network) -export const isUtxoBasedNetwork = (network: Network) => { - return UTXO_BASED_NETWORKS.includes(network) -} +export const isUtxoBasedNetwork = (network: Network) => UTXO_BASED_NETWORKS.includes(network) -export const isXrpNetwork = (network: Network) => { - return [Network.XRP, Network.XRP_TESTNET].includes(network) -} +export const isXrpNetwork = (network: Network) => [Network.XRP, Network.XRP_TESTNET].includes(network) -export const isDataApiEvmEnabledNetwork = (network: Network) => { - return DATA_API_EVM_NETWORKS.includes(network) -} +export const isDataApiEvmEnabledNetwork = (network: Network) => DATA_API_EVM_NETWORKS.includes(network) -export const isDataApiUtxoEnabledNetwork = (network: Network) => { - return DATA_API_UTXO_NETWORKS.includes(network) -} +export const isDataApiUtxoEnabledNetwork = (network: Network) => DATA_API_UTXO_NETWORKS.includes(network) -export const isSolanaEnabledNetwork = (network: Network) => { - return SOLANA_NETWORKS.includes(network) -} +export const isSolanaEnabledNetwork = (network: Network) => SOLANA_NETWORKS.includes(network) -export const isTronNetwork = (network: Network) => { - return TRON_NETWORKS.includes(network) -} +export const isTronNetwork = (network: Network) => TRON_NETWORKS.includes(network) -export const isLoadBalancerNetwork = (network: Network) => { - return LOAD_BALANCER_NETWORKS.includes(network) -} +export const isLoadBalancerNetwork = (network: Network) => LOAD_BALANCER_NETWORKS.includes(network) -export const isUtxoLoadBalancerNetwork = (network: Network) => { - return UTXO_LOAD_BALANCER_NETWORKS.includes(network) -} +export const isUtxoLoadBalancerNetwork = (network: Network) => UTXO_LOAD_BALANCER_NETWORKS.includes(network) -export const isEvmLoadBalancerNetwork = (network: Network) => { - return EVM_LOAD_BALANCER_NETWORKS.includes(network) -} +export const isEvmLoadBalancerNetwork = (network: Network) => EVM_LOAD_BALANCER_NETWORKS.includes(network) + +export const isEvmArchiveNonArchiveLoadBalancerNetwork = (network: Network) => EVM_ARCHIVE_NON_ARCHIVE_LOAD_BALANCER_NETWORKS.includes(network) diff --git a/src/e2e/rpc/evm.e2e.utils.ts b/src/e2e/rpc/evm.e2e.utils.ts index a7023ac90a..80dd2e32dc 100644 --- a/src/e2e/rpc/evm.e2e.utils.ts +++ b/src/e2e/rpc/evm.e2e.utils.ts @@ -6,7 +6,7 @@ import { RpcE2eUtils } from './rpc.e2e.utils' export const EvmE2eUtils = { initTatum: async (network: Network) => TatumSDK.init(RpcE2eUtils.initConfig(network)), e2e: ({ network, chainId }: { network: Network; chainId: number }) => { - it('chain info', async () => { + it('eth_blockNumber', async () => { const tatum = await EvmE2eUtils.initTatum(network) const { data, status } = await tatum.rpc.blockNumber() @@ -15,7 +15,7 @@ export const EvmE2eUtils = { tatum.rpc.destroy() }) - it('chain id', async () => { + it('eth_chainId', async () => { const tatum = await EvmE2eUtils.initTatum(network) const { data, status } = await tatum.rpc.chainId() @@ -24,7 +24,7 @@ export const EvmE2eUtils = { tatum.rpc.destroy() }) - it('estimate gas', async () => { + it('eth_estimateGas', async () => { const tatum = await EvmE2eUtils.initTatum(network) const { data, status } = await tatum.rpc.estimateGas({ from: '0xb4c9E4617a16Be36B92689b9e07e9F64757c1792', @@ -37,7 +37,7 @@ export const EvmE2eUtils = { tatum.rpc.destroy() }) - it('gas price', async () => { + it('eth_gasPrice', async () => { const tatum = await EvmE2eUtils.initTatum(network) const { data, status } = await tatum.rpc.gasPrice() @@ -46,7 +46,7 @@ export const EvmE2eUtils = { tatum.rpc.destroy() }) - it('client version', async () => { + it('web3_clientVersion', async () => { const tatum = await EvmE2eUtils.initTatum(network) const { data, status } = await tatum.rpc.clientVersion() @@ -54,5 +54,15 @@ export const EvmE2eUtils = { expect(data).toBeTruthy() tatum.rpc.destroy() }) + + it('eth_getBlockByNumber', async () => { + const tatum = await EvmE2eUtils.initTatum(network) + const { data: blockNum } = await tatum.rpc.blockNumber() + const { data, status } = await tatum.rpc.getBlockByNumber(blockNum.toNumber()) + expect(status).toBe(Status.SUCCESS) + expect(data.timestamp).toBeDefined() + expect(data.size).toBeDefined() + tatum.rpc.destroy() + }) }, } diff --git a/src/e2e/rpc/rpc.e2e.utils.ts b/src/e2e/rpc/rpc.e2e.utils.ts index 791cbbdb31..0d61ea2cba 100644 --- a/src/e2e/rpc/rpc.e2e.utils.ts +++ b/src/e2e/rpc/rpc.e2e.utils.ts @@ -5,5 +5,8 @@ export const RpcE2eUtils = { network, retryCount: 1, retryDelay: 2000, + apiKey: { + v2: 't-647835e1930be3001cb53f81-647835e2930be3001cb53f87' + } }), } diff --git a/src/e2e/rpc/tatum.rpc.flare.spec.ts b/src/e2e/rpc/tatum.rpc.flare.spec.ts index 8494dbf9bc..4ca5719738 100644 --- a/src/e2e/rpc/tatum.rpc.flare.spec.ts +++ b/src/e2e/rpc/tatum.rpc.flare.spec.ts @@ -2,7 +2,7 @@ import { Network } from '../../service' import { EvmE2eUtils } from './evm.e2e.utils' //temporarily skipping Flare as RPC's are not available -describe.skip('Flare', () => { +describe('Flare', () => { describe('mainnet', () => { EvmE2eUtils.e2e({ network: Network.FLARE, chainId: 14 }) }) diff --git a/src/e2e/rpc/tatum.rpc.polygon.spec.ts b/src/e2e/rpc/tatum.rpc.polygon.spec.ts index 8320411732..517b3d4e54 100644 --- a/src/e2e/rpc/tatum.rpc.polygon.spec.ts +++ b/src/e2e/rpc/tatum.rpc.polygon.spec.ts @@ -6,7 +6,7 @@ describe('Polygon', () => { EvmE2eUtils.e2e({ network: Network.POLYGON, chainId: 137 }) }) - describe('mumbai', () => { + describe.skip('mumbai', () => { EvmE2eUtils.e2e({ network: Network.POLYGON_MUMBAI, chainId: 80001 }) }) }) diff --git a/src/service/address/address.ts b/src/service/address/address.ts index a38ef0be32..256981e789 100644 --- a/src/service/address/address.ts +++ b/src/service/address/address.ts @@ -10,7 +10,7 @@ import { isEvmBasedNetwork, } from '../../dto' import { CONFIG, Constant, ErrorUtils, ResponseDto, Utils } from '../../util' -import { EvmBasedRpc, GenericRpc } from '../rpc' +import { EvmRpc, GenericRpc } from '../rpc' import { Network, TatumConfig } from '../tatum' import { AddressBalance, AddressTransaction, GetAddressTransactionsQuery } from './address.dto' @@ -235,7 +235,7 @@ export class Address { private async getNativeBalance(addresses: string[]): Promise { const network = this.config.network if (isEvmBasedNetwork(network)) { - const rpc = Utils.getRpc(this.id, network) + const rpc = Utils.getRpc(this.id, network) const result = await Promise.all(addresses.map((a, i) => rpc.rawRpcCall(Utils.prepareRpcCall('eth_getBalance', [a, 'pending'], i)))) // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore diff --git a/src/service/rpc/evm/AbstractEvmBasedRpc.ts b/src/service/rpc/evm/AbstractEvmRpc.ts similarity index 99% rename from src/service/rpc/evm/AbstractEvmBasedRpc.ts rename to src/service/rpc/evm/AbstractEvmRpc.ts index e24c7b0577..d4265cf86c 100644 --- a/src/service/rpc/evm/AbstractEvmBasedRpc.ts +++ b/src/service/rpc/evm/AbstractEvmRpc.ts @@ -13,7 +13,7 @@ import { import { ErrorUtils, ResponseDto, ResponseUtils, Status } from '../../../util' @Service() -export abstract class AbstractEvmBasedRpc implements EvmBasedRpcInterface { +export abstract class AbstractEvmRpc implements EvmBasedRpcInterface { protected abstract rpcCall(method: string, params?: unknown[]): Promise async blockNumber(): Promise> { diff --git a/src/service/rpc/evm/EvmArchiveLoadBalancerRpc.ts b/src/service/rpc/evm/EvmArchiveLoadBalancerRpc.ts new file mode 100644 index 0000000000..08a88d7fa4 --- /dev/null +++ b/src/service/rpc/evm/EvmArchiveLoadBalancerRpc.ts @@ -0,0 +1,95 @@ +import { Container, Service } from 'typedi' +import { EvmBasedRpcSuite, JsonRpcCall, JsonRpcResponse } from '../../../dto' +import { LoadBalancerRpc } from '../generic/LoadBalancerRpc' +import { Utils } from '../../../util' +import { AbstractEvmRpc } from './AbstractEvmRpc' + +const ARCHIVE_METHODS = [ + // Archival information + 'debug_getBadBlocks', + 'debug_storageRangeAt', + 'debug_traceCall', + 'debug_traceTransaction', + 'debug_traceBlockByHash', + 'debug_traceBlockByNumber', + 'trace_block', + 'trace_call', + 'trace_callMany', + 'trace_rawTransaction', + 'trace_replayBlockTransactions', + // Network state + 'eth_getBlockByHash', + 'eth_getTransactionByHash', + 'eth_getTransactionReceipt', + 'eth_getUncleCountByBlockHash', + 'eth_getUncleCountByBlockNumber', + 'eth_getBlockByNumber', + 'eth_getBlockTransactionCountByHash', + 'eth_getBlockTransactionCountByNumber', + 'eth_getTransactionByBlockHashAndIndex', + 'eth_getTransactionByBlockNumberAndIndex', + 'eth_getTransactionCount', + 'eth_getProof', +] + +const POSSIBLE_ARCHIVE_METHODS = [ + // Network state + { method: 'eth_getStorageAt', index: 2 }, // second param block + { method: 'eth_call', index: 1 }, // second param block + { method: 'eth_getBalance', index: 1 }, // second param block + { method: 'eth_getCode', index: 1 }, // second param block +] + +@Service({ + factory: (data: { id: string }) => { + return new EvmArchiveLoadBalancerRpc(data.id) + }, + transient: true, +}) +export class EvmArchiveLoadBalancerRpc extends AbstractEvmRpc implements EvmBasedRpcSuite { + protected readonly loadBalancerRpc: LoadBalancerRpc + + constructor(id: string) { + super() + this.loadBalancerRpc = Container.of(id).get(LoadBalancerRpc) + } + + private isArchiveMethod(rpc: JsonRpcCall): boolean { + const isArchiveMethod = ARCHIVE_METHODS.includes(rpc.method) + if (isArchiveMethod) { + return true + } + + const possibleArchiveMethod = POSSIBLE_ARCHIVE_METHODS.find((possibleArchiveMethod) => possibleArchiveMethod.method === rpc.method) + if (possibleArchiveMethod) { + const param = rpc?.params?.[possibleArchiveMethod.index] + return !!param + } + + if (rpc.method === 'eth_getLogs') { + const param = rpc?.params?.[1] + return !!param?.fromBlock || !!param?.toBlock + } + + return false + } + + protected async rpcCall(method: string, params?: unknown[]): Promise { + const preparedCall = Utils.prepareRpcCall(method, params) + const isArchive = this.isArchiveMethod(preparedCall) + return (await this.loadBalancerRpc.rawRpcCall(preparedCall, isArchive)) as T + } + + async rawRpcCall(body: JsonRpcCall): Promise { + const isArchive = this.isArchiveMethod(body) + return this.loadBalancerRpc.rawRpcCall(body, isArchive) + } + + rawBatchRpcCall(body: JsonRpcCall[]): Promise { + return this.loadBalancerRpc.rawBatchRpcCall(body) + } + + public destroy() { + this.loadBalancerRpc.destroy() + } +} diff --git a/src/service/rpc/evm/EvmBasedLoadBalancerRpc.ts b/src/service/rpc/evm/EvmLoadBalancerRpc.ts similarity index 82% rename from src/service/rpc/evm/EvmBasedLoadBalancerRpc.ts rename to src/service/rpc/evm/EvmLoadBalancerRpc.ts index de671678fa..131a9c1dff 100644 --- a/src/service/rpc/evm/EvmBasedLoadBalancerRpc.ts +++ b/src/service/rpc/evm/EvmLoadBalancerRpc.ts @@ -2,15 +2,15 @@ import { Container, Service } from 'typedi' import { EvmBasedRpcSuite, JsonRpcCall, JsonRpcResponse } from '../../../dto' import { LoadBalancerRpc } from '../generic/LoadBalancerRpc' import { Utils } from '../../../util' -import { AbstractEvmBasedRpc } from './AbstractEvmBasedRpc' +import { AbstractEvmRpc } from './AbstractEvmRpc' @Service({ factory: (data: { id: string }) => { - return new EvmBasedLoadBalancerRpc(data.id) + return new EvmLoadBalancerRpc(data.id) }, transient: true, }) -export class EvmBasedLoadBalancerRpc extends AbstractEvmBasedRpc implements EvmBasedRpcSuite { +export class EvmLoadBalancerRpc extends AbstractEvmRpc implements EvmBasedRpcSuite { protected readonly loadBalancerRpc: LoadBalancerRpc constructor(id: string) { diff --git a/src/service/rpc/evm/EvmBasedRpc.ts b/src/service/rpc/evm/EvmRpc.ts similarity index 86% rename from src/service/rpc/evm/EvmBasedRpc.ts rename to src/service/rpc/evm/EvmRpc.ts index 571f332cc3..dbd10ec3d9 100644 --- a/src/service/rpc/evm/EvmBasedRpc.ts +++ b/src/service/rpc/evm/EvmRpc.ts @@ -6,15 +6,15 @@ import { } from '../../../dto' import { GenericRpc } from '../generic/GenericRpc' import { Utils } from '../../../util' -import { AbstractEvmBasedRpc } from './AbstractEvmBasedRpc' +import { AbstractEvmRpc } from './AbstractEvmRpc' @Service({ factory: (data: { id: string }) => { - return new EvmBasedRpc(data.id) + return new EvmRpc(data.id) }, transient: true, }) -export class EvmBasedRpc extends AbstractEvmBasedRpc { +export class EvmRpc extends AbstractEvmRpc { public readonly genericRpc: GenericRpc constructor(id: string) { diff --git a/src/service/rpc/evm/index.ts b/src/service/rpc/evm/index.ts index c89ca01f74..7dcc1dc800 100644 --- a/src/service/rpc/evm/index.ts +++ b/src/service/rpc/evm/index.ts @@ -1,2 +1,2 @@ -export * from './EvmBasedRpc' -export * from './EvmBasedLoadBalancerRpc' +export * from './EvmRpc' +export * from './EvmLoadBalancerRpc' diff --git a/src/service/rpc/generic/LoadBalancerRpc.ts b/src/service/rpc/generic/LoadBalancerRpc.ts index bac110c755..2db27660b1 100644 --- a/src/service/rpc/generic/LoadBalancerRpc.ts +++ b/src/service/rpc/generic/LoadBalancerRpc.ts @@ -203,19 +203,33 @@ export class LoadBalancerRpc implements AbstractRpcInterface { public getActiveArchiveUrlWithFallback() { const activeArchiveUrl = this.getActiveUrl(RpcNodeType.ARCHIVE) - if (activeArchiveUrl) { - return { url: activeArchiveUrl, type: RpcNodeType.ARCHIVE } + if (activeArchiveUrl?.url) { + return { url: activeArchiveUrl.url, type: RpcNodeType.ARCHIVE } } - if (this.getActiveUrl(RpcNodeType.NORMAL)) { - return { url: this.getActiveUrl(RpcNodeType.NORMAL), type: RpcNodeType.NORMAL } + if (this.getActiveUrl(RpcNodeType.NORMAL)?.url) { + return { url: this.getActiveUrl(RpcNodeType.NORMAL).url, type: RpcNodeType.NORMAL } } throw new Error('No active node found.') } - public getActiveUrl(nodeType: RpcNodeType): string { - return this.activeUrl[nodeType]?.url as string + + public getActiveNormalUrlWithFallback() { + const activeNormalUrl = this.getActiveUrl(RpcNodeType.NORMAL) + if (activeNormalUrl?.url) { + return { url: activeNormalUrl.url, type: RpcNodeType.NORMAL } + } + + if (this.getActiveUrl(RpcNodeType.ARCHIVE)?.url) { + return { url: this.getActiveUrl(RpcNodeType.ARCHIVE).url, type: RpcNodeType.ARCHIVE } + } + + throw new Error('No active node found.') + } + + public getActiveUrl(nodeType: RpcNodeType) { + return { url: this.activeUrl[nodeType]?.url as string, type: nodeType } } private getActiveIndex(nodeType: RpcNodeType): number { @@ -225,29 +239,31 @@ export class LoadBalancerRpc implements AbstractRpcInterface { private initRemoteHosts(nodeType: RpcNodeType, nodes: RpcNode[]) { const filteredNodes = nodes.filter((node) => node.type === nodeType) - const randomIndex = Math.floor(Math.random() * filteredNodes.length) - if (filteredNodes.length === 0) { - Utils.log({ - id: this.id, - message: `No ${nodeType} nodes found for ${this.network} blockchain.`, - }) return } - Utils.log({ - id: this.id, - message: `Using random URL ${filteredNodes[randomIndex].url} for ${this.network} blockchain during the initialization for node`, - }) - - this.activeUrl[nodeType] = { url: filteredNodes[randomIndex].url, index: randomIndex } + if (!this.rpcUrls[nodeType]) { + this.rpcUrls[nodeType] = []; + } - this.rpcUrls[nodeType] = filteredNodes.map((s) => ({ + this.rpcUrls[nodeType] = [...this.rpcUrls[nodeType], ...filteredNodes.map((s) => ({ node: { url: s.url }, lastBlock: 0, lastResponseTime: 0, failed: false, - })) + }))] + + const randomIndex = Math.floor(Math.random() * this.rpcUrls[nodeType].length) + + Utils.log({ + id: this.id, + message: `Using random URL ${this.rpcUrls[nodeType][randomIndex].node.url} for ${this.network} blockchain during the initialization for node ${nodeType}.`, + }) + + this.activeUrl[nodeType] = { url: this.rpcUrls[nodeType][randomIndex].node.url, index: randomIndex } + + } private async initRemoteHostsUrls() { @@ -257,13 +273,21 @@ export class LoadBalancerRpc implements AbstractRpcInterface { try { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore - const res = await fetch(rpcList) - if (res.ok) { - const nodes: RpcNode[] = await res.json() + const [normal, archive] = await Promise.all(rpcList.map((url) => fetch(url))) + if (normal.ok) { + const nodes: RpcNode[] = await normal.json() this.initRemoteHosts(RpcNodeType.NORMAL, nodes) this.initRemoteHosts(RpcNodeType.ARCHIVE, nodes) } else { - console.error(new Date().toISOString(), `Failed to fetch RPC configuration for ${network} blockchain`) + console.error(new Date().toISOString(), `Failed to fetch RPC configuration for ${network} blockchain for normal nodes`) + } + + if (archive.ok) { + const nodes: RpcNode[] = await archive.json() + this.initRemoteHosts(RpcNodeType.NORMAL, nodes) + this.initRemoteHosts(RpcNodeType.ARCHIVE, nodes) + } else { + console.error(new Date().toISOString(), `Failed to fetch RPC configuration for ${network} blockchain for archive nodes`) } } catch (e) { console.error(new Date().toISOString(), `Failed to initialize RPC module. Error: ${JSON.stringify(e, Object.getOwnPropertyNames(e))}`) @@ -272,12 +296,18 @@ export class LoadBalancerRpc implements AbstractRpcInterface { async handleFailedRpcCall(rpcCall: JsonRpcCall | JsonRpcCall[], e: unknown, nodeType: RpcNodeType) { const { verbose, rpc: rpcConfig } = Container.of(this.id).get(CONFIG) - const url = this.getActiveUrl(nodeType) + const { url } = this.getActiveUrl(nodeType) const activeIndex = this.getActiveIndex(nodeType) if (verbose) { console.warn(new Date().toISOString(), `Failed to call RPC ${Array.isArray(rpcCall) ? 'methods' : rpcCall.method} on ${url}. Error: ${JSON.stringify(e, Object.getOwnPropertyNames(e))}`) console.log(new Date().toISOString(), `Switching to another server, marking this as unstable.`) } + + if (!activeIndex) { + console.error(`No active server found for ${nodeType} node.`) + throw e + } + /** * If the node is not responding, it will be marked as failed. * New node will be selected and will be used for the given blockchain. @@ -299,9 +329,13 @@ export class LoadBalancerRpc implements AbstractRpcInterface { this.activeUrl[nodeType] = { url: fastestServer.node.url, index } } - async rawRpcCall(rpcCall: JsonRpcCall): Promise { - const { url, type } = this.getActiveArchiveUrlWithFallback() + async rawRpcCall(rpcCall: JsonRpcCall, archive?: boolean): Promise { + const { url, type } = archive ? this.getActiveArchiveUrlWithFallback() : this.getActiveNormalUrlWithFallback() try { + Utils.log({ + id: this.id, + message: `Sending RPC ${rpcCall.method} to ${url} for ${this.network} blockchain node type ${type}.`, + }) return await this.connector.rpcCall(url, rpcCall) } catch (e) { await this.handleFailedRpcCall(rpcCall, e, type) diff --git a/src/service/rpc/utxo/AbstractUtxoBasedRpc.ts b/src/service/rpc/utxo/AbstractUtxoRpc.ts similarity index 98% rename from src/service/rpc/utxo/AbstractUtxoBasedRpc.ts rename to src/service/rpc/utxo/AbstractUtxoRpc.ts index d1fe572e2a..af7727487b 100644 --- a/src/service/rpc/utxo/AbstractUtxoBasedRpc.ts +++ b/src/service/rpc/utxo/AbstractUtxoRpc.ts @@ -2,7 +2,7 @@ import { JsonRpcResponse, UtxoBasedRpcInterface } from '../../../dto' import { ResponseDto, ResponseUtils } from '../../../util' -export abstract class AbstractUtxoBasedRpc implements UtxoBasedRpcInterface { +export abstract class AbstractUtxoRpc implements UtxoBasedRpcInterface { protected abstract rpcCall(method: string, params?: unknown[]): Promise async createRawTransaction( diff --git a/src/service/rpc/utxo/UtxoBasedLoadBalancerRpc.ts b/src/service/rpc/utxo/UtxoLoadBalancerRpc.ts similarity index 82% rename from src/service/rpc/utxo/UtxoBasedLoadBalancerRpc.ts rename to src/service/rpc/utxo/UtxoLoadBalancerRpc.ts index f91f4df3f2..9e0154cd69 100644 --- a/src/service/rpc/utxo/UtxoBasedLoadBalancerRpc.ts +++ b/src/service/rpc/utxo/UtxoLoadBalancerRpc.ts @@ -1,16 +1,16 @@ import { Container, Service } from 'typedi' import { JsonRpcCall, JsonRpcResponse, UtxoBasedRpcSuite } from '../../../dto' -import { AbstractUtxoBasedRpc } from './AbstractUtxoBasedRpc' +import { AbstractUtxoRpc } from './AbstractUtxoRpc' import { LoadBalancerRpc } from '../generic/LoadBalancerRpc' import { Utils } from '../../../util' @Service({ factory: (data: { id: string }) => { - return new UtxoBasedLoadBalancerRpc(data.id) + return new UtxoLoadBalancerRpc(data.id) }, transient: true, }) -export class UtxoBasedLoadBalancerRpc extends AbstractUtxoBasedRpc implements UtxoBasedRpcSuite { +export class UtxoLoadBalancerRpc extends AbstractUtxoRpc implements UtxoBasedRpcSuite { protected readonly loadBalancerRpc: LoadBalancerRpc constructor(id: string) { diff --git a/src/service/rpc/utxo/UtxoBasedRpc.ts b/src/service/rpc/utxo/UtxoRpc.ts similarity index 83% rename from src/service/rpc/utxo/UtxoBasedRpc.ts rename to src/service/rpc/utxo/UtxoRpc.ts index 8b51c7f77c..1f1adfbe33 100644 --- a/src/service/rpc/utxo/UtxoBasedRpc.ts +++ b/src/service/rpc/utxo/UtxoRpc.ts @@ -1,17 +1,17 @@ import { Container, Service } from 'typedi' import { JsonRpcCall, JsonRpcResponse, UtxoBasedRpcSuite } from '../../../dto' import { Utils } from '../../../util' -import { AbstractUtxoBasedRpc } from './AbstractUtxoBasedRpc' +import { AbstractUtxoRpc } from './AbstractUtxoRpc' import { GenericRpc } from '../generic' @Service({ factory: (data: { id: string }) => { - return new UtxoBasedRpc(data.id) + return new UtxoRpc(data.id) }, transient: true, }) -export class UtxoBasedRpc extends AbstractUtxoBasedRpc implements UtxoBasedRpcSuite { +export class UtxoRpc extends AbstractUtxoRpc implements UtxoBasedRpcSuite { public readonly genericRpc: GenericRpc constructor(id: string) { diff --git a/src/service/rpc/utxo/index.ts b/src/service/rpc/utxo/index.ts index 6adceed410..10f6c487bb 100644 --- a/src/service/rpc/utxo/index.ts +++ b/src/service/rpc/utxo/index.ts @@ -1,3 +1,3 @@ -export * from './AbstractUtxoBasedRpc' -export * from './UtxoBasedLoadBalancerRpc' -export * from './UtxoBasedRpc' +export * from './AbstractUtxoRpc' +export * from './UtxoLoadBalancerRpc' +export * from './UtxoRpc' diff --git a/src/service/walletProvider/metaMask.ts b/src/service/walletProvider/metaMask.ts index f9739da4c1..d5be3f2d2c 100644 --- a/src/service/walletProvider/metaMask.ts +++ b/src/service/walletProvider/metaMask.ts @@ -8,7 +8,7 @@ import { CreateNftCollection, } from '../../dto/walletProvider' import { CONFIG, Constant, Utils } from '../../util' -import { EvmBasedRpc } from '../rpc' +import { EvmRpc } from '../rpc' import { TatumConfig } from '../tatum' @Service({ @@ -17,7 +17,7 @@ import { TatumConfig } from '../tatum' }, transient: true, }) -export class MetaMask { +export class MetaMask { private readonly config: TatumConfig private readonly rpc: T private readonly connector: TatumConnector diff --git a/src/service/walletProvider/wallet.provider.ts b/src/service/walletProvider/wallet.provider.ts index 948bfb8446..54db22bb9a 100644 --- a/src/service/walletProvider/wallet.provider.ts +++ b/src/service/walletProvider/wallet.provider.ts @@ -1,6 +1,6 @@ import { Container, Service } from 'typedi' import { MetaMask } from './metaMask' -import { EvmBasedRpc } from '../rpc' +import { EvmRpc } from '../rpc' @Service({ factory: (data: { id: string }) => { @@ -9,7 +9,7 @@ import { EvmBasedRpc } from '../rpc' transient: true, }) export class WalletProvider { - readonly metaMask: MetaMask + readonly metaMask: MetaMask constructor(private readonly id: string) { this.metaMask = Container.of(this.id).get(MetaMask) diff --git a/src/util/util.shared.ts b/src/util/util.shared.ts index b4fe734d91..11974365e8 100644 --- a/src/util/util.shared.ts +++ b/src/util/util.shared.ts @@ -2,7 +2,7 @@ import { Container } from 'typedi' import { CONFIG } from './di.tokens' import { - AddressEventNotificationChain, + AddressEventNotificationChain, isEvmArchiveNonArchiveLoadBalancerNetwork, isEvmBasedNetwork, isEvmLoadBalancerNetwork, isSolanaEnabledNetwork, @@ -28,8 +28,8 @@ import { Dogecoin, Ethereum, EthereumClassic, - EvmBasedLoadBalancerRpc, - EvmBasedRpc, + EvmLoadBalancerRpc, + EvmRpc, Fantom, Flare, GenericRpc, Gnosis, @@ -46,32 +46,38 @@ import { SolanaRpc, Tron, TronRpc, - UtxoBasedLoadBalancerRpc, - UtxoBasedRpc, + UtxoLoadBalancerRpc, + UtxoRpc, Vechain, Xdc, Xrp, XrpRpc, } from '../service' import { BigNumber } from 'bignumber.js' +import { EvmArchiveLoadBalancerRpc } from '../service/rpc/evm/EvmArchiveLoadBalancerRpc' export const Utils = { getRpc: (id: string, network: Network): T => { if (isUtxoLoadBalancerNetwork(network)) { - return Container.of(id).get(UtxoBasedLoadBalancerRpc) as T + return Container.of(id).get(UtxoLoadBalancerRpc) as T + } + + if (isEvmArchiveNonArchiveLoadBalancerNetwork(network)) { + return Container.of(id).get(EvmArchiveLoadBalancerRpc) as T } if (isEvmLoadBalancerNetwork(network)) { - return Container.of(id).get(EvmBasedLoadBalancerRpc) as T + return Container.of(id).get(EvmLoadBalancerRpc) as T } if (isEvmBasedNetwork(network)) { - return Container.of(id).get(EvmBasedRpc) as T + return Container.of(id).get(EvmRpc) as T } if (isUtxoBasedNetwork(network)) { - return Container.of(id).get(UtxoBasedRpc) as T + return Container.of(id).get(UtxoRpc) as T } + if (isXrpNetwork(network)) { return Container.of(id).get(XrpRpc) as T } @@ -84,8 +90,8 @@ export const Utils = { console.warn(`RPC Network ${network} is not supported.`) return Container.of(id).get(GenericRpc) as T }, - getRpcListUrl: (network: Network): string => { - return `https://rpc.tatum.com/${network}/list.json` + getRpcListUrl: (network: Network): string[] => { + return [`https://rpc.tatum.com/${network}/list.json`, `https://rpc.tatum.com/${network}-archive/list.json`] }, getStatusPayload: (network: Network) => { if (isUtxoBasedNetwork(network)) {