import { CeloTokenContract , ContractKit } from '@celo/contractkit' ; import { useCallback } from 'react' ; import { CONNECTOR_TYPES } from './connectors' ; import { localStorageKeys , STATIC_NETWORK_WALLETS , WalletTypes , } from './constants' ; import { Dispatcher } from './contract-kit-provider' ; import { Connector , Network } from './types' ; export function useContractKitMethods ( { connector , networks , network , } , dispatch ) { const destroy = useCallback ( async ( ) => { await connector . close ( ) ; dispatch ( 'destroy' ) ; } , [ dispatch , connector ] ) ; const initConnector = useCallback ( async ( nextConnector ) => { try { const initialisedConnector = await nextConnector . initialise ( ) ; dispatch ( 'initialisedConnector' , initialisedConnector ) ; const netId = await initialisedConnector . kit . web3 . eth . net . getId ( ) ; const newNetwork = networks . find ( ( n ) => netId === n . chainId ) ; if ( newNetwork !== network ) { dispatch ( 'setNetwork' , network ) ; } initialisedConnector . onNetworkChange ?. ( ( chainId ) => { const network = networks . find ( ( n ) => n . chainId === chainId ) ; if ( netId === chainId || ! network ) return ; if ( network ) { dispatch ( 'setNetwork' , network ) ; initialisedConnector . updateKitWithNetwork && initialisedConnector . updateKitWithNetwork ( network ) . then ( ( ) => { dispatch ( 'initialisedConnector' , initialisedConnector ) ; } ) . catch ( ( e ) => { console . error ( '[use-contractkit] Error switching network' , nextConnector . type , e ) ; const error = e instanceof Error ? e : new Error ( `Failed to initialise connector with ${ network . name }` ) ; dispatch ( 'setConnectorInitError' , error ) ; throw e ; } ) ; } } ) ; initialisedConnector . onAddressChange ?. ( ( address ) => { dispatch ( 'setAddress' , address ) ; } ) ; return initialisedConnector ; } catch ( e ) { console . error ( '[use-contractkit] Error initializing connector' , nextConnector . type , e ) ; const error = e instanceof Error ? e : new Error ( 'Failed to initialise connector' ) ; dispatch ( 'setConnectorInitError' , error ) ; throw e ; } } , [ dispatch , network , networks ] ) ; const updateNetwork = useCallback ( async ( newNetwork ) => { if ( STATIC_NETWORK_WALLETS . includes ( connector . type ) ) { throw new Error ( "The connected wallet's network must be changed from the wallet." ) ; } if ( network === newNetwork ) return ; if ( connector . initialised ) { const connectorArgs = JSON . parse ( localStorage . getItem ( localStorageKeys . lastUsedWalletArguments ) || '[]' ) as unknown [ ] ; await connector . close ( ) ; const ConnectorConstructor = CONNECTOR_TYPES [ connector . type ] ; const newConnector = new ConnectorConstructor ( newNetwork , ... connectorArgs ) ; await initConnector ( newConnector ) ; } dispatch ( 'setNetwork' , newNetwork ) ; } , [ dispatch , connector , network , initConnector ] ) ; const connect = useCallback ( async ( ) : Promise < Connector > => { const connectionResultPromise = new Promise ( ( resolve ) => { dispatch ( 'setConnectionCallback' , resolve ) ; } ) ; const newConnector = await connectionResultPromise ; dispatch ( 'setConnectionCallback' , null ) ; if ( newConnector === false ) { throw new Error ( 'Connection cancelled' ) ; } return newConnector ; } , [ dispatch ] ) ; const getConnectedKit = useCallback ( async ( ) : Promise < ContractKit > => { let initialisedConnection = connector ; if ( connector . type === WalletTypes . Unauthenticated ) { initialisedConnection = await connect ( ) ; } else if ( ! initialisedConnection . initialised ) { await initConnector ( initialisedConnection ) ; } return initialisedConnection . kit ; } , [ connect , connector , initConnector ] ) ; const updateFeeCurrency = useCallback ( async ( newFeeCurrency ) : Promise < void > => { await connector . updateFeeCurrency ( newFeeCurrency ) ; dispatch ( 'setFeeCurrency' , newFeeCurrency ) ; } , [ connector , dispatch ] ) ; const performActions = useCallback ( async ( ... operations ) => { const kit = await getConnectedKit ( ) ; dispatch ( 'setPendingActionCount' , operations . length ) ; const results = [ ] ; for ( const op of operations ) { try { results . push ( await op ( kit ) ) ; } catch ( e ) { dispatch ( 'setPendingActionCount' , 0 ) ; throw e ; } dispatch ( 'decrementPendingActionCount' ) ; } return results ; } , [ getConnectedKit , dispatch ] ) ; return { destroy , initConnector , updateNetwork , connect , getConnectedKit , performActions , updateFeeCurrency , } ; } export interface ContractKitMethods { destroy : ( ) => Promise < void > ; initConnector : ( connector : Connector ) => Promise < Connector > ; updateNetwork : ( network : Network ) => Promise < void > ; connect : ( ) => Promise < Connector > ; getConnectedKit : ( ) => Promise < ContractKit > ; performActions : ( ... operations : ( ( kit : ContractKit ) => unknown | Promise < unknown > ) [ ] ) => Promise < unknown [ ] > ; updateFeeCurrency : ( newFeeCurrency : CeloTokenContract ) => Promise < void > ; }