import { Web3Provider } from "ethers/providers" ; import { History } from "history" ; import { Action } from "redux" ; import { ThunkAction } from "redux-thunk" ; import { RoutePath } from "../../types" ; import { forFunds , getIndexedCFBalances , requestDeposit , requestWithdraw } from "../../utils/counterfactual" ; import log from "../../utils/log" ; import { getTokens , ShortTokenNetworksName , getUserWalletBalances } from "../../utils/nodeTokenClient" ; import { ActionType , ApplicationState , AssetType , Deposit , StoreAction , WalletState } from "../types" ; export const initialState = { tokenAddresses : [ ] , ethAddress : "" , error : { } , status : "" } as WalletState ; export const connectToWallet = ( provider ) : ThunkAction < void , ApplicationState , null , Action < ActionType > > => async ( dispatch ) => { try { const { ethereum } = window ; await ethereum . enable ( ) ; dispatch ( { data : { ethAddress : ethereum . selectedAddress } as WalletState , type : ActionType . WalletSetAddress } ) ; const network = await provider . getNetwork ( ) ; let tokenAddresses = await getTokens ( ShortTokenNetworksName [ network . name ] ) ; tokenAddresses = await getUserWalletBalances ( provider , ethereum . selectedAddress , tokenAddresses ) ; dispatch ( { data : { tokenAddresses } , type : ActionType . WalletSetBalance } ) ; } catch ( e ) { dispatch ( { data : { error : { message : "You must allow Counterfactual to connect with Metamask in order to use it." } } as WalletState , type : ActionType . WalletError } ) ; } } ; export enum WalletDepositTransition { CheckWallet = "WALLET_DEPOSIT_CHECK_WALLET" , WaitForUserFunds = "WALLET_DEPOSIT_WAITING_FOR_USER_FUNDS" , WaitForCollateralFunds = "WALLET_DEPOSIT_WAITING_FOR_COLLATERAL_FUNDS" } export const deposit = ( transaction , provider , history ? ) : ThunkAction < void , ApplicationState , null , Action < ActionType | WalletDepositTransition > > => async ( dispatch ) => { try { dispatch ( { type : WalletDepositTransition . CheckWallet } ) ; await requestDeposit ( transaction ) ; dispatch ( { type : WalletDepositTransition . WaitForUserFunds } ) ; await forFunds ( transaction , "user" ) ; dispatch ( { type : WalletDepositTransition . WaitForCollateralFunds } ) ; await forFunds ( transaction ) ; let tokenAddresses = await getIndexedCFBalances ( { multisigAddress : transaction . multisigAddress as string , nodeAddress : transaction . nodeAddress } ) ; tokenAddresses = await getUserWalletBalances ( provider , transaction . ethAddress , tokenAddresses ) ; dispatch ( { data : { tokenAddresses } , type : ActionType . WalletSetBalance } ) ; if ( history ) { history . push ( RoutePath . Channels ) ; } } catch ( e ) { const error = e as Error ; dispatch ( { data : { error : { message : `${ error . message } because of ${ error . stack }` } } , type : ActionType . WalletError } ) ; } } ; export enum WalletWithdrawTransition { CheckWallet = "WALLET_WITHDRAW_CHECK_WALLET" , WaitForFunds = "WALLET_WITHDRAW_WAITING_FOR_FUNDS" } export const withdraw = ( transaction , provider , history ? ) : ThunkAction < void , ApplicationState , null , Action < ActionType | WalletWithdrawTransition > > => async ( dispatch ) => { try { dispatch ( { type : WalletWithdrawTransition . CheckWallet } ) ; const response = await requestWithdraw ( transaction ) ; log ( "withdraw response" , response ) ; dispatch ( { type : WalletWithdrawTransition . WaitForFunds } ) ; await forFunds ( transaction ) ; let tokenAddresses = await getIndexedCFBalances ( { multisigAddress : transaction . multisigAddress as string , nodeAddress : transaction . nodeAddress } ) ; tokenAddresses = await getUserWalletBalances ( provider , transaction . ethAddress , tokenAddresses ) ; dispatch ( { data : { tokenAddresses } , type : ActionType . WalletSetBalance } ) ; if ( history ) { history . push ( RoutePath . Channels ) ; } } catch ( e ) { const error = e as Error ; dispatch ( { data : { error : { message : `${ error . message } because of ${ error . stack }` } } , type : ActionType . WalletError } ) ; } } ; export const reducers = function ( state = initialState , action ) { switch ( action . type ) { case ActionType . WalletSetNodeTokens : case ActionType . WalletSetBalance : const tokenAddresses = Object . values ( ( state . tokenAddresses || [ ] ) . concat ( action . data . tokenAddresses ) . reduce ( ( accumulator , item ) => { return { ... accumulator , [ item . tokenAddress ] : { ... accumulator [ item . tokenAddress ] , ... item } } ; } , { } ) ) ; return { ... state , tokenAddresses , status : action . type } ; case ActionType . WalletSetAddress : case ActionType . WalletDeposit : case ActionType . WalletWithdraw : return { ... state , ... action . data , status : action . type } ; case ActionType . WalletError : console . error ( "wallet error" , action . data ) ; return { ... state , ... action . data , status : action . type } ; default : return { ... state , status : action . type } ; } } ;