import BigNumber from 'bignumber.js'; import { Contract, ContractInterface, providers } from 'ethers'; import { ErrorCodes } from './common/errors/error-codes'; import { UniswapError } from './common/errors/uniswap-error'; import { ChainId, ChainNames } from './enums/chain-id'; import { CustomNetwork } from './factories/pair/models/custom-network'; export interface ChainIdAndProvider { chainId: ChainId; providerUrl?: string | undefined; customNetwork?: CustomNetwork | undefined; } export interface EthereumProvider { ethereumProvider: any; customNetwork?: CustomNetwork | undefined; } export class EthersProvider { private _ethersProvider: | providers.StaticJsonRpcProvider | providers.JsonRpcProvider | providers.InfuraProvider | providers.Web3Provider; constructor(private _providerContext: ChainIdAndProvider | EthereumProvider) { const chainId = (<ChainIdAndProvider>this._providerContext).chainId; if (chainId) { const chainName = this.getChainName(chainId); const providerUrl = (<ChainIdAndProvider>this._providerContext) .providerUrl; if (providerUrl) { this._ethersProvider = new providers.StaticJsonRpcProvider( providerUrl, { name: chainName, chainId: chainId, } ); } else { this._ethersProvider = new providers.InfuraProvider( chainId, this._getApiKey ); } } else { const ethereumProvider = (<EthereumProvider>this._providerContext) .ethereumProvider; if (!ethereumProvider) { throw new UniswapError( 'Wrong ethers provider context', ErrorCodes.wrongEthersProviderContext ); } if (ethereumProvider._isProvider) { this._ethersProvider = ethereumProvider; } else { this._ethersProvider = new providers.Web3Provider(ethereumProvider); } } } /** * Get the chain name * @param chainId The chain id * @returns */ private getChainName(chainId: number): string { if (this._providerContext.customNetwork) { return this._providerContext.customNetwork.nameNetwork; } const chainName = ChainNames.get(chainId); if (!chainName) { throw new UniswapError( `Can not find chain name for ${chainId}. This lib only supports mainnet(1), ropsten(4), kovan(42), rinkeby(4) and görli(5)`, ErrorCodes.canNotFindChainId ); } return chainName; } /** * Creates a contract instance * @param abi The ABI * @param contractAddress The contract address */ public getContract<TGeneratedTypedContext>( abi: ContractInterface, contractAddress: string ): TGeneratedTypedContext { const contract = new Contract(contractAddress, abi, this._ethersProvider); return contract as unknown as TGeneratedTypedContext; } /** * Get the network */ public network(): providers.Network { if (this._ethersProvider.network) { return this._ethersProvider.network; } // @ts-ignore if (this._ethersProvider.provider) { // @ts-ignore const chainId = this._ethersProvider.provider.chainId; if (chainId) { const chainIdNumber = new BigNumber(chainId).toNumber(); const chainName = ChainNames.get(chainIdNumber); if (chainName) { return { chainId: chainIdNumber, name: chainName, }; } } } throw new UniswapError( 'chainId can not be found on the provider', ErrorCodes.chainIdCanNotBeFound ); } /** * Get the ethers provider */ public get provider(): providers.BaseProvider { return this._ethersProvider; } /** * Get eth amount * @param ethereumAddress The ethereum address */ public async balanceOf(ethereumAddress: string): Promise<string> { return ( await this._ethersProvider.getBalance(ethereumAddress) ).toHexString(); } /** * Get provider url */ public getProviderUrl(): string | undefined { const ethereumProvider = (<EthereumProvider>this._providerContext) .ethereumProvider; if (ethereumProvider) { return undefined; } const providerUrl = (<ChainIdAndProvider>this._providerContext).providerUrl; if (providerUrl) { return providerUrl; } const chainId = (<ChainIdAndProvider>this._providerContext).chainId; switch (chainId) { case ChainId.MAINNET: return `https://mainnet.infura.io/v3/${this._getApiKey}`; case ChainId.ROPSTEN: return `https://ropsten.infura.io/v3/${this._getApiKey}`; case ChainId.RINKEBY: return `https://rinkeby.infura.io/v3/${this._getApiKey}`; case ChainId.GÖRLI: return `https://goerli.infura.io/v3/${this._getApiKey}`; case ChainId.KOVAN: return `https://kovan.infura.io/v3/${this._getApiKey}`; default: return undefined; } } /** * Get the api key */ private get _getApiKey(): string { return '9aa3d95b3bc440fa88ea12eaa4456161'; } }