import { BigNumber } from "bignumber.js" ; import { promisify } from "es6-promisify" ; import abi = require ( "ethereumjs-abi" ) ; import Contract = require ( "truffle-contract" ) ; import { providers as Web3Providers , Web3 } from "web3" ; import { Address , Hash , SchemePermissions } from "./commonTypes" ; import { ConfigService } from "./configService" ; import { LoggingService } from "./loggingService" ; export class Utils { static get NULL_ADDRESS ( ) : Address { return "0x0000000000000000000000000000000000000000" ; } static get NULL_HASH ( ) : Hash { return "0x0000000000000000000000000000000000000000000000000000000000000000" ; } public static setDeployedAddresses ( addresses ) { this . deployedContractAddresses = addresses ; for ( const name of Object . keys ( this . deployedContractAddresses ) ) { this . deployedContractAddresses [ name ] = `0x${ this . deployedContractAddresses [ name ] . substring ( 2 ) . toLowerCase ( ) }` ; } } public static getDeployedAddress ( contractName ) { return Utils . deployedContractAddresses [ contractName ] ; } param contractName public static async requireContract ( contractName ) { try { let contract = Utils . contractCache . get ( contractName ) ; if ( contract ) { LoggingService . debug ( `requireContract: loaded from cache ${ contractName }` ) ; return contract ; } const artifact = require ( `../migrated_contracts/${ contractName }.json` ) ; contract = new Contract ( artifact ) ; const myWeb3 = await Utils . getWeb3 ( ) ; contract . setProvider ( myWeb3 . currentProvider ) ; contract . setNetwork ( await Utils . getNetworkId ( ) ) ; contract . defaults ( { from : await Utils . getDefaultAccount ( ) , gas : ConfigService . get ( "defaultGasLimit" ) , } ) ; /**
             * Use the supplied contract deployment addresses.
             * Arc.js is not doing migrations anymore, so the truffle artifact files contain no
             * deployment addresses.
             */ contract . deployed = ( ) : any => { return contract . at ( Utils . getDeployedAddress ( contractName ) ) . then ( ( result ) => result ) . catch ( ( ex ) => { throw ex ; } ) ; } ; Utils . contractCache . set ( contractName , contract ) ; LoggingService . debug ( `requireContract: loaded ${ contractName }` ) ; return contract ; } catch ( ex ) { LoggingService . error ( `requireContract failing: ${ ex }` ) ; throw Error ( `requireContract: unable to load solidity contract: ${ contractName }: ${ ex }` ) ; } } param public static async getWeb3 ( refetch = false ) { if ( ! refetch && Utils . web3 ) { return Utils . web3 ; } LoggingService . debug ( "Utils.getWeb3: getting web3" ) ; Utils . clearContractCache ( ) ; let preWeb3 ; let globalWeb3 ; const webConstructor = require ( "web3" ) ; if ( ( typeof global !== "undefined" ) && ( global as any ) . web3 && ( ( typeof window === "undefined" ) || ( global as any ) . web3 !== ( window as any ) . web3 ) ) { /**
             * `global.web3` is set and either `window.web3` is not set or the two values for web3 are not equal.
             * In either case we take `global.web3` as apparently it has been provided by an application,
             * either manually or via `InitializeArcJs`. We'll "provide" it further down.
             */ LoggingService . debug ( "Utils.getWeb3: found web3 in global" ) ; globalWeb3 = ( global as any ) . web3 ; } else if ( typeof window !== "undefined" ) { /**
             * we didn't take `global.web` or it wasn't available, and `window` is set
             */ if ( ( window as any ) . ethereum && ConfigService . get ( "useMetamaskEthereumWeb3Provider" ) ) { /**
                 * `windows.ethereum`-provided web3 takes precedence if available.
                 * "Provide" it right here.
                 */ LoggingService . debug ( "Utils.getWeb3: creating Web3 using window.ethereum provider" ) ; preWeb3 = ( window as any ) . web3 = new webConstructor ( ( window as any ) . ethereum ) ; } else if ( ( window as any ) . web3 ) { /**
                 * else take `window.web3` and "provide" it further down
                 */ LoggingService . debug ( "Utils.getWeb3: found web3 in window" ) ; globalWeb3 = ( window as any ) . web3 ; } } if ( ! preWeb3 ) { if ( globalWeb3 ) { LoggingService . debug ( "Utils.getWeb3: instantiating web3 with currentProvider" ) ; preWeb3 = new webConstructor ( globalWeb3 . currentProvider ) ; } else if ( Utils . alreadyTriedAndFailed ) { throw new Error ( "Utils.getWeb3: already tried and failed" ) ; } else { let url = `http://${ ConfigService . get ( "providerUrl" ) }` ; const port = ConfigService . get ( "providerPort" ) ; if ( port ) { url = `${ url }:${ port }` ; } LoggingService . debug ( `Utils.getWeb3: instantiating web3 with configured provider at ${ url }` ) ; preWeb3 = new webConstructor ( new Web3Providers . HttpProvider ( url ) ) ; } } const connected = await promisify ( preWeb3 . net . getListening ) ( ) . then ( ( isListening ) => { return isListening ; } ) . catch ( ( error ) => { return false ; } ) ; if ( ! connected ) { Utils . alreadyTriedAndFailed = true ; throw new Error ( "Utils.getWeb3: web3 is not connected to a net" ) ; } if ( typeof window !== "undefined" ) { ( window as any ) . web3 = preWeb3 ; } Utils . networkId = Number . parseInt ( await promisify ( preWeb3 . version . getNetwork ) ( ) as string , 10 ) as number | undefined ; return ( Utils . web3 = preWeb3 ) ; } /**
     * Returns the address of the default user account.
     *
     * Has the side-effect of setting web3.eth.defaultAccount.
     *
     * Throws an exception on failure.
     */ public static async getDefaultAccount ( ) { const localWeb3 = await Utils . getWeb3 ( ) ; return promisify ( localWeb3 . eth . getAccounts ) ( ) . then ( ( accounts ) => { const defaultAccount = localWeb3 . eth . defaultAccount = ( accounts && ( accounts . length > 0 ) ) ? accounts [ 0 ] : undefined ; if ( ! defaultAccount ) { throw new Error ( "accounts[0] is not set" ) ; } return defaultAccount ; } ) ; } returns public static async getUserApprovalForAccounts ( ) { const ethereumProvider = ( window as any ) . ethereum ; if ( ethereumProvider ) { try { await ethereumProvider . enable ( ) ; } catch { return Promise . resolve ( false ) ; } } else { try { await Utils . getDefaultAccount ( ) ; } catch { return Promise . resolve ( false ) ; } } return Promise . resolve ( true ) ; } /**
     * Return the current token balance for the given token and agent.
     */ public static async getTokenBalance ( agentAddress , tokenAddress ) { if ( ! tokenAddress ) { throw new Error ( "Utils.getTokenBalance: tokenAddress is not defined" ) ; } if ( ! agentAddress ) { throw new Error ( "Utils.getTokenBalance: agentAddress is not defined" ) ; } const token = await ( await Utils . requireContract ( "BasicToken" ) ) . at ( tokenAddress ) ; return token . balanceOf ( agentAddress ) ; } /**
     * Return the current ETH balance for the given agent.
     */ public static async getEthBalance ( agentAddress ) { if ( ! agentAddress ) { throw new Error ( "Utils.getEthBalance: agentAddress is not defined" ) ; } const web3 = await Utils . getWeb3 ( ) ; return promisify ( ( callback ) => web3 . eth . getBalance ( agentAddress , web3 . eth . defaultBlock , callback ) ) ( ) . then ( ( balance ) => { return balance ; } ) ; } param str public static SHA3 ( str ) { return Utils . keccak256 ( [ "string" ] , [ str ] ) ; } param types param values public static keccak256 ( types , values ) { return `0x${ abi . soliditySHA3 ( types , values ) . toString ( "hex" ) }` ; } param { string } permissions public static permissionsStringToNumber ( permissions ) { if ( ! permissions ) { return 0 ; } return Number ( permissions ) as SchemePermissions ; } param { Number } permissions public static numberToPermissionsString ( permissions ) { if ( ! permissions ) { permissions = SchemePermissions . None ; } return `0x${ ( "00000000" + ( permissions as number ) . toString ( 16 ) ) . substr ( - 8 ) }` ; } /**
     * Returns address of the global GEN token.
     */ public static getGenTokenAddress ( ) { return this . deployedContractAddresses . DAOToken ; } param id public static async getNetworkName ( id ? ) { if ( ! id ) { id = await Utils . getNetworkId ( ) ; } switch ( id ) { case 1 : return "Live" ; case 2 : return "Morden" ; case 3 : return "Ropsten" ; case 4 : return "Rinkeby" ; case 42 : return "Kovan" ; case 1512051714758 : return "Ganache" ; default : return "Private" ; } } param public static async getNetworkId ( ) { if ( ! Utils . networkId ) { await Utils . getWeb3 ( ) ; } return Utils . networkId ; } private static contractCache : Map < string , Contract > = new Map < string , string > ( ) ; private static web3 : Web3 = undefined ; private static alreadyTriedAndFailed : boolean = false ; private static networkId : number ; private static deployedContractAddresses : any ; private static clearContractCache ( ) { Utils . contractCache . clear ( ) ; } } export { Web3 } from "web3" ;