Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix logic for letting the user execute the transaction based on available funds. #268

Merged
merged 4 commits into from
Sep 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 38 additions & 11 deletions src/actions/transactionActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with Parity Bridges UI. If not, see <http://www.gnu.org/licenses/>.

import { BalanceState } from '../types/accountTypes';
import { CreateType } from '../types/apiCallsTypes';
import { SourceTargetState } from '../types/sourceTargetTypes';

Expand All @@ -32,7 +33,8 @@ enum TransactionActionTypes {
SET_RECEIVER = 'SET_RECEIVER',
SET_RECEIVER_ADDRESS = 'SET_RECEIVER_ADDRESS',
SET_RECEIVER_VALIDATION = 'SET_RECEIVER_VALIDATION',
SET_SENDER_AND_ACTION = 'SET_SENDER_AND_ACTION',
SET_SENDER = 'SET_SENDER',
SET_ACTION = 'SET_ACTION',
SET_PAYLOAD_ESTIMATED_FEE = 'SET_PAYLOAD_ESTIMATED_FEE',
CREATE_TRANSACTION_STATUS = 'CREATE_TRANSACTION_STATUS',
UPDATE_CURRENT_TRANSACTION_STATUS = 'UPDATE_CURRENT_TRANSACTION_STATUS',
Expand All @@ -42,6 +44,8 @@ enum TransactionActionTypes {
SET_WEIGHT_INPUT = 'SET_WEIGHT_INPUT',
UPDATE_TRANSACTIONS_STATUS = 'UPDATE_TRANSACTIONS_STATUS',
SET_BATCH_PAYLOAD_ESTIMATED_FEE = 'SET_BATCH_PAYLOAD_ESTIMATED_FEE',
UPDATE_SENDER_BALANCES = 'UPDATE_SENDER_BALANCES',
SET_TRANSFER_TYPE = 'SET_TRANSFER_TYPE',
RESET = 'RESET'
}

Expand All @@ -58,15 +62,19 @@ const setPayloadEstimatedFee = (
payloadEstimatedFeeLoading: boolean,
sourceTargetDetails: SourceTargetState,
createType: CreateType,
isBridged: boolean
isBridged: boolean,
senderAccountBalance: BalanceState | null,
senderCompanionAccountBalance: BalanceState | null
) => ({
payload: {
payloadEstimatedFee,
payloadEstimatedFeeError,
payloadEstimatedFeeLoading,
sourceTargetDetails,
createType,
isBridged
isBridged,
senderAccountBalance,
senderCompanionAccountBalance
},
type: TransactionActionTypes.SET_PAYLOAD_ESTIMATED_FEE
});
Expand Down Expand Up @@ -114,13 +122,14 @@ const setTransactionRunning = (transactionRunning: boolean) => ({
type: TransactionActionTypes.SET_TRANSACTION_RUNNING
});

type SenderAndActionInput = {
senderAccount: string | null;
action: TransactionTypes;
};
const setSenderAndAction = ({ senderAccount, action }: SenderAndActionInput) => ({
payload: { senderAccount, action },
type: TransactionActionTypes.SET_SENDER_AND_ACTION
const setAction = (action: TransactionTypes) => ({
payload: { action },
type: TransactionActionTypes.SET_ACTION
});

const setSender = (senderAccount: string | null) => ({
payload: { senderAccount },
type: TransactionActionTypes.SET_SENDER
});

const setRemarkInput = (remarkInput: string | null) => ({
Expand All @@ -143,8 +152,24 @@ const setBatchedEvaluationPayloadEstimatedFee = (batchedTransactionState: Transa
type: TransactionActionTypes.SET_BATCH_PAYLOAD_ESTIMATED_FEE
});

type UpdateSenderBalances = {
senderAccountBalance: BalanceState | null;
senderCompanionAccountBalance: BalanceState | null;
};

const updateSenderBalances = ({ senderAccountBalance, senderCompanionAccountBalance }: UpdateSenderBalances) => ({
payload: { senderAccountBalance, senderCompanionAccountBalance },
type: TransactionActionTypes.UPDATE_SENDER_BALANCES
});

const setTransferType = (transferType: TransactionTypes) => ({
payload: { transferType },
type: TransactionActionTypes.SET_TRANSFER_TYPE
});

const TransactionActionCreators = {
setSenderAndAction,
setSender,
setAction,
setReceiverAddress,
setReceiver,
setTransferAmount,
Expand All @@ -157,6 +182,8 @@ const TransactionActionCreators = {
updateTransactionStatus,
updateTransactionsStatus,
setBatchedEvaluationPayloadEstimatedFee,
updateSenderBalances,
setTransferType,
reset
};

Expand Down
12 changes: 10 additions & 2 deletions src/components/EstimatedFee.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import React from 'react';
import { useSourceTarget } from '../contexts/SourceTargetContextProvider';
import { useTransactionContext } from '../contexts/TransactionContext';
import { transformToBaseUnit } from '../util/evalUnits';
import { Alert } from '.';

const useStyles = makeStyles(() => ({
container: {
Expand All @@ -30,7 +31,12 @@ const useStyles = makeStyles(() => ({
export const EstimatedFee = (): React.ReactElement => {
const classes = useStyles();
const { sourceChainDetails } = useSourceTarget();
const { estimatedFee, payloadEstimatedFeeLoading, transactionRunning } = useTransactionContext();
const {
estimatedFee,
payloadEstimatedFeeLoading,
transactionRunning,
evaluateTransactionStatusError
} = useTransactionContext();
const srcChainDecimals = sourceChainDetails.apiConnection.api.registry.chainDecimals[0];
const { chainTokens } = sourceChainDetails.apiConnection.api.registry;

Expand All @@ -42,7 +48,9 @@ export const EstimatedFee = (): React.ReactElement => {

const feeLabel = `Estimated ${sourceChainDetails.chain} fee`;

return (
return evaluateTransactionStatusError ? (
<Alert severity="error">{evaluateTransactionStatusError}</Alert>
) : (
<div className={classes.container}>
<Typography variant="body1" color="secondary">
{payloadEstimatedFeeLoading && !transactionRunning
Expand Down
27 changes: 4 additions & 23 deletions src/components/Transfer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,18 @@
// You should have received a copy of the GNU General Public License
// along with Parity Bridges UI. If not, see <http://www.gnu.org/licenses/>.

import React, { useState, useEffect, useCallback } from 'react';
import React, { useEffect, useCallback } from 'react';
import { Box, makeStyles } from '@material-ui/core';
import { useSourceTarget } from '../contexts/SourceTargetContextProvider';
import { useTransactionContext } from '../contexts/TransactionContext';
import { useAccountContext } from '../contexts/AccountContextProvider';
import { TransactionActionCreators } from '../actions/transactionActions';
import { useUpdateTransactionContext } from '../contexts/TransactionContext';
import useBalance from '../hooks/subscriptions/useBalance';
import useSendMessage from '../hooks/chain/useSendMessage';
import { TransactionTypes } from '../types/transactionTypes';
import { TokenSymbol } from './TokenSymbol';
import Receiver from './Receiver';
import { Alert, ButtonSubmit } from '../components';
import { ButtonSubmit } from '../components';
import { EstimatedFee } from '../components/EstimatedFee';
import BN from 'bn.js';
import { DebouncedTextField } from './DebouncedTextField';
import { useInternalTransfer } from '../hooks/chain/useInternalTransfer';
import { useGUIContext } from '../contexts/GUIContextProvider';
Expand All @@ -55,19 +52,15 @@ const useStyles = makeStyles((theme) => ({
function Transfer() {
const { dispatchTransaction } = useUpdateTransactionContext();
const classes = useStyles();
const [amountNotCorrect, setAmountNotCorrect] = useState<boolean>(false);
const { sourceChainDetails, targetChainDetails } = useSourceTarget();
const { isBridged } = useGUIContext();
const { account } = useAccountContext();
const {
estimatedFee,
transferAmount,
transferAmountError,
transactionRunning,
transactionReadyToExecute
} = useTransactionContext();
const { api } = sourceChainDetails.apiConnection;
const balance = useBalance(api, account?.address || '');
const executeInternalTransfer = useInternalTransfer();

const dispatchCallback = useCallback(
Expand Down Expand Up @@ -99,12 +92,6 @@ function Transfer() {
transactionRunning && transferAmount && dispatchCallback('');
}, [dispatchCallback, transactionRunning, transferAmount]);

useEffect((): void => {
estimatedFee &&
transferAmount &&
setAmountNotCorrect(new BN(balance.free).sub(transferAmount).add(new BN(estimatedFee)).isNeg());
}, [transferAmount, estimatedFee, balance]);

const buttonLabel = isBridged
? `Send bridge transfer from ${sourceChainDetails.chain} to ${targetChainDetails.chain}`
: `Send internal transfer to ${sourceChainDetails.chain}`;
Expand All @@ -126,16 +113,10 @@ function Transfer() {
/>
</Box>
<Receiver />
<ButtonSubmit disabled={!transactionReadyToExecute || amountNotCorrect} onClick={sendTransaction}>
<ButtonSubmit disabled={!transactionReadyToExecute} onClick={sendTransaction}>
{buttonLabel}
</ButtonSubmit>
{amountNotCorrect ? (
<Alert severity="error">
Account&apos;s amount (including fees: {estimatedFee}) is not enough for this transaction.
</Alert>
) : (
<EstimatedFee />
)}
<EstimatedFee />
</>
);
}
Expand Down
18 changes: 9 additions & 9 deletions src/contexts/TransactionContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { useGUIContext } from './GUIContextProvider';
import { initTransactionState } from '../reducers/initReducersStates/initTransactionState';
import { useSourceTarget } from './SourceTargetContextProvider';
import { encodeAddress } from '@polkadot/util-crypto';
import useSenderBalanceUpdates from '../hooks/transactions/useSenderBalanceUpdates';

interface TransactionContextProviderProps {
children: React.ReactElement;
Expand All @@ -51,7 +52,7 @@ export function useUpdateTransactionContext() {

export function TransactionContextProvider(props: TransactionContextProviderProps): React.ReactElement {
const { children = null } = props;
const { account } = useAccountContext();
const { account, senderAccountBalance, senderCompanionAccountBalance } = useAccountContext();
const { action } = useGUIContext();
const {
sourceChainDetails: {
Expand All @@ -61,18 +62,17 @@ export function TransactionContextProvider(props: TransactionContextProviderProp
const [transactionsState, dispatchTransaction] = useReducer(transactionReducer, initTransactionState);

useResetTransactionState(action, dispatchTransaction);

useEstimatedFeePayload(transactionsState, dispatchTransaction);
useTransactionsStatus(transactionsState.transactions, transactionsState.evaluatingTransactions, dispatchTransaction);
useSenderBalanceUpdates(senderAccountBalance, senderCompanionAccountBalance, dispatchTransaction);

useEffect((): void => {
account && dispatchTransaction(TransactionActionCreators.setSender(encodeAddress(account.address, ss58Format)));
}, [account, ss58Format]);

useEffect((): void => {
dispatchTransaction(
TransactionActionCreators.setSenderAndAction({
senderAccount: account ? encodeAddress(account.address, ss58Format) : null,
action
})
);
}, [account, action, ss58Format]);
action && dispatchTransaction(TransactionActionCreators.setAction(action));
}, [action]);

return (
<TransactionContext.Provider value={transactionsState}>
Expand Down
55 changes: 47 additions & 8 deletions src/hooks/transactions/useEstimatedFeePayload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,13 @@ import type { InterfaceTypes } from '@polkadot/types/types';
import useLaneId from '../chain/useLaneId';
import { getSubstrateDynamicNames } from '../../util/getSubstrateDynamicNames';
import { genericCall } from '../../util/apiUtlis';
import { PayloadEstimatedFee, TransactionsActionType, TransactionState } from '../../types/transactionTypes';
import { getTransactionCallWeight } from '../../util/transactions/';
import {
PayloadEstimatedFee,
TransactionsActionType,
TransactionState,
TransactionTypes
} from '../../types/transactionTypes';
import { getFeeAndWeightForInternals, getTransactionCallWeight } from '../../util/transactions/';
import { useGUIContext } from '../../contexts/GUIContextProvider';
import usePrevious from '../react/usePrevious';

Expand All @@ -41,13 +46,16 @@ export const useEstimatedFeePayload = (
const laneId = useLaneId();
const sourceTargetDetails = useSourceTarget();
const {
sourceChainDetails: { chain: sourceChain },
sourceChainDetails: {
chain: sourceChain,
apiConnection: { api: sourceApi }
},
targetChainDetails: {
apiConnection: { api: targetApi },
chain: targetChain
}
} = sourceTargetDetails;
const { account } = useAccountContext();
const { account, senderAccountBalance, senderCompanionAccountBalance } = useAccountContext();
const { action, isBridged } = useGUIContext();
const { estimatedFeeMethodName } = getSubstrateDynamicNames(targetChain);
const previousPayloadEstimatedFeeLoading = usePrevious(transactionState.payloadEstimatedFeeLoading);
Expand All @@ -61,14 +69,36 @@ export const useEstimatedFeePayload = (
loading,
sourceTargetDetails,
createType,
isBridged
isBridged,
senderAccountBalance,
senderCompanionAccountBalance
)
),
[createType, dispatchTransaction, isBridged, sourceTargetDetails]
[
createType,
dispatchTransaction,
isBridged,
senderAccountBalance,
senderCompanionAccountBalance,
sourceTargetDetails
]
);

const calculateFeeAndPayload = useCallback(
async (currentTransactionState: TransactionState) => {
if (currentTransactionState.action === TransactionTypes.INTERNAL_TRANSFER) {
const { estimatedFee, weight } = await getFeeAndWeightForInternals({
api: sourceApi,
transactionState: currentTransactionState
});
const payload = {
sourceAccount: currentTransactionState.senderAccount,
transferAmount: currentTransactionState.transferAmount!.toNumber(),
receiverAddress: currentTransactionState.receiverAddress,
weight
};
return { estimatedFee, payload };
}
const { call, weight } = await getTransactionCallWeight({
action,
account,
Expand Down Expand Up @@ -103,7 +133,7 @@ export const useEstimatedFeePayload = (
const estimatedFee = estimatedFeeType.toString();
return { estimatedFee, payload };
},
[account, action, createType, estimatedFeeMethodName, laneId, sourceChain, stateCall, targetApi]
[account, action, createType, estimatedFeeMethodName, laneId, sourceApi, sourceChain, stateCall, targetApi]
);

useEffect(() => {
Expand All @@ -126,7 +156,14 @@ export const useEstimatedFeePayload = (

useEffect(() => {
const { batchedTransactionState, payloadEstimatedFeeLoading } = transactionState;
if (previousPayloadEstimatedFeeLoading && !payloadEstimatedFeeLoading && batchedTransactionState) {

if (
previousPayloadEstimatedFeeLoading &&
!payloadEstimatedFeeLoading &&
batchedTransactionState &&
senderAccountBalance &&
senderCompanionAccountBalance
) {
genericCall({
call: () => calculateFeeAndPayload(batchedTransactionState),
dispatch,
Expand All @@ -140,6 +177,8 @@ export const useEstimatedFeePayload = (
dispatch,
dispatchTransaction,
previousPayloadEstimatedFeeLoading,
senderAccountBalance,
senderCompanionAccountBalance,
transactionState
]);
};
Expand Down
Loading