diff --git a/src/actions/transactionActions.ts b/src/actions/transactionActions.ts
index 9baf197c..21c79e44 100644
--- a/src/actions/transactionActions.ts
+++ b/src/actions/transactionActions.ts
@@ -14,6 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with Parity Bridges UI. If not, see .
+import { BalanceState } from '../types/accountTypes';
import { CreateType } from '../types/apiCallsTypes';
import { SourceTargetState } from '../types/sourceTargetTypes';
@@ -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',
@@ -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'
}
@@ -58,7 +62,9 @@ const setPayloadEstimatedFee = (
payloadEstimatedFeeLoading: boolean,
sourceTargetDetails: SourceTargetState,
createType: CreateType,
- isBridged: boolean
+ isBridged: boolean,
+ senderAccountBalance: BalanceState | null,
+ senderCompanionAccountBalance: BalanceState | null
) => ({
payload: {
payloadEstimatedFee,
@@ -66,7 +72,9 @@ const setPayloadEstimatedFee = (
payloadEstimatedFeeLoading,
sourceTargetDetails,
createType,
- isBridged
+ isBridged,
+ senderAccountBalance,
+ senderCompanionAccountBalance
},
type: TransactionActionTypes.SET_PAYLOAD_ESTIMATED_FEE
});
@@ -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) => ({
@@ -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,
@@ -157,6 +182,8 @@ const TransactionActionCreators = {
updateTransactionStatus,
updateTransactionsStatus,
setBatchedEvaluationPayloadEstimatedFee,
+ updateSenderBalances,
+ setTransferType,
reset
};
diff --git a/src/components/EstimatedFee.tsx b/src/components/EstimatedFee.tsx
index 83556a87..98193e06 100644
--- a/src/components/EstimatedFee.tsx
+++ b/src/components/EstimatedFee.tsx
@@ -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: {
@@ -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;
@@ -42,7 +48,9 @@ export const EstimatedFee = (): React.ReactElement => {
const feeLabel = `Estimated ${sourceChainDetails.chain} fee`;
- return (
+ return evaluateTransactionStatusError ? (
+ {evaluateTransactionStatusError}
+ ) : (
{payloadEstimatedFeeLoading && !transactionRunning
diff --git a/src/components/Transfer.tsx b/src/components/Transfer.tsx
index 01bef27f..ca8f75f9 100644
--- a/src/components/Transfer.tsx
+++ b/src/components/Transfer.tsx
@@ -14,21 +14,18 @@
// You should have received a copy of the GNU General Public License
// along with Parity Bridges UI. If not, see .
-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';
@@ -55,19 +52,15 @@ const useStyles = makeStyles((theme) => ({
function Transfer() {
const { dispatchTransaction } = useUpdateTransactionContext();
const classes = useStyles();
- const [amountNotCorrect, setAmountNotCorrect] = useState(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(
@@ -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}`;
@@ -126,16 +113,10 @@ function Transfer() {
/>
-
+
{buttonLabel}
- {amountNotCorrect ? (
-
- Account's amount (including fees: {estimatedFee}) is not enough for this transaction.
-
- ) : (
-
- )}
+
>
);
}
diff --git a/src/contexts/TransactionContext.tsx b/src/contexts/TransactionContext.tsx
index 80c55ddf..3094b31b 100644
--- a/src/contexts/TransactionContext.tsx
+++ b/src/contexts/TransactionContext.tsx
@@ -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;
@@ -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: {
@@ -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 (
diff --git a/src/hooks/transactions/useEstimatedFeePayload.ts b/src/hooks/transactions/useEstimatedFeePayload.ts
index b0ff5889..a5df71db 100644
--- a/src/hooks/transactions/useEstimatedFeePayload.ts
+++ b/src/hooks/transactions/useEstimatedFeePayload.ts
@@ -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';
@@ -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);
@@ -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,
@@ -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(() => {
@@ -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,
@@ -140,6 +177,8 @@ export const useEstimatedFeePayload = (
dispatch,
dispatchTransaction,
previousPayloadEstimatedFeeLoading,
+ senderAccountBalance,
+ senderCompanionAccountBalance,
transactionState
]);
};
diff --git a/src/hooks/transactions/useSenderBalanceUpdates.ts b/src/hooks/transactions/useSenderBalanceUpdates.ts
new file mode 100644
index 00000000..d0f38980
--- /dev/null
+++ b/src/hooks/transactions/useSenderBalanceUpdates.ts
@@ -0,0 +1,55 @@
+// Copyright 2021 Parity Technologies (UK) Ltd.
+// This file is part of Parity Bridges UI.
+//
+// Parity Bridges UI is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Parity Bridges UI is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Parity Bridges UI. If not, see .
+
+import { Dispatch, useEffect } from 'react';
+import isEqual from 'lodash/isEqual';
+import { TransactionActionCreators } from '../../actions/transactionActions';
+
+import { TransactionsActionType } from '../../types/transactionTypes';
+import usePrevious from '../react/usePrevious';
+import { BalanceState } from '../../types/accountTypes';
+
+const useSenderBalanceUpdates = (
+ senderAccountBalance: BalanceState | null,
+ senderCompanionAccountBalance: BalanceState | null,
+ dispatchTransaction: Dispatch
+) => {
+ const prevSenderAccountBalance = usePrevious(senderAccountBalance);
+ const prevSenderCompanionAccountBalance = usePrevious(senderCompanionAccountBalance);
+
+ useEffect((): void => {
+ if (
+ (senderAccountBalance &&
+ senderCompanionAccountBalance &&
+ !isEqual(prevSenderAccountBalance, senderAccountBalance)) ||
+ !isEqual(prevSenderCompanionAccountBalance, senderCompanionAccountBalance)
+ )
+ dispatchTransaction(
+ TransactionActionCreators.updateSenderBalances({
+ senderAccountBalance,
+ senderCompanionAccountBalance
+ })
+ );
+ }, [
+ dispatchTransaction,
+ prevSenderAccountBalance,
+ prevSenderCompanionAccountBalance,
+ senderAccountBalance,
+ senderCompanionAccountBalance
+ ]);
+};
+
+export default useSenderBalanceUpdates;
diff --git a/src/reducers/accountReducer.ts b/src/reducers/accountReducer.ts
index cb961b65..d6baee7b 100644
--- a/src/reducers/accountReducer.ts
+++ b/src/reducers/accountReducer.ts
@@ -43,7 +43,7 @@ export default function accountReducer(state: AccountState, action: AccountsActi
const companionAccount = getDeriveAccount(toDerive);
- return { ...state, account, companionAccount };
+ return { ...state, account, companionAccount, senderAccountBalance: null, senderCompanionAccountBalance: null };
}
case AccountActionsTypes.SET_SENDER_BALANCES:
return {
diff --git a/src/reducers/transactionReducer.ts b/src/reducers/transactionReducer.ts
index 07545e79..079581d2 100644
--- a/src/reducers/transactionReducer.ts
+++ b/src/reducers/transactionReducer.ts
@@ -20,7 +20,8 @@ import {
updateTransaction,
isReadyToExecute,
setReceiver,
- shouldCalculatePayloadFee
+ shouldCalculatePayloadFee,
+ enoughFundsEvaluation
} from '../util/transactions/reducer';
import { TransactionsActionType, TransactionState } from '../types/transactionTypes';
import logger from '../util/logger';
@@ -38,18 +39,30 @@ export default function transactionReducer(state: TransactionState, action: Tran
payloadEstimatedFeeLoading,
sourceTargetDetails,
createType,
- isBridged
+ isBridged,
+ senderAccountBalance,
+ senderCompanionAccountBalance
} = action.payload;
- const { senderAccount, transferAmount, receiverAddress } = state;
+ const { senderAccount, receiverAddress, transferAmount } = state;
- const readyToExecute = payloadEstimatedFeeLoading ? false : transactionReadyToExecute;
+ const { evaluateTransactionStatusError, notEnoughFundsToTransfer, notEnoughToPayFee } = enoughFundsEvaluation({
+ transferAmount,
+ senderCompanionAccountBalance,
+ senderAccountBalance,
+ estimatedFee,
+ action: state.action
+ });
+
+ const readyToExecute = payloadEstimatedFeeLoading
+ ? false
+ : transactionReadyToExecute && !notEnoughToPayFee && !notEnoughFundsToTransfer;
let payloadHex = null;
let transactionDisplayPayload = null;
- if (senderAccount) {
- if (payload && isBridged) {
+ if (senderAccount && payload) {
+ if (isBridged) {
const updated = getTransactionDisplayPayload({
payload,
account: senderAccount,
@@ -63,7 +76,8 @@ export default function transactionReducer(state: TransactionState, action: Tran
transactionDisplayPayload = {
sourceAccount: senderAccount,
transferAmount: transferAmount.toNumber(),
- receiverAddress: receiverAddress
+ receiverAddress: receiverAddress,
+ weight: payload.weight
};
}
}
@@ -74,11 +88,11 @@ export default function transactionReducer(state: TransactionState, action: Tran
payloadEstimatedFeeError,
payloadEstimatedFeeLoading,
payload: payloadEstimatedFeeError ? null : payload,
-
transactionReadyToExecute: readyToExecute,
shouldEvaluatePayloadEstimatedFee: false,
payloadHex,
- transactionDisplayPayload
+ transactionDisplayPayload,
+ evaluateTransactionStatusError
};
}
@@ -186,6 +200,7 @@ export default function transactionReducer(state: TransactionState, action: Tran
case TransactionActionTypes.RESET:
return {
...state,
+ evaluateTransactionStatusError: null,
resetedAt: Date.now().toString(),
derivedReceiverAccount: null,
estimatedFee: null,
@@ -228,20 +243,36 @@ export default function transactionReducer(state: TransactionState, action: Tran
return setReceiver(state, action.payload.receiverPayload);
case TransactionActionTypes.SET_TRANSACTION_RUNNING:
return { ...state, transactionRunning: action.payload.transactionRunning, transactionReadyToExecute: false };
- case TransactionActionTypes.SET_SENDER_AND_ACTION: {
- const { senderAccount, action: transactionType } = action.payload;
+ case TransactionActionTypes.SET_ACTION: {
+ const { action: transactionType } = action.payload;
+
+ return {
+ ...state,
+ action: transactionType
+ };
+ }
+ case TransactionActionTypes.SET_SENDER: {
+ const { senderAccount } = action.payload;
+
+ return {
+ ...state,
+ senderAccount: senderAccount
+ };
+ }
+ case TransactionActionTypes.UPDATE_SENDER_BALANCES: {
+ const { action: transactionType, senderAccount } = state;
+
const shouldEvaluatePayloadEstimatedFee = shouldCalculatePayloadFee(state, {
senderAccount,
action: transactionType
});
+
return {
...state,
- senderAccount: senderAccount,
- action: transactionType,
- shouldEvaluatePayloadEstimatedFee
+ shouldEvaluatePayloadEstimatedFee,
+ transactionReadyToExecute: false
};
}
-
case TransactionActionTypes.UPDATE_TRANSACTIONS_STATUS: {
const { evaluateTransactionStatusError, transactions, evaluatingTransactions } = action.payload;
return {
@@ -251,6 +282,14 @@ export default function transactionReducer(state: TransactionState, action: Tran
evaluateTransactionStatusError
};
}
+ case TransactionActionTypes.SET_TRANSFER_TYPE: {
+ const { transferType } = action.payload;
+ return {
+ ...state,
+ action: transferType
+ };
+ }
+
default:
throw new Error(`Unknown type: ${action.type}`);
}
diff --git a/src/screens/Main.tsx b/src/screens/Main.tsx
index 0639bce8..db7035ed 100644
--- a/src/screens/Main.tsx
+++ b/src/screens/Main.tsx
@@ -29,9 +29,10 @@ import ArrowDownwardIcon from '@material-ui/icons/ArrowDownward';
import Transactions from '../components/Transactions';
import { useGUIContext } from '../contexts/GUIContextProvider';
import { TransactionTypes } from '../types/transactionTypes';
-
+import { TransactionActionCreators } from '../actions/transactionActions';
import BridgedLocalWrapper from '../components/BridgedLocalWrapper';
import { useCallback } from 'react';
+import { useUpdateTransactionContext } from '../contexts/TransactionContext';
const useStyles = makeStyles(() => ({
root: {
@@ -50,12 +51,18 @@ const ActionComponents = {
function Main() {
const classes = useStyles();
const { actions, action, setAction, isBridged, setBridged } = useGUIContext();
+ const { dispatchTransaction } = useUpdateTransactionContext();
const handleOnSwitch = useCallback(
- (event: React.MouseEvent, newAlignment: string | null) => {
- setBridged(Boolean(newAlignment));
+ (event: React.MouseEvent, isBridged: boolean) => {
+ setBridged(isBridged);
+ dispatchTransaction(
+ TransactionActionCreators.setTransferType(
+ isBridged ? TransactionTypes.TRANSFER : TransactionTypes.INTERNAL_TRANSFER
+ )
+ );
},
- [setBridged]
+ [dispatchTransaction, setBridged]
);
// TODO #242: ToggleButtonGroup needs to contain the colors designed by custom css.
diff --git a/src/types/transactionTypes.ts b/src/types/transactionTypes.ts
index f8a8ee38..b5d02a24 100644
--- a/src/types/transactionTypes.ts
+++ b/src/types/transactionTypes.ts
@@ -40,7 +40,8 @@ export enum SwitchTabEnum {
PAYLOAD = 'PAYLOAD',
DECODED = 'DECODED'
}
-export interface TransactionPayload {
+
+export interface BridgedTransactionPayload {
call: Uint8Array;
origin: {
SourceAccount: Uint8Array;
@@ -49,20 +50,28 @@ export interface TransactionPayload {
weight: number;
}
+export interface InternalTransferPayload {
+ sourceAccount: string | null;
+ transferAmount: number;
+ receiverAddress: string | null;
+ weight: number;
+}
+
+export type TransactionPayload = BridgedTransactionPayload | InternalTransferPayload;
+
export interface TransactionDisplayPayload {
call: Object;
origin: Object;
spec_version: string;
- weight: string;
+ weight: number;
}
-export interface LocalTransactionDisplayPayload {
- sourceAccount: string;
- transferAmount: number;
- receiverAddress: string;
-}
+export type PayloadEstimatedFee = {
+ payload: TransactionPayload | null;
+ estimatedFee: string | null;
+};
-export type DisplayPayload = TransactionDisplayPayload | LocalTransactionDisplayPayload;
+export type DisplayPayload = TransactionDisplayPayload | InternalTransferPayload;
export interface TransactionStatusType extends UpdatedTransactionStatusType {
input: string;
@@ -138,8 +147,3 @@ export interface ReceiverPayload {
targetChainDetails: ChainState;
isBridged: boolean;
}
-
-export type PayloadEstimatedFee = {
- payload: TransactionPayload | null;
- estimatedFee: string | null;
-};
diff --git a/src/util/transactions/index.ts b/src/util/transactions/index.ts
index a15d2e9b..bd88100f 100644
--- a/src/util/transactions/index.ts
+++ b/src/util/transactions/index.ts
@@ -135,6 +135,20 @@ export async function getTransactionCallWeight({
}
return { call, weight };
}
+
+interface FeeWeightInternal {
+ api: ApiPromise;
+ transactionState: TransactionState;
+}
+
+export async function getFeeAndWeightForInternals({ api, transactionState }: FeeWeightInternal) {
+ const { receiverAddress, transferAmount, senderAccount } = transactionState;
+ const transfer = api.tx.balances.transfer(receiverAddress!, transferAmount || 0);
+
+ const { partialFee, weight } = await transfer.paymentInfo(senderAccount!);
+ return { estimatedFee: partialFee.toString(), weight: weight.toNumber() };
+}
+
const stepEvaluator = (transactionValue: string | number | null, chainValue: string | number | null): boolean => {
if (!transactionValue || !chainValue) return false;
diff --git a/src/util/transactions/reducer/index.ts b/src/util/transactions/reducer/index.ts
index 450a8096..e2aee0cb 100644
--- a/src/util/transactions/reducer/index.ts
+++ b/src/util/transactions/reducer/index.ts
@@ -21,6 +21,8 @@ import { INCORRECT_FORMAT, GENERIC } from '../../../constants';
import { getValidAddressFormat } from '../../accounts';
import getReceiverAddress from '../../getReceiverAddress';
import logger from '../../logger';
+import BN from 'bn.js';
+import { BalanceState } from '../../../types/accountTypes';
const validateAccount = (receiver: string, sourceChainDetails: ChainState, targetChainDetails: ChainState) => {
try {
@@ -42,6 +44,51 @@ const validateAccount = (receiver: string, sourceChainDetails: ChainState, targe
}
};
+interface EnoughFundsEvaluation {
+ transferAmount: BN | null;
+ senderAccountBalance: BalanceState;
+ senderCompanionAccountBalance: BalanceState;
+ estimatedFee: string | null;
+ action: TransactionTypes;
+}
+
+const enoughFundsEvaluation = ({
+ transferAmount,
+ senderCompanionAccountBalance,
+ senderAccountBalance,
+ estimatedFee,
+ action
+}: EnoughFundsEvaluation) => {
+ let evaluateTransactionStatusError = null;
+ let notEnoughFundsToTransfer = false;
+ let notEnoughToPayFee = false;
+
+ if (senderAccountBalance && estimatedFee) {
+ notEnoughToPayFee = new BN(senderAccountBalance.free).sub(new BN(estimatedFee)).isNeg();
+ if (notEnoughToPayFee) {
+ evaluateTransactionStatusError = `Account's amount is not enough for pay fee transaction: ${estimatedFee}.`;
+ }
+
+ if (action === TransactionTypes.TRANSFER && transferAmount && senderCompanionAccountBalance) {
+ notEnoughFundsToTransfer = new BN(senderCompanionAccountBalance.free).sub(new BN(estimatedFee)).isNeg();
+ if (notEnoughFundsToTransfer) {
+ evaluateTransactionStatusError = "Companion account's amount is not enough for this transaction.";
+ }
+ }
+
+ if (action === TransactionTypes.INTERNAL_TRANSFER && transferAmount) {
+ notEnoughFundsToTransfer = new BN(senderAccountBalance.free)
+ .sub(transferAmount)
+ .sub(new BN(estimatedFee))
+ .isNeg();
+ if (notEnoughFundsToTransfer) {
+ evaluateTransactionStatusError = "Account's amount is not enough for this transaction.";
+ }
+ }
+ }
+ return { evaluateTransactionStatusError, notEnoughFundsToTransfer, notEnoughToPayFee };
+};
+
const shouldCalculatePayloadFee = (state: TransactionState, payload: Payload) => {
const nextState = { ...state, ...payload };
const {
@@ -54,7 +101,9 @@ const shouldCalculatePayloadFee = (state: TransactionState, payload: Payload) =>
senderAccount,
action
} = nextState;
+
switch (action) {
+ case TransactionTypes.INTERNAL_TRANSFER:
case TransactionTypes.TRANSFER: {
return Boolean(transferAmount && receiverAddress && senderAccount);
}
@@ -90,6 +139,7 @@ const updateTransaction = (state: TransactionState, payload: Payload): Transacti
const isInputReady = (state: TransactionState): boolean => {
switch (state.action) {
+ case TransactionTypes.INTERNAL_TRANSFER:
case TransactionTypes.TRANSFER: {
return Boolean(state.transferAmount) && Boolean(state.receiverAddress);
}
@@ -274,4 +324,4 @@ const setReceiver = (state: TransactionState, payload: ReceiverPayload): Transac
};
};
-export { updateTransaction, isReadyToExecute, setReceiver, shouldCalculatePayloadFee };
+export { updateTransaction, isReadyToExecute, setReceiver, shouldCalculatePayloadFee, enoughFundsEvaluation };