/ src / utils / marketsAndNetworksConfig.ts
marketsAndNetworksConfig.ts
  1  import { ChainId, ChainIdToNetwork } from '@aave/contract-helpers';
  2  import { StaticJsonRpcProvider } from '@ethersproject/providers';
  3  import { ProviderWithSend } from 'src/components/transactions/GovVote/temporary/VotingMachineService';
  4  
  5  import {
  6    CustomMarket,
  7    MarketDataType,
  8    marketsData as _marketsData,
  9  } from '../ui-config/marketsConfig';
 10  import {
 11    BaseNetworkConfig,
 12    ExplorerLinkBuilderConfig,
 13    ExplorerLinkBuilderProps,
 14    NetworkConfig,
 15    networkConfigs as _networkConfigs,
 16  } from '../ui-config/networksConfig';
 17  import { RotationProvider } from './rotationProvider';
 18  import { ServerJsonRpcProvider } from './ServerJsonRpcProvider';
 19  
 20  export type Pool = {
 21    address: string;
 22  };
 23  
 24  export const STAGING_ENV = process.env.NEXT_PUBLIC_ENV === 'staging';
 25  export const PROD_ENV = !process.env.NEXT_PUBLIC_ENV || process.env.NEXT_PUBLIC_ENV === 'prod';
 26  export const ENABLE_TESTNET =
 27    PROD_ENV && global?.window?.localStorage.getItem('testnetsEnabled') === 'true';
 28  
 29  // determines if forks should be shown
 30  export const FORK_ENABLED =
 31    !!process.env.NEXT_PUBLIC_FORK_URL_RPC ||
 32    global?.window?.localStorage.getItem('forkEnabled') === 'true';
 33  // specifies which network was forked
 34  export const FORK_BASE_CHAIN_ID =
 35    Number(process.env.NEXT_PUBLIC_FORK_BASE_CHAIN_ID) ||
 36    Number(global?.window?.localStorage.getItem('forkBaseChainId') || 1);
 37  // specifies on which chainId the fork is running
 38  export const FORK_CHAIN_ID =
 39    Number(process.env.NEXT_PUBLIC_FORK_CHAIN_ID) ||
 40    Number(global?.window?.localStorage.getItem('forkNetworkId') || 3030);
 41  export const FORK_RPC_URL =
 42    process.env.NEXT_PUBLIC_FORK_URL_RPC ||
 43    global?.window?.localStorage.getItem('forkRPCUrl') ||
 44    'http://127.0.0.1:8545';
 45  
 46  /**
 47   * Generates network configs based on networkConfigs & fork settings.
 48   * Forks will have a rpcOnly clone of their underlying base network config.
 49   */
 50  export const networkConfigs = Object.keys(_networkConfigs).reduce((acc, value) => {
 51    acc[value] = _networkConfigs[value];
 52    if (FORK_ENABLED && Number(value) === FORK_BASE_CHAIN_ID) {
 53      acc[FORK_CHAIN_ID] = {
 54        ..._networkConfigs[value],
 55        name: `${_networkConfigs[value].name} Fork`,
 56        isFork: true,
 57        publicJsonRPCUrl: [FORK_RPC_URL],
 58        underlyingChainId: FORK_BASE_CHAIN_ID,
 59      };
 60    }
 61    return acc;
 62  }, {} as { [key: string]: BaseNetworkConfig });
 63  
 64  /**
 65   * Generates network configs based on marketsData & fork settings.
 66   * Fork markets are generated for all markets on the underlying base chain.
 67   */
 68  
 69  export const marketsData = Object.keys(_marketsData).reduce((acc, value) => {
 70    acc[value] = _marketsData[value as keyof typeof CustomMarket];
 71    if (
 72      FORK_ENABLED &&
 73      _marketsData[value as keyof typeof CustomMarket].chainId === FORK_BASE_CHAIN_ID
 74    ) {
 75      acc[`fork_${value}`] = {
 76        ..._marketsData[value as keyof typeof CustomMarket],
 77        chainId: FORK_CHAIN_ID,
 78        isFork: true,
 79      };
 80    }
 81    return acc;
 82  }, {} as { [key: string]: MarketDataType });
 83  
 84  export function getDefaultChainId() {
 85    return marketsData[availableMarkets[0]].chainId;
 86  }
 87  
 88  export function getSupportedChainIds(): number[] {
 89    return Array.from(
 90      Object.keys(marketsData)
 91        .filter((value) => {
 92          const isTestnet =
 93            networkConfigs[marketsData[value as keyof typeof CustomMarket].chainId].isTestnet;
 94  
 95          // If this is a staging environment, or the testnet toggle is on, only show testnets
 96          if (STAGING_ENV || ENABLE_TESTNET) {
 97            return isTestnet;
 98          }
 99  
100          return !isTestnet;
101        })
102        .reduce(
103          (acc, value) => acc.add(marketsData[value as keyof typeof CustomMarket].chainId),
104          new Set<number>()
105        )
106    );
107  }
108  
109  /**
110   * selectable markets (markets in a available network + forks when enabled)
111   */
112  
113  export const availableMarkets = Object.keys(marketsData).filter((key) =>
114    getSupportedChainIds().includes(marketsData[key as keyof typeof CustomMarket].chainId)
115  ) as CustomMarket[];
116  
117  const linkBuilder =
118    ({ baseUrl, addressPrefix = 'address', txPrefix = 'tx' }: ExplorerLinkBuilderConfig) =>
119    ({ tx, address }: ExplorerLinkBuilderProps): string => {
120      if (tx) {
121        return `${baseUrl}/${txPrefix}/${tx}`;
122      }
123      if (address) {
124        return `${baseUrl}/${addressPrefix}/${address}`;
125      }
126      return baseUrl;
127    };
128  
129  export function getNetworkConfig(chainId: ChainId): NetworkConfig {
130    const config = networkConfigs[chainId];
131    if (!config) {
132      // this case can only ever occure when a wallet is connected with a unknown chainId which will not allow interaction
133      const name = ChainIdToNetwork[chainId];
134      return {
135        name: name || `unknown chainId: ${chainId}`,
136      } as unknown as NetworkConfig;
137    }
138    return {
139      ...config,
140      explorerLinkBuilder: linkBuilder({ baseUrl: config.explorerLink }),
141    };
142  }
143  
144  export const isFeatureEnabled = {
145    faucet: (data: MarketDataType) => data.enabledFeatures?.faucet,
146    governance: (data: MarketDataType) => data.enabledFeatures?.governance,
147    staking: (data: MarketDataType) => data.enabledFeatures?.staking,
148    liquiditySwap: (data: MarketDataType) => data.enabledFeatures?.liquiditySwap,
149    collateralRepay: (data: MarketDataType) => data.enabledFeatures?.collateralRepay,
150    permissions: (data: MarketDataType) => data.enabledFeatures?.permissions,
151    debtSwitch: (data: MarketDataType) => data.enabledFeatures?.debtSwitch,
152    withdrawAndSwitch: (data: MarketDataType) => data.enabledFeatures?.withdrawAndSwitch,
153    switch: (data: MarketDataType) => data.enabledFeatures?.switch,
154  };
155  
156  const providers: { [network: string]: ProviderWithSend } = {};
157  
158  /**
159   * Created a fallback rpc provider in which providers are prioritized from private to public and in case there are multiple public ones, from top to bottom.
160   * @param chainId
161   * @returns provider or fallbackprovider in case multiple rpcs are configured
162   */
163  export const getProvider = (chainId: ChainId): ProviderWithSend => {
164    if (!providers[chainId]) {
165      const config = getNetworkConfig(chainId);
166      if (
167        (FORK_ENABLED && FORK_BASE_CHAIN_ID === chainId) ||
168        process.env.NEXT_PUBLIC_PRIVATE_RPC_ENABLED !== 'true'
169      ) {
170        // No private RPC or there is a fork configured, use public ones directly
171        const chainProviders: string[] = [];
172        if (config.publicJsonRPCUrl.length) {
173          config.publicJsonRPCUrl.map((rpc) => chainProviders.push(rpc));
174        }
175        if (!chainProviders.length) {
176          throw new Error(`${chainId} has no jsonRPCUrl configured`);
177        }
178        if (chainProviders.length === 1) {
179          providers[chainId] = new StaticJsonRpcProvider(chainProviders[0], chainId);
180        } else {
181          providers[chainId] = new RotationProvider(chainProviders, chainId);
182        }
183      } else {
184        providers[chainId] = new ServerJsonRpcProvider(chainId);
185      }
186    }
187    return providers[chainId];
188  };
189  
190  export const getENSProvider = () => {
191    const chainId = 1;
192    const config = getNetworkConfig(chainId);
193    return new StaticJsonRpcProvider(config.publicJsonRPCUrl[0], chainId);
194  };
195  
196  const ammDisableProposal = 'https://governance-v2.aave.com/governance/proposal/44';
197  const ustDisableProposal = 'https://governance-v2.aave.com/governance/proposal/75';
198  const kncDisableProposal = 'https://governance-v2.aave.com/governance/proposal/69';
199  const v2MainnetDisableProposal = 'https://governance-v2.aave.com/governance/proposal/111';
200  const v2MainnetDisableProposal2 = 'https://governance-v2.aave.com/governance/proposal/125';
201  const v2PolygonDisableProposal = 'https://governance-v2.aave.com/governance/proposal/124';
202  
203  export const frozenProposalMap: Record<string, string> = {
204    ['UST' + CustomMarket.proto_mainnet]: ustDisableProposal,
205    ['KNC' + CustomMarket.proto_mainnet]: kncDisableProposal,
206    ['UNIDAIUSDC' + CustomMarket.proto_mainnet]: ammDisableProposal,
207    ['UNIWBTCUSDC' + CustomMarket.proto_mainnet]: ammDisableProposal,
208    ['UNIDAIWETH' + CustomMarket.proto_mainnet]: ammDisableProposal,
209    ['UNIUSDCWETH' + CustomMarket.proto_mainnet]: ammDisableProposal,
210    ['UNIAAVEWETH' + CustomMarket.proto_mainnet]: ammDisableProposal,
211    ['UNIBATWETH' + CustomMarket.proto_mainnet]: ammDisableProposal,
212    ['UNICRVWETH' + CustomMarket.proto_mainnet]: ammDisableProposal,
213    ['UNILINKWETH' + CustomMarket.proto_mainnet]: ammDisableProposal,
214    ['UNIMKRWETH' + CustomMarket.proto_mainnet]: ammDisableProposal,
215    ['UNIRENWETH' + CustomMarket.proto_mainnet]: ammDisableProposal,
216    ['UNISNXWETH' + CustomMarket.proto_mainnet]: ammDisableProposal,
217    ['UNIUNIWETH' + CustomMarket.proto_mainnet]: ammDisableProposal,
218    ['UNIWBTCWETH' + CustomMarket.proto_mainnet]: ammDisableProposal,
219    ['UNIYFIWETH' + CustomMarket.proto_mainnet]: ammDisableProposal,
220    ['BPTWBTCWETH' + CustomMarket.proto_mainnet]: ammDisableProposal,
221    ['BPTBALWETH' + CustomMarket.proto_mainnet]: ammDisableProposal,
222    ['BAL' + CustomMarket.proto_mainnet]: v2MainnetDisableProposal,
223    ['CVX' + CustomMarket.proto_mainnet]: v2MainnetDisableProposal,
224    ['REN' + CustomMarket.proto_mainnet]: v2MainnetDisableProposal,
225    ['YFI' + CustomMarket.proto_mainnet]: v2MainnetDisableProposal2,
226    ['CRV' + CustomMarket.proto_mainnet]: v2MainnetDisableProposal2,
227    ['ZRX' + CustomMarket.proto_mainnet]: v2MainnetDisableProposal2,
228    ['MANA' + CustomMarket.proto_mainnet]: v2MainnetDisableProposal2,
229    ['1INCH' + CustomMarket.proto_mainnet]: v2MainnetDisableProposal2,
230    ['BAT' + CustomMarket.proto_mainnet]: v2MainnetDisableProposal2,
231    ['SUSD' + CustomMarket.proto_mainnet]: v2MainnetDisableProposal2,
232    ['ENJ' + CustomMarket.proto_mainnet]: v2MainnetDisableProposal2,
233    ['GUSD' + CustomMarket.proto_mainnet]: v2MainnetDisableProposal2,
234    ['AMPL' + CustomMarket.proto_mainnet]: v2MainnetDisableProposal2,
235    ['RAI' + CustomMarket.proto_mainnet]: v2MainnetDisableProposal2,
236    ['USDP' + CustomMarket.proto_mainnet]: v2MainnetDisableProposal2,
237    ['LUSD' + CustomMarket.proto_mainnet]: v2MainnetDisableProposal2,
238    ['XSUSHI' + CustomMarket.proto_mainnet]: v2MainnetDisableProposal2,
239    ['DPI' + CustomMarket.proto_mainnet]: v2MainnetDisableProposal2,
240    ['RENFIL' + CustomMarket.proto_mainnet]: v2MainnetDisableProposal2,
241    ['MKR' + CustomMarket.proto_mainnet]: v2MainnetDisableProposal2,
242    ['ENS' + CustomMarket.proto_mainnet]: v2MainnetDisableProposal2,
243    ['LINK' + CustomMarket.proto_mainnet]: v2MainnetDisableProposal2,
244    ['UNI' + CustomMarket.proto_mainnet]: v2MainnetDisableProposal2,
245    ['SNX' + CustomMarket.proto_mainnet]: v2MainnetDisableProposal2,
246    ['BAL' + CustomMarket.proto_polygon]: v2PolygonDisableProposal,
247    ['CRV' + CustomMarket.proto_polygon]: v2PolygonDisableProposal,
248    ['DPI' + CustomMarket.proto_polygon]: v2PolygonDisableProposal,
249    ['GHST' + CustomMarket.proto_polygon]: v2PolygonDisableProposal,
250    ['LINK' + CustomMarket.proto_polygon]: v2PolygonDisableProposal,
251    ['XSUSHI' + CustomMarket.proto_polygon]: v2PolygonDisableProposal,
252  };
253  
254  // reexport so we can forbit config import
255  export { CustomMarket };
256  export type { MarketDataType, NetworkConfig };