From ae8803ea34709957e9ac878d9f47cc65c72933d5 Mon Sep 17 00:00:00 2001 From: Mostly Void <7rat13@gmail.com> Date: Tue, 29 Mar 2022 19:13:01 +0530 Subject: [PATCH] Feat: incorporate network fees in Create Payment --- .../CreatePaymentDialog.tsx | 14 +++-- .../CreatePaymentDialogForm.css | 2 +- .../CreatePaymentDialogForm.css.d.ts | 1 + .../CreatePaymentDialogForm.tsx | 60 +++++++++++++++++++ 4 files changed, 72 insertions(+), 5 deletions(-) diff --git a/src/modules/dashboard/components/Dialogs/CreatePaymentDialog/CreatePaymentDialog.tsx b/src/modules/dashboard/components/Dialogs/CreatePaymentDialog/CreatePaymentDialog.tsx index 7cc3853ef02..d04d13dbb1d 100644 --- a/src/modules/dashboard/components/Dialogs/CreatePaymentDialog/CreatePaymentDialog.tsx +++ b/src/modules/dashboard/components/Dialogs/CreatePaymentDialog/CreatePaymentDialog.tsx @@ -11,12 +11,12 @@ import { ActionForm } from '~core/Fields'; import { Address } from '~types/index'; import { ActionTypes } from '~redux/index'; -import { useMembersSubscription } from '~data/index'; +import { useMembersSubscription, useNetworkContracts } from '~data/index'; import { getTokenDecimalsWithFallback } from '~utils/tokens'; import { pipe, withMeta, mapPayload } from '~utils/actions'; import { WizardDialogType } from '~utils/hooks'; -import DialogForm from './CreatePaymentDialogForm'; +import DialogForm, { calculateFee } from './CreatePaymentDialogForm'; const MSG = defineMessages({ amountZero: { @@ -33,7 +33,7 @@ export interface FormValues { forceAction: boolean; domainId: string; recipient: Address; - amount: string; + amount: string; // Amount the receiver finally gets, the initiator pays this plus network fee tokenAddress: Address; annotation: string; motionDomainId: string; @@ -93,6 +93,8 @@ const CreatePaymentDialog = ({ variables: { colonyAddress }, }); + const { feeInverse: networkFeeInverse } = useNetworkContracts(); + const transform = useCallback( pipe( mapPayload((payload) => { @@ -114,6 +116,10 @@ const CreatePaymentDialog = ({ selectedToken && selectedToken.decimals, ); + const amountWithFees = networkFeeInverse + ? calculateFee(amount, networkFeeInverse, decimals).totalToPay + : amount; + return { colonyName, colonyAddress, @@ -121,7 +127,7 @@ const CreatePaymentDialog = ({ domainId, singlePayment: { tokenAddress, - amount, + amount: amountWithFees, // NOTE: The contract only sees this amount decimals, }, annotationMessage, diff --git a/src/modules/dashboard/components/Dialogs/CreatePaymentDialog/CreatePaymentDialogForm.css b/src/modules/dashboard/components/Dialogs/CreatePaymentDialog/CreatePaymentDialogForm.css index cf0e8c92846..52b3fbc308e 100644 --- a/src/modules/dashboard/components/Dialogs/CreatePaymentDialog/CreatePaymentDialogForm.css +++ b/src/modules/dashboard/components/Dialogs/CreatePaymentDialog/CreatePaymentDialogForm.css @@ -24,7 +24,7 @@ text-align: right; } -.domainPotBalance { +.domainPotBalance, .networkFee { font-size: var(--size-tiny); font-weight: var(--weight-bold); text-align: right; diff --git a/src/modules/dashboard/components/Dialogs/CreatePaymentDialog/CreatePaymentDialogForm.css.d.ts b/src/modules/dashboard/components/Dialogs/CreatePaymentDialog/CreatePaymentDialogForm.css.d.ts index d6593844830..868327c13d1 100644 --- a/src/modules/dashboard/components/Dialogs/CreatePaymentDialog/CreatePaymentDialogForm.css.d.ts +++ b/src/modules/dashboard/components/Dialogs/CreatePaymentDialog/CreatePaymentDialogForm.css.d.ts @@ -4,6 +4,7 @@ export const tokenAmountSelect: string; export const tokenAmountContainer: string; export const tokenAmountUsd: string; export const domainPotBalance: string; +export const networkFee: string; export const domainSelects: string; export const tokenAmountInputContainer: string; export const singleUserContainer: string; diff --git a/src/modules/dashboard/components/Dialogs/CreatePaymentDialog/CreatePaymentDialogForm.tsx b/src/modules/dashboard/components/Dialogs/CreatePaymentDialog/CreatePaymentDialogForm.tsx index 072e52abef5..8d9d16406b6 100644 --- a/src/modules/dashboard/components/Dialogs/CreatePaymentDialog/CreatePaymentDialogForm.tsx +++ b/src/modules/dashboard/components/Dialogs/CreatePaymentDialog/CreatePaymentDialogForm.tsx @@ -32,6 +32,7 @@ import { useLoggedInUser, useTokenBalancesForDomainsLazyQuery, AnyUser, + useNetworkContracts, } from '~data/index'; import { getBalanceFromToken, @@ -64,6 +65,10 @@ const MSG = defineMessages({ id: 'dashboard.CreatePaymentDialog.CreatePaymentDialogForm.amount', defaultMessage: 'Amount', }, + fee: { + id: 'dashboard.CreatePaymentDialog.CreatePaymentDialogForm.fee', + defaultMessage: 'Network fee: {fee} {symbol}', + }, token: { id: 'dashboard.CreatePaymentDialog.CreatePaymentDialogForm.address', defaultMessage: 'Token', @@ -114,6 +119,22 @@ const supRenderAvatar = (address: Address, item: ItemDataType) => ( ); +export const calculateFee = ( + receivedAmount: string, // amount that the recipient finally receives + feeInverse: string, + decimals: number, +): { feesInWei: string; totalToPay: string } => { + const amountInWei = moveDecimal(receivedAmount, decimals); + const totalToPay = bigNumberify(amountInWei) + .mul(feeInverse) + .div(bigNumberify(feeInverse).sub(1)); // this formula is easily derivable + const feesInWei = totalToPay.sub(amountInWei); + return { + feesInWei: feesInWei.toString(), + totalToPay: moveDecimal(totalToPay, -1 * decimals), + }; // NOTE: seems like moveDecimal does not have strict typing +}; + const CreatePaymentDialogForm = ({ back, colony, @@ -313,6 +334,8 @@ const CreatePaymentDialogForm = ({ const inputDisabled = !canMakePayment || onlyForceAction || isSubmitting; + const { feeInverse: networkFeeInverse } = useNetworkContracts(); + return ( <> @@ -427,7 +450,44 @@ const CreatePaymentDialogForm = ({ */ forcedFieldError={customAmountError} /> + + {networkFeeInverse && + values.amount && + values.amount !== '0' && + values.amount !== '0.' && + values.amount !== '.' && ( +
+ + ), + symbol: (selectedToken && selectedToken.symbol) || '???', + }} + /> +
+ )} +