From d57a63ce3f3ae640cf9c9ef39799c038af973ad8 Mon Sep 17 00:00:00 2001 From: Ben Goldberg Date: Thu, 16 Nov 2023 15:45:35 -0500 Subject: [PATCH] RPC Proxy (#5169) * progress * use remote flag * types * put back config --- globals.d.ts | 4 +++ src/env.ts | 16 +++++++++- src/handlers/web3.ts | 64 +++++++++++++++++++++++++++------------- src/model/config.ts | 9 +++--- src/networks/arbitrum.ts | 4 +-- src/networks/base.ts | 4 +-- src/networks/bsc.ts | 4 +-- src/networks/goerli.ts | 4 +-- src/networks/mainnet.ts | 4 +-- src/networks/optimism.ts | 4 +-- src/networks/polygon.ts | 4 +-- src/networks/zora.ts | 4 +-- 12 files changed, 84 insertions(+), 41 deletions(-) diff --git a/globals.d.ts b/globals.d.ts index f6628687064..d3d8fcd2ea6 100644 --- a/globals.d.ts +++ b/globals.d.ts @@ -90,4 +90,8 @@ declare module 'react-native-dotenv' { export const ARC_GRAPHQL_API_KEY: string; export const RESERVOIR_API_KEY_PROD: string; export const RESERVOIR_API_KEY_DEV: string; + export const RPC_PROXY_BASE_URL_PROD: string; + export const RPC_PROXY_BASE_URL_DEV: string; + export const RPC_PROXY_API_KEY_PROD: string; + export const RPC_PROXY_API_KEY_DEV: string; } diff --git a/src/env.ts b/src/env.ts index 9024d4f8dd4..534dfd72bb8 100644 --- a/src/env.ts +++ b/src/env.ts @@ -1,5 +1,12 @@ import ReactNative from 'react-native'; -import { ENABLE_DEV_MODE, IS_TESTING } from 'react-native-dotenv'; +import { + ENABLE_DEV_MODE, + IS_TESTING, + RPC_PROXY_BASE_URL_PROD, + RPC_PROXY_BASE_URL_DEV, + RPC_PROXY_API_KEY_PROD, + RPC_PROXY_API_KEY_DEV, +} from 'react-native-dotenv'; /** * @deprecated use IS_ANDROID @@ -21,3 +28,10 @@ export const IS_DEV = (typeof __DEV__ === 'boolean' && __DEV__) || !!Number(ENABLE_DEV_MODE); export const IS_TEST = IS_TESTING === 'true'; export const IS_PROD = !IS_DEV && !IS_TEST; + +export const RPC_PROXY_BASE_URL = IS_PROD + ? RPC_PROXY_BASE_URL_PROD + : RPC_PROXY_BASE_URL_DEV; +export const RPC_PROXY_API_KEY = IS_PROD + ? RPC_PROXY_API_KEY_PROD + : RPC_PROXY_API_KEY_DEV; diff --git a/src/handlers/web3.ts b/src/handlers/web3.ts index 9c70766dc3f..0ac99fedd3f 100644 --- a/src/handlers/web3.ts +++ b/src/handlers/web3.ts @@ -13,7 +13,7 @@ import { import { parseEther } from '@ethersproject/units'; import Resolution from '@unstoppabledomains/resolution'; import { startsWith } from 'lodash'; -import { RainbowConfig } from '../model/config'; +import config from '@/model/config'; import { AssetType, NewTransaction, ParsedAddressAsset } from '@/entities'; import { isNativeAsset } from '@/handlers/assets'; import { Network } from '@/helpers/networkTypes'; @@ -41,7 +41,7 @@ import { } from '@/helpers/utilities'; import { ethereumUtils } from '@/utils'; import { logger, RainbowError } from '@/logger'; -import { IS_IOS } from '@/env'; +import { IS_IOS, RPC_PROXY_API_KEY, RPC_PROXY_BASE_URL } from '@/env'; import { getNetworkObj } from '@/networks'; export enum TokenStandard { @@ -53,7 +53,40 @@ export const networkProviders: { [network in Network]?: StaticJsonRpcProvider; } = {}; -const rpcEndpoints: { [network in Network]?: string } = {}; +/** + * Creates an rpc endpoint for a given chain id using the Rainbow rpc proxy. + * If the firebase config flag is disabled, it will fall back to the deprecated rpc. + */ +export const proxyRpcEndpoint = (chainId: number, customEndpoint?: string) => { + if (config.rpc_proxy_enabled) { + return `${RPC_PROXY_BASE_URL}/${chainId}/${RPC_PROXY_API_KEY}${ + customEndpoint ? `?custom_rpc=${encodeURIComponent(customEndpoint)}` : '' + }`; + } else { + if (customEndpoint) return customEndpoint; + const network = ethereumUtils.getNetworkFromChainId(chainId); + switch (network) { + case Network.arbitrum: + return config.arbitrum_mainnet_rpc; + case Network.goerli: + return config.ethereum_goerli_rpc; + case Network.optimism: + return config.optimism_mainnet_rpc; + case Network.polygon: + return config.polygon_mainnet_rpc; + case Network.base: + return config.base_mainnet_rpc; + case Network.bsc: + return config.bsc_mainnet_rpc; + case Network.zora: + return config.zora_mainnet_rpc; + case Network.gnosis: + case Network.mainnet: + default: + return config.ethereum_mainnet_rpc; + } + } +}; /** * Gas parameter types returned by `getTransactionGasParams`. @@ -102,21 +135,6 @@ type NewTransactionNonNullable = { [key in keyof NewTransaction]-?: NonNullable; }; -/** - * @desc Configures `rpcEndpoints` based on a given `RainbowConfig`. - * @param config The `RainbowConfig` to use. - */ -export const setRpcEndpoints = (config: RainbowConfig): void => { - rpcEndpoints[Network.mainnet] = config.ethereum_mainnet_rpc; - rpcEndpoints[Network.goerli] = config.ethereum_goerli_rpc; - rpcEndpoints[Network.optimism] = config.optimism_mainnet_rpc; - rpcEndpoints[Network.arbitrum] = config.arbitrum_mainnet_rpc; - rpcEndpoints[Network.polygon] = config.polygon_mainnet_rpc; - rpcEndpoints[Network.bsc] = config.bsc_mainnet_rpc; - rpcEndpoints[Network.zora] = config.zora_mainnet_rpc; - rpcEndpoints[Network.base] = config.base_mainnet_rpc; -}; - /** * @desc web3 http instance */ @@ -174,7 +192,10 @@ export const isTestnetNetwork = (network: Network): boolean => { // shoudl figure out better way to include this in networks export const getFlashbotsProvider = async () => { return new StaticJsonRpcProvider( - 'https://rpc.flashbots.net/?hint=hash&builder=flashbots&builder=f1b.io&builder=rsync&builder=beaverbuild.org&builder=builder0x69&builder=titan&builder=eigenphi&builder=boba-builder', + proxyRpcEndpoint( + 1, + 'https://rpc.flashbots.net/?hint=hash&builder=flashbots&builder=f1b.io&builder=rsync&builder=beaverbuild.org&builder=builder0x69&builder=titan&builder=eigenphi&builder=boba-builder' + ), Network.mainnet ); }; @@ -203,7 +224,10 @@ export const getProviderForNetwork = async ( return provider; } else { const chainId = getNetworkObj(network).id; - const provider = new StaticJsonRpcProvider(rpcEndpoints[network], chainId); + const provider = new StaticJsonRpcProvider( + getNetworkObj(network).rpc, + chainId + ); if (!networkProviders[network]) { networkProviders[network] = provider; } diff --git a/src/model/config.ts b/src/model/config.ts index b5b7446b158..8b45b38deed 100644 --- a/src/model/config.ts +++ b/src/model/config.ts @@ -20,7 +20,7 @@ import { getNetwork, saveNetwork, } from '@/handlers/localstorage/globalSettings'; -import { setRpcEndpoints, web3SetHttpProvider } from '@/handlers/web3'; +import { web3SetHttpProvider } from '@/handlers/web3'; import Logger from '@/utils/logger'; @@ -69,6 +69,7 @@ export interface RainbowConfig base_swaps_enabled: boolean; mints_enabled: boolean; points_enabled: boolean; + rpc_proxy_enabled: boolean; } const DEFAULT_CONFIG: RainbowConfig = { @@ -129,11 +130,11 @@ const DEFAULT_CONFIG: RainbowConfig = { base_swaps_enabled: false, mints_enabled: true, points_enabled: true, + rpc_proxy_enabled: true, }; // Initialize with defaults in case firebase doesn't respond const config: RainbowConfig = { ...DEFAULT_CONFIG }; -setRpcEndpoints(config); const init = async () => { try { @@ -183,7 +184,8 @@ const init = async () => { key === 'goerli_enabled' || key === 'base_swaps_enabled' || key === 'mints_enabled' || - key === 'points_enabled' + key === 'points_enabled' || + key === 'rpc_proxy_enabled' ) { config[key] = entry.asBoolean(); } else { @@ -198,7 +200,6 @@ const init = async () => { Logger.debug('CURRENT CONFIG', JSON.stringify(config, null, 2)); // UPDATE THE PROVIDER AFTER LOADING THE NEW CONFIG const currentNetwork = await getNetwork(); - setRpcEndpoints(config); web3SetHttpProvider(currentNetwork); saveNetwork(currentNetwork); } diff --git a/src/networks/arbitrum.ts b/src/networks/arbitrum.ts index 209e63e4dfe..8412907ee17 100644 --- a/src/networks/arbitrum.ts +++ b/src/networks/arbitrum.ts @@ -1,4 +1,4 @@ -import { getProviderForNetwork } from '@/handlers/web3'; +import { getProviderForNetwork, proxyRpcEndpoint } from '@/handlers/web3'; import { Network, NetworkProperties } from './types'; import { gasUtils } from '@/utils'; import { arbitrum } from '@wagmi/chains'; @@ -23,7 +23,7 @@ export const getArbitrumNetworkObject = (): NetworkProperties => { address: ARBITRUM_ETH_ADDRESS, }, - rpc: config.arbitrum_mainnet_rpc, + rpc: proxyRpcEndpoint(arbitrum.id), getProvider: getProviderForNetwork(Network.arbitrum), balanceCheckerAddress: '0x54A4E5800345c01455a7798E0D96438364e22723', diff --git a/src/networks/base.ts b/src/networks/base.ts index 9baeb369252..fdde7032871 100644 --- a/src/networks/base.ts +++ b/src/networks/base.ts @@ -1,4 +1,4 @@ -import { getProviderForNetwork } from '@/handlers/web3'; +import { getProviderForNetwork, proxyRpcEndpoint } from '@/handlers/web3'; import { Network, NetworkProperties } from './types'; import { gasUtils } from '@/utils'; import { base } from '@wagmi/chains'; @@ -24,7 +24,7 @@ export const getBaseNetworkObject = (): NetworkProperties => { address: BASE_ETH_ADDRESS, }, - rpc: config.base_mainnet_rpc, + rpc: proxyRpcEndpoint(base.id), getProvider: getProviderForNetwork(Network.base), balanceCheckerAddress: '0x1C8cFdE3Ba6eFc4FF8Dd5C93044B9A690b6CFf36', diff --git a/src/networks/bsc.ts b/src/networks/bsc.ts index 7e96ac47bf2..2eccac98a7b 100644 --- a/src/networks/bsc.ts +++ b/src/networks/bsc.ts @@ -1,4 +1,4 @@ -import { getProviderForNetwork } from '@/handlers/web3'; +import { getProviderForNetwork, proxyRpcEndpoint } from '@/handlers/web3'; import { Network, NetworkProperties } from './types'; import { gasUtils } from '@/utils'; import { bsc } from '@wagmi/chains'; @@ -26,7 +26,7 @@ export const getBSCNetworkObject = (): NetworkProperties => { }, // this should be refactored to have less deps - rpc: config.bsc_mainnet_rpc, + rpc: proxyRpcEndpoint(bsc.id), getProvider: getProviderForNetwork(Network.bsc), balanceCheckerAddress: '0x400A9f1Bb1Db80643C33710C2232A0D74EF5CFf1', diff --git a/src/networks/goerli.ts b/src/networks/goerli.ts index 771b45f5d3b..b54e36182c7 100644 --- a/src/networks/goerli.ts +++ b/src/networks/goerli.ts @@ -1,4 +1,4 @@ -import { getProviderForNetwork } from '@/handlers/web3'; +import { getProviderForNetwork, proxyRpcEndpoint } from '@/handlers/web3'; import { Network, NetworkProperties } from './types'; import { gasUtils } from '@/utils'; import { goerli } from '@wagmi/chains'; @@ -25,7 +25,7 @@ export const getGoerliNetworkObject = (): NetworkProperties => { // this should be refactored to have less deps getProvider: getProviderForNetwork(Network.goerli), - rpc: config.ethereum_goerli_rpc, + rpc: proxyRpcEndpoint(goerli.id), balanceCheckerAddress: '0xf3352813b612a2d198e437691557069316b84ebe', // features diff --git a/src/networks/mainnet.ts b/src/networks/mainnet.ts index 4948b6c3c51..e5baecece54 100644 --- a/src/networks/mainnet.ts +++ b/src/networks/mainnet.ts @@ -1,4 +1,4 @@ -import { getProviderForNetwork } from '@/handlers/web3'; +import { getProviderForNetwork, proxyRpcEndpoint } from '@/handlers/web3'; import { Network, NetworkProperties } from './types'; import { gasUtils } from '@/utils'; import { mainnet } from '@wagmi/chains'; @@ -25,7 +25,7 @@ export const getMainnetNetworkObject = (): NetworkProperties => { // this should be refactored to have less deps getProvider: getProviderForNetwork(Network.mainnet), - rpc: config.ethereum_mainnet_rpc, + rpc: proxyRpcEndpoint(mainnet.id), balanceCheckerAddress: '0x4dcf4562268dd384fe814c00fad239f06c2a0c2b', // features diff --git a/src/networks/optimism.ts b/src/networks/optimism.ts index b8bafc724a7..bd116d3ad90 100644 --- a/src/networks/optimism.ts +++ b/src/networks/optimism.ts @@ -1,4 +1,4 @@ -import { getProviderForNetwork } from '@/handlers/web3'; +import { getProviderForNetwork, proxyRpcEndpoint } from '@/handlers/web3'; import { Network, NetworkProperties } from './types'; import { gasUtils } from '@/utils'; import { optimism } from '@wagmi/chains'; @@ -24,7 +24,7 @@ export const getOptimismNetworkObject = (): NetworkProperties => { address: OPTIMISM_ETH_ADDRESS, }, - rpc: config.optimism_mainnet_rpc, + rpc: proxyRpcEndpoint(optimism.id), getProvider: getProviderForNetwork(Network.optimism), balanceCheckerAddress: '0x1C8cFdE3Ba6eFc4FF8Dd5C93044B9A690b6CFf36', diff --git a/src/networks/polygon.ts b/src/networks/polygon.ts index baf6129e467..48a3e50e004 100644 --- a/src/networks/polygon.ts +++ b/src/networks/polygon.ts @@ -1,4 +1,4 @@ -import { getProviderForNetwork } from '@/handlers/web3'; +import { getProviderForNetwork, proxyRpcEndpoint } from '@/handlers/web3'; import { Network, NetworkProperties } from './types'; import { gasUtils } from '@/utils'; import { polygon } from '@wagmi/chains'; @@ -25,7 +25,7 @@ export const getPolygonNetworkObject = (): NetworkProperties => { mainnetAddress: MATIC_MAINNET_ADDRESS, }, - rpc: config.polygon_mainnet_rpc, + rpc: proxyRpcEndpoint(polygon.id), getProvider: getProviderForNetwork(Network.polygon), balanceCheckerAddress: '0x54A4E5800345c01455a7798E0D96438364e22723', diff --git a/src/networks/zora.ts b/src/networks/zora.ts index 10a9ea41dd7..6a4fe5a6154 100644 --- a/src/networks/zora.ts +++ b/src/networks/zora.ts @@ -1,4 +1,4 @@ -import { getProviderForNetwork } from '@/handlers/web3'; +import { getProviderForNetwork, proxyRpcEndpoint } from '@/handlers/web3'; import { Network, NetworkProperties } from './types'; import { gasUtils } from '@/utils'; import { zora } from '@wagmi/chains'; @@ -24,7 +24,7 @@ export const getZoraNetworkObject = (): NetworkProperties => { address: ZORA_ETH_ADDRESS, }, - rpc: config.zora_mainnet_rpc, + rpc: proxyRpcEndpoint(zora.id), getProvider: getProviderForNetwork(Network.zora), balanceCheckerAddress: '0x1C8cFdE3Ba6eFc4FF8Dd5C93044B9A690b6CFf36',