Skip to content

Commit

Permalink
Select which chain pays the fee for the dispatch call fee. (#300)
Browse files Browse the repository at this point in the history
* First approach of basic functionality. Need styling and tests

* Work in progress. Need to adjust the select on fee selector

* Finishing last details. Functionality ready
  • Loading branch information
hbulgarini authored Nov 8, 2021
1 parent aa15668 commit 5bac4b2
Show file tree
Hide file tree
Showing 7 changed files with 212 additions and 48 deletions.
12 changes: 10 additions & 2 deletions src/actions/transactionActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ import {
UpdatedTransactionStatusType,
ReceiverPayload,
PayloadEstimatedFee,
TransactionState
TransactionState,
PayFee
} from '../types/transactionTypes';

enum TransactionActionTypes {
Expand All @@ -48,7 +49,8 @@ enum TransactionActionTypes {
SET_TRANSFER_TYPE = 'SET_TRANSFER_TYPE',
ENABLE_TX_BUTTON = 'ENABLE_TX_BUTTON',
DISABLE_TX_BUTTON = 'DISABLE_TX_BUTTON',
RESET = 'RESET'
RESET = 'RESET',
CHANGE_DISPATCH_FEE_PAY_CHAIN = 'CHANGE_DISPATCH_FEE_PAY_CHAIN'
}

const setTransferAmount = (transferAmount: string | null, chainDecimals?: number) => {
Expand Down Expand Up @@ -193,6 +195,11 @@ const disableTXButton = () => ({
type: TransactionActionTypes.DISABLE_TX_BUTTON
});

const changeDispatchFeePayChain = (payFee: PayFee) => ({
payload: { payFee },
type: TransactionActionTypes.CHANGE_DISPATCH_FEE_PAY_CHAIN
});

const TransactionActionCreators = {
setSender,
setAction,
Expand All @@ -212,6 +219,7 @@ const TransactionActionCreators = {
setTransferType,
enableTxButton,
disableTXButton,
changeDispatchFeePayChain,
reset
};

Expand Down
69 changes: 25 additions & 44 deletions src/components/EstimatedFee.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,18 @@
// along with Parity Bridges UI. If not, see <http://www.gnu.org/licenses/>.

import React from 'react';
import { Typography, Tooltip } from '@material-ui/core';
import { fade, makeStyles } from '@material-ui/core/styles';
import HelpOutlineIcon from '@material-ui/icons/HelpOutline';
import { Typography } from '@material-ui/core';
import { makeStyles } from '@material-ui/core/styles';
import { useSourceTarget } from '../contexts/SourceTargetContextProvider';
import { useTransactionContext } from '../contexts/TransactionContext';
import { Alert } from '.';
import { formatBalance } from '@polkadot/util';
import FeeValue from './FeeValue';

const useStyles = makeStyles((theme) => ({
container: {
minHeight: '20px',
display: 'flex'
},
tooltipIcon: {
...theme.typography.body1,
marginTop: 2,
marginLeft: 2,
'&:not(:hover)': {
color: fade(theme.palette.text.hint, 0.75)
}
display: 'flex',
marginTop: theme.spacing(1)
}
}));

Expand All @@ -43,7 +35,7 @@ const getFormattedAmount = (fee: string | null, chainDecimals: number, chainToke
? formatBalance(fee, {
decimals: chainDecimals,
withUnit: chainTokens,
withSi: true
withSi: false
})
: null;

Expand Down Expand Up @@ -74,38 +66,27 @@ export const EstimatedFee = (): React.ReactElement => {
const estimatedSourceFeeAmount = getFormattedAmount(estimatedSourceFee, srcChainDecimals, srcChainTokens[0]);
const targetFeeAmount = getFormattedAmount(estimatedTargetFee, tarChainDecimals, tarChainTokens[0]);

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

return evaluateTransactionStatusError ? (
<Alert severity="error">{evaluateTransactionStatusError}</Alert>
) : (
<>
<div className={classes.container}>
<Typography variant="body1" color="secondary">
{payloadEstimatedFeeLoading && !transactionRunning
? `${feeLabel}...`
: estimatedSourceFeeAmount
? `${feeLabel}: ${estimatedSourceFeeAmount} `
: null}
</Typography>
{!payloadEstimatedFeeLoading && !transactionRunning && estimatedFeeMessageDeliveryAmount && (
<Tooltip
title={`Message Delivery Fee: ${estimatedFeeMessageDeliveryAmount} + Send Message Fee: ${estimatedFeeBridgeCallAmount} `}
arrow
placement="top"
>
<HelpOutlineIcon className={classes.tooltipIcon} />
</Tooltip>
)}
</div>
<Typography variant="body1" color="secondary">
{payloadEstimatedFeeLoading && !transactionRunning
? `${feeLabelTarget}...`
: targetFeeAmount
? `${feeLabelTarget}: ${targetFeeAmount}`
: null}
</Typography>
</>
<Typography variant="body1" color="secondary">
{payloadEstimatedFeeLoading && !transactionRunning ? (
'Calculating fee...'
) : estimatedSourceFeeAmount && targetFeeAmount ? (
<div className={classes.container}>
<Typography variant="body1" color="secondary">
Estimated Fee value
</Typography>
<FeeValue
amount={estimatedSourceFeeAmount}
tooltip={`Message Delivery Fee: ${estimatedFeeMessageDeliveryAmount} ${srcChainTokens[0]} + Send Message Fee: ${estimatedFeeBridgeCallAmount} ${srcChainTokens[0]}`}
chainTokens={srcChainTokens[0]}
showPlus
/>

<FeeValue amount={targetFeeAmount} chainTokens={tarChainTokens[0]} />
</div>
) : null}
</Typography>
);
};
82 changes: 82 additions & 0 deletions src/components/FeePaySelector.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// 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 <http://www.gnu.org/licenses/>.

import React, { useCallback } from 'react';
import { Typography, Select, MenuItem, makeStyles } from '@material-ui/core';
import ChainLogo from './ChainLogo';
import { PayFee } from '../types/transactionTypes';
import { useSourceTarget } from '../contexts/SourceTargetContextProvider';
import { useTransactionContext, useUpdateTransactionContext } from '../contexts/TransactionContext';
import { TransactionActionCreators } from '../actions/transactionActions';

const useStyles = makeStyles((theme) => ({
container: {
minHeight: theme.spacing(2),
display: 'flex',
alignItems: 'center'
},
item: {
marginLeft: theme.spacing(0.8)
}
}));

export default function FeePaySelector() {
const classes = useStyles();
const sourceTargetDetails = useSourceTarget();
const { dispatchTransaction } = useUpdateTransactionContext();
const { payFee } = useTransactionContext();

const {
sourceChainDetails: { chain: sourceChain },
targetChainDetails: { chain: targetChain }
} = sourceTargetDetails;

const onChange = useCallback(
(event) => {
dispatchTransaction(TransactionActionCreators.changeDispatchFeePayChain(event.target.value));
},
[dispatchTransaction]
);

const chain = payFee === PayFee.AtSourceChain ? sourceChain : targetChain;

return (
<div className={classes.container}>
<Typography variant="body1" color="secondary">
Dispatch fee payed on
</Typography>
<div className={classes.item}>
<ChainLogo chain={chain} />
</div>

<div className={classes.item}>
<Select
onChange={onChange}
value={payFee}
disableUnderline
renderValue={(): React.ReactNode => (
<Typography variant="body1" color="secondary" className={classes.item}>
{chain}
</Typography>
)}
>
<MenuItem value={PayFee.AtSourceChain}>Source Chain </MenuItem>
<MenuItem value={PayFee.AtTargetChain}>Target Chain </MenuItem>
</Select>
</div>
</div>
);
}
85 changes: 85 additions & 0 deletions src/components/FeeValue.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// 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 <http://www.gnu.org/licenses/>.

import React from 'react';
import { Typography, Tooltip } from '@material-ui/core';
import { fade, makeStyles } from '@material-ui/core/styles';
import HelpOutlineIcon from '@material-ui/icons/HelpOutline';

const useStyles = makeStyles((theme) => ({
container: {
minHeight: '20px',
display: 'flex'
},
tooltipIcon: {
...theme.typography.body1,
marginTop: 2,
marginLeft: 2,
'&:not(:hover)': {
color: fade(theme.palette.text.hint, 0.75)
}
},
value: {
backgroundColor: '#f5dada',
fontFamily: 'monospace',
paddingLeft: theme.spacing(0.7),
paddingRight: theme.spacing(0.7),
borderRadius: '3px'
},
textContainer: {
marginLeft: theme.spacing(0.5)
}
}));

interface Props {
chainTokens: string;
amount: string;
tooltip?: string;
showPlus?: boolean;
}

interface TextStyle {
text: string;
background?: boolean;
}

const CustomTypography = ({ text, background = false }: TextStyle) => {
const classes = useStyles();
return (
<div className={classes.textContainer}>
<Typography variant="body1" className={background ? classes.value : ''}>
{text}
</Typography>
</div>
);
};

export default function FeeValue({ tooltip = '', chainTokens, amount, showPlus = false }: Props) {
const classes = useStyles();
return (
<div className={classes.container}>
<CustomTypography text={amount} background />
<CustomTypography text={chainTokens} />

{tooltip && (
<Tooltip title={tooltip} arrow placement="top">
<HelpOutlineIcon className={classes.tooltipIcon} />
</Tooltip>
)}
{showPlus && <CustomTypography text={'+'} />}
</div>
);
}
2 changes: 2 additions & 0 deletions src/components/Transfer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { EstimatedFee } from '../components/EstimatedFee';
import { DebouncedTextField } from './DebouncedTextField';
import { useInternalTransfer } from '../hooks/chain/useInternalTransfer';
import { useGUIContext } from '../contexts/GUIContextProvider';
import FeePaySelector from './FeePaySelector';

const useStyles = makeStyles((theme) => ({
inputAmount: {
Expand Down Expand Up @@ -116,6 +117,7 @@ function Transfer() {
<ButtonSubmit disabled={!transactionReadyToExecute} onClick={sendTransaction}>
{buttonLabel}
</ButtonSubmit>
<FeePaySelector />
<EstimatedFee />
</>
);
Expand Down
3 changes: 1 addition & 2 deletions src/hooks/transactions/useEstimatedFeePayload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ import useLaneId from '../chain/useLaneId';
import { getSubstrateDynamicNames } from '../../util/getSubstrateDynamicNames';
import { genericCall } from '../../util/apiUtlis';
import {
PayFee,
PayloadEstimatedFee,
TransactionsActionType,
TransactionState,
Expand Down Expand Up @@ -122,7 +121,7 @@ export const useEstimatedFeePayload = (
origin: {
SourceAccount: account!.addressRaw
},
dispatch_fee_payment: PayFee.AtSourceChain,
dispatch_fee_payment: currentTransactionState.payFee,
spec_version: targetApi.consts.system.version.specVersion.toNumber(),
weight
};
Expand Down
7 changes: 7 additions & 0 deletions src/reducers/transactionReducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,13 @@ export default function transactionReducer(state: TransactionState, action: Tran
transactionReadyToExecute: false
};
}
case TransactionActionTypes.CHANGE_DISPATCH_FEE_PAY_CHAIN: {
return {
...state,
payFee: action.payload.payFee,
shouldEvaluatePayloadEstimatedFee: true
};
}
default:
throw new Error(`Unknown type: ${action.type}`);
}
Expand Down

0 comments on commit 5bac4b2

Please sign in to comment.