import React, {useEffect, useState} from 'react';
import './wallet.scss';
import {useService} from '@xstate/react';
import {formatEther} from '@ethersproject/units';
import {Button, Heading, Flex, Text, Box, Link, Loader, Tooltip, Icon} from 'rimble-ui';
import {BN} from '@statechannels/wallet-core';
import {ApproveBudgetAndFundService} from '../workflows/approve-budget-and-fund';
import {track} from '../segment-analytics';
import {getAmountsFromBudget} from './selectors';
import {ETH_ASSET_HOLDER_ADDRESS, TARGET_NETWORK, FAUCET_LINK} from '../config';
interface Props {
service: ApproveBudgetAndFundService;
}
export const ApproveBudgetAndFund = (props: Props) => {
const [current, _send] = useService(props.service);
const {budget} = current.context;
const {playerAmount, hubAmount} = getAmountsFromBudget(budget);
const send = (
event:
| 'USER_APPROVES_BUDGET'
| 'USER_REJECTS_BUDGET'
| 'USER_APPROVES_RETRY'
| 'USER_REJECTS_RETRY'
) => () => {
track(event, {domain: current.context.budget.domain});
_send(event);
};
// Sets a timer that expires after 1.5 minutes
// Used to determine if we've timed out waiting for the hub
let stateTimer;
const [stateTimerExpired, setStateTimerExpired] = useState(false);
useEffect(() => {
setStateTimerExpired(false);
stateTimer = setTimeout(() => setStateTimerExpired(true), 90_000 /* 1.5 min */);
return () => {
clearTimeout(stateTimer);
};
}, [current]);
const waitForSufficientFundsInit = (
App BudgetChecking if your Metamask account has sufficient ETH
);
const waitForSufficientFunds = (
App Budget
You don't have enough ETH in your wallet!
You'll need at least {formatEther(BN.from(playerAmount))} ETH in your Metamask wallet to
fund the channel. You can get more ETH{' '}
here.
);
const waitForUserApproval = ({waiting}: {waiting: boolean} = {waiting: false}) => (
App Budget
Approve budget?
Send: {formatEther(BN.from(playerAmount))} ETHReceive: {formatEther(BN.from(hubAmount))} ETH{budget.domain} will manage these funds.
You will deposit {formatEther(BN.from(playerAmount))} ETH into a channel. Our hub will also
make a deposit.
Cancel
);
const waitForPreFS = (
Deposit fundsWaiting for the hub to respond.
);
const depositInit = (
Deposit fundsQuerying blockchain
);
const depositWaitTurn = (
Deposit fundsThe hub is now depositing funds on-chain. This may take a moment.
Click{' '}
here
{' '}
to follow the progress on etherscan.
);
const depositSubmitTransaction = (
Deposit funds
Please approve the transaction in metamask
);
const depositWaitMining = ({transactionId}: {transactionId: string}) => (
Deposit fundsWaiting for your transaction to be mined.
Click{' '}
here
{' '}
to follow the progress on etherscan.
);
const depositRetry = () => (
Deposit FundsYour deposit transaction failed. Do you want to retry?Cancel
);
// in the current setup, the hub deposits first, so this should never be shown
const depositFullyFunded = (
Deposit fundsWaiting for hub to deposit
);
const hubTimeout = (
Deposit Funds
We haven't heard back from the hub in a bit so something might have gone wrong.
You can click{' '}
here
{' '}
to see the progress on etherscan or you can download your log files and reach out to us on{' '}
{' '}
github.
);
if (current.matches('waitForUserApproval')) {
return waitForUserApproval();
} else if (current.matches({waitForSufficientFunds: 'init'})) {
return waitForSufficientFundsInit;
} else if (current.matches({waitForSufficientFunds: 'waitForFunds'})) {
return waitForSufficientFunds;
} else if (current.matches('createLedger')) {
return waitForSufficientFunds;
} else if (current.matches('waitForPreFS')) {
return waitForPreFS;
} else if (current.matches({deposit: 'init'})) {
return depositInit;
} else if (current.matches({deposit: 'waitTurn'})) {
if (stateTimerExpired) {
return hubTimeout;
} else {
return depositWaitTurn;
}
} else if (current.matches({deposit: 'submitTransaction'})) {
return depositSubmitTransaction;
} else if (current.matches({deposit: 'waitMining'})) {
return depositWaitMining(current.context);
} else if (current.matches({deposit: 'retry'})) {
return depositRetry();
} else if (current.matches({deposit: 'waitFullyFunded'})) {
return depositFullyFunded;
} else if (current.matches('createBudget')) {
return depositFullyFunded;
} else if (current.matches('done')) {
// workflow hides ui, so user shouldn't ever see this
return
Success! Returning to app..
;
} else if (current.matches('failure')) {
// workflow hides ui, so user shouldn't ever see this
return