Skip to content

Commit

Permalink
Fix logic for letting the user execute the transaction based on avail…
Browse files Browse the repository at this point in the history
…able funds. (#268)

* Work in progress

* Finishing logic for splitting enough fee and amount

* removing unwanted changes

* Addressing bug with local transfer
  • Loading branch information
hbulgarini authored Sep 1, 2021
1 parent 2de9e24 commit e1bbd5c
Show file tree
Hide file tree
Showing 12 changed files with 311 additions and 87 deletions.
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

0 comments on commit e1bbd5c

Please sign in to comment.