import React, { createContext, forwardRef, useContext, useState, useEffect, } from 'react'; import { Just, Nothing } from 'folktale/maybe'; import * as azimuth from 'azimuth-js'; import Web3 from 'web3'; import { CONTRACT_ADDRESSES } from '../lib/contracts'; import { NETWORK_TYPES, chainIdToNetworkType } from '../lib/network'; import { isDevelopment } from '../lib/flags'; import { Grid } from 'indigo-react'; import View from 'components/View'; import Blinky from 'components/Blinky'; import detectEthereumProvider from '@metamask/detect-provider'; function _useNetwork(initialNetworkType = null) { const [networkType, setNetworkType] = useState(initialNetworkType); const [metamask, setMetamask] = useState(false); const [web3, setWeb3] = useState(Nothing()); const [contracts, setContracts] = useState(Nothing()); useEffect(() => { (async () => { // given a web3 provider and contract addresses, // build the web3 and contracts objects const initWeb3 = async (provider, contractAddresses) => { // use an in-window eth provider if possible const _provider = metamask ? window.ethereum : provider; const web3 = new Web3(_provider); let contracts = await azimuth.initContractsPartial( web3, contractAddresses.azimuth ); contracts = azimuth.contracts.newLinearStarRelease( contracts, web3, contractAddresses.linearSR ); contracts = azimuth.contracts.newConditionalStarRelease( contracts, web3, contractAddresses.conditionalSR ); contracts = azimuth.contracts.newDelegatedSending( contracts, web3, contractAddresses.delegatedSending ); setWeb3(Just(web3)); setContracts(Just(contracts)); return; }; switch (networkType) { case NETWORK_TYPES.LOCAL: { const protocol = isDevelopment ? 'ws' : 'wss'; const endpoint = `${protocol}://${document.location.hostname}:8545`; initWeb3( new Web3.providers.WebsocketProvider(endpoint), CONTRACT_ADDRESSES.DEV ); return; } case NETWORK_TYPES.GOERLI: { const endpoint = `https://goerli.infura.io/v3/${ import.meta.env.VITE_INFURA_ENDPOINT }`; initWeb3( new Web3.providers.HttpProvider(endpoint), CONTRACT_ADDRESSES.GOERLI ); return; } case NETWORK_TYPES.MAINNET: { const endpoint = `https://mainnet.infura.io/v3/${ import.meta.env.VITE_INFURA_ENDPOINT }`; initWeb3( new Web3.providers.HttpProvider(endpoint), CONTRACT_ADDRESSES.MAINNET ); return; } case NETWORK_TYPES.OFFLINE: default: { // NB (jtobin): // // The 'offline' network type targets the mainnet contracts, but does // not actually use a provider to connect. We use a web3 instance to // initalise the contracts, but the network itself is set to Nothing. // // We may want to offer the ability to select a target network for // transactions when offline. // Note: example.com:3456 doesn't actually point to anything, we just // need a provider to initialize the Web3 object initWeb3( new Web3.providers.HttpProvider('http://example.com:3456'), isDevelopment ? CONTRACT_ADDRESSES.DEV : CONTRACT_ADDRESSES.MAINNET ); setWeb3(Nothing()); // ^ overwrite the web3 object from initWeb3 with a Nothing // to indicate that there is no valid web3 connection return; } } })(); }, [networkType, metamask]); return { networkType, setNetworkType, setMetamask, web3, contracts }; } const NetworkContext = createContext(null); // provider export function NetworkProvider({ initialNetworkType, children }) { const value = _useNetwork(initialNetworkType); if (Just.hasInstance(value.contracts)) { return ( {children} ); } else { return ( Connecting... ); } } // hook consumer export function useNetwork() { return useContext(NetworkContext); } // hoc consumer export const withNetwork = Component => forwardRef((props, ref) => { return ( {value => } ); });