Skip to content

Commit

Permalink
Include trade.value in calculation of displayed network fees (#9621)
Browse files Browse the repository at this point in the history
* Ensure that trade.value fees are included in displayed network fees

* Remove unused getTotalEthCost function

* Remove unused getTotalEthCost function

* Update ui/app/pages/swaps/swaps.util.js

Co-authored-by: Mark Stacey <[email protected]>

* Lint fix

Co-authored-by: Mark Stacey <[email protected]>
  • Loading branch information
danjm and Gudahtt authored Oct 27, 2020
1 parent a8cb6fb commit a4f817e
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 24 deletions.
12 changes: 9 additions & 3 deletions app/_locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@
"affirmAgree": {
"message": "I Agree"
},
"aggregatorFeeCost": {
"message": "Aggregator network fee"
},
"alertDisableTooltip": {
"message": "This can be changed in \"Settings > Alerts\""
},
Expand Down Expand Up @@ -129,6 +132,9 @@
"message": "MetaMask",
"description": "The name of the application"
},
"approvalAndAggregatorTxFeeCost": {
"message": "Approval and aggregator network fee"
},
"approvalTxGasCost": {
"message": "Approval Tx Gas Cost"
},
Expand Down Expand Up @@ -1685,9 +1691,6 @@
"swapFinalizing": {
"message": "Finalizing..."
},
"swapGasFeeSummary": {
"message": "The gas fee covers the cost of processing your swap and storing it on the Ethereum network. MetaMask does not profit from this fee."
},
"swapGetQuotes": {
"message": "Get quotes"
},
Expand Down Expand Up @@ -1736,6 +1739,9 @@
"message": "$1 quotes available",
"description": "$1 is the number of quotes that the user can select from when opening the list of quotes on the 'view quote' screen"
},
"swapNetworkFeeSummary": {
"message": "The network fee covers the cost of processing your swap and storing it on the Ethereum network. MetaMask does not profit from this fee."
},
"swapNewQuoteIn": {
"message": "New quotes in $1",
"description": "Tells the user the amount of time until the currently displayed quotes are update. $1 is a time that is counting down from 1:00 to 0:00"
Expand Down
15 changes: 12 additions & 3 deletions ui/app/pages/swaps/awaiting-swap/awaiting-swap.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import {
import { SUBMITTED_STATUS } from '../../../helpers/constants/transactions'
import { ASSET_ROUTE, DEFAULT_ROUTE } from '../../../helpers/constants/routes'

import { getRenderableGasFeesForQuote } from '../swaps.util'
import { getRenderableNetworkFeesForQuote } from '../swaps.util'
import SwapsFooter from '../swaps-footer'
import SwapFailureIcon from './swap-failure-icon'
import SwapSuccessIcon from './swap-success-icon'
Expand Down Expand Up @@ -70,8 +70,17 @@ export default function AwaitingSwap ({

let feeinFiat
if (usedQuote && tradeTxParams) {
const renderableGasFees = getRenderableGasFeesForQuote(usedQuote.gasEstimateWithRefund || usedQuote.averageGas, approveTxParams?.gas || '0x0', tradeTxParams.gasPrice, currentCurrency, conversionRate)
feeinFiat = renderableGasFees.feeinFiat?.slice(1)
const renderableNetworkFees = getRenderableNetworkFeesForQuote(
usedQuote.gasEstimateWithRefund || usedQuote.averageGas,
approveTxParams?.gas || '0x0',
tradeTxParams.gasPrice,
currentCurrency,
conversionRate,
tradeTxParams.value,
sourceTokenInfo?.symbol,
usedQuote.sourceAmount,
)
feeinFiat = renderableNetworkFees.feeinFiat?.slice(1)
}

const quotesExpiredEvent = useNewMetricEvent({
Expand Down
2 changes: 1 addition & 1 deletion ui/app/pages/swaps/fee-card/fee-card.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export default function FeeCard ({
position="top"
contentText={(
<>
<p className="fee-card__info-tooltip-paragraph">{ t('swapGasFeeSummary') }</p>
<p className="fee-card__info-tooltip-paragraph">{ t('swapNetworkFeeSummary') }</p>
<p className="fee-card__info-tooltip-paragraph">{ t('swapEstimatedNetworkFeeSummary', [
<span className="fee-card__bold" key="fee-card-bold-1">
{ t('swapEstimatedNetworkFee') }
Expand Down
31 changes: 27 additions & 4 deletions ui/app/pages/swaps/swaps.util.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { ETH_SWAPS_TOKEN_OBJECT } from '../../helpers/constants/swaps'
import { calcTokenValue, calcTokenAmount } from '../../helpers/utils/token-util'
import { constructTxParams, toPrecisionWithoutTrailingZeros } from '../../helpers/utils/util'
import { decimalToHex, getValueFromWeiHex } from '../../helpers/utils/conversions.util'

import { subtractCurrencies } from '../../helpers/utils/conversion-util'
import { formatCurrency } from '../../helpers/utils/confirm-tx.util'
import fetchWithCache from '../../helpers/utils/fetch-with-cache'
Expand Down Expand Up @@ -265,17 +266,34 @@ export async function fetchTokenBalance (address, userAddress) {
return usersToken
}

export function getRenderableGasFeesForQuote (tradeGas, approveGas, gasPrice, currentCurrency, conversionRate) {
export function getRenderableNetworkFeesForQuote (
tradeGas,
approveGas,
gasPrice,
currentCurrency,
conversionRate,
tradeValue,
sourceSymbol,
sourceAmount,
) {
const totalGasLimitForCalculation = (new BigNumber(tradeGas || '0x0', 16)).plus(approveGas || '0x0', 16).toString(16)
const gasTotalInWeiHex = calcGasTotal(totalGasLimitForCalculation, gasPrice)

const nonGasFee = new BigNumber(tradeValue, 16)
.minus(sourceSymbol === 'ETH' ? sourceAmount : 0, 10)
.toString(16)

const totalWeiCost = new BigNumber(gasTotalInWeiHex, 16)
.plus(nonGasFee, 16)
.toString(16)

const ethFee = getValueFromWeiHex({
value: gasTotalInWeiHex,
value: totalWeiCost,
toDenomination: 'ETH',
numberOfDecimals: 5,
})
const rawNetworkFees = getValueFromWeiHex({
value: gasTotalInWeiHex,
value: totalWeiCost,
toCurrency: currentCurrency,
conversionRate,
numberOfDecimals: 2,
Expand All @@ -286,6 +304,7 @@ export function getRenderableGasFeesForQuote (tradeGas, approveGas, gasPrice, cu
rawEthFee: ethFee,
feeInFiat: formattedNetworkFee,
feeInEth: `${ethFee} ETH`,
nonGasFee,
}
}

Expand All @@ -302,6 +321,7 @@ export function quotesToRenderableData (quotes, gasPrice, conversionRate, curren
gasEstimateWithRefund,
averageGas,
fee,
trade,
} = quote
const sourceValue = calcTokenAmount(sourceAmount, sourceTokenInfo.decimals || 18).toString(10)
const destinationValue = calcTokenAmount(destinationAmount, destinationTokenInfo.decimals || 18).toPrecision(8)
Expand All @@ -311,7 +331,7 @@ export function quotesToRenderableData (quotes, gasPrice, conversionRate, curren
rawNetworkFees,
rawEthFee,
feeInEth,
} = getRenderableGasFeesForQuote(
} = getRenderableNetworkFeesForQuote(
(
gasEstimateWithRefund ||
decimalToHex(averageGas || 800000)
Expand All @@ -320,6 +340,9 @@ export function quotesToRenderableData (quotes, gasPrice, conversionRate, curren
gasPrice,
currentCurrency,
conversionRate,
trade.value,
sourceTokenInfo.symbol,
sourceAmount,
)

const slippageMultiplier = (new BigNumber(100 - slippage)).div(100)
Expand Down
47 changes: 34 additions & 13 deletions ui/app/pages/swaps/view-quote/view-quote.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ import MainQuoteSummary from '../main-quote-summary'
import { calcGasTotal } from '../../send/send.utils'
import { getCustomTxParamsData } from '../../confirm-approve/confirm-approve.util'
import ActionableMessage from '../actionable-message'
import { quotesToRenderableData, getRenderableGasFeesForQuote } from '../swaps.util'
import { quotesToRenderableData, getRenderableNetworkFeesForQuote } from '../swaps.util'
import { useTokenTracker } from '../../../hooks/useTokenTracker'
import { QUOTES_EXPIRED_ERROR } from '../../../helpers/constants/swaps'
import CountdownTimer from '../countdown-timer'
Expand Down Expand Up @@ -99,7 +99,7 @@ export default function ViewQuote () {

// Select necessary data
const tradeTxParams = useSelector(getSwapsTradeTxParams)
const { gasPrice } = tradeTxParams || {}
const { gasPrice, value: tradeValue } = tradeTxParams || {}
const customMaxGas = useSelector(getCustomSwapsGas)
const tokenConversionRates = useSelector(getTokenExchangeRates)
const memoizedTokenConversionRates = useEqualityCheck(tokenConversionRates)
Expand Down Expand Up @@ -161,12 +161,6 @@ export default function ViewQuote () {
calcTokenAmount(approveValue, selectedFromToken.decimals).toFixed(9)
)
const approveGas = approveTxParams?.gas
const approveGasTotal = calcGasTotal(approveGas || '0x0', gasPrice)
const approveGasTotalInEth = getValueFromWeiHex({
value: approveGasTotal,
toDenomination: 'ETH',
numberOfDecimals: 4,
})

const renderablePopoverData = useMemo(() => {
return quotesToRenderableData(
Expand Down Expand Up @@ -203,23 +197,30 @@ export default function ViewQuote () {
sourceTokenIconUrl,
} = renderableDataForUsedQuote

const { feeInFiat, feeInEth } = getRenderableGasFeesForQuote(
const { feeInFiat, feeInEth } = getRenderableNetworkFeesForQuote(
usedGasLimit,
approveGas,
gasPrice,
currentCurrency,
conversionRate,
tradeValue,
sourceTokenSymbol,
usedQuote.sourceAmount,
)

const {
feeInFiat: maxFeeInFiat,
feeInEth: maxFeeInEth,
} = getRenderableGasFeesForQuote(
nonGasFee,
} = getRenderableNetworkFeesForQuote(
maxGasLimit,
approveGas,
gasPrice,
currentCurrency,
conversionRate,
tradeValue,
sourceTokenSymbol,
usedQuote.sourceAmount,
)

const tokenCost = (new BigNumber(usedQuote.sourceAmount))
Expand Down Expand Up @@ -378,6 +379,26 @@ export default function ViewQuote () {
}))
}

const nonGasFeeIsPositive = (new BigNumber(nonGasFee, 16)).gt(0)
const approveGasTotal = calcGasTotal(approveGas || '0x0', gasPrice)
const extraNetworkFeeTotalInHexWEI = (new BigNumber(nonGasFee, 16))
.plus(approveGasTotal, 16)
.toString(16)
const extraNetworkFeeTotalInEth = getValueFromWeiHex({
value: extraNetworkFeeTotalInHexWEI,
toDenomination: 'ETH',
numberOfDecimals: 4,
})

let extraInfoRowLabel = ''
if (approveGas && nonGasFeeIsPositive) {
extraInfoRowLabel = t('approvalAndAggregatorTxFeeCost')
} else if (approveGas) {
extraInfoRowLabel = t('approvalTxGasCost')
} else if (nonGasFeeIsPositive) {
extraInfoRowLabel = t('aggregatorFeeCost')
}

const onFeeCardMaxRowClick = () => dispatch(showModal({
name: 'CUSTOMIZE_GAS',
txData: { txParams: { ...tradeTxParams, gas: maxGasLimit } },
Expand All @@ -389,10 +410,10 @@ export default function ViewQuote () {
),
customTotalSupplement: approveGasTotal,
extraInfoRow: (
approveGas
extraInfoRowLabel
? {
label: t('approvalTxGasCost'),
value: t('amountInEth', [approveGasTotalInEth]),
label: extraInfoRowLabel,
value: t('amountInEth', [extraNetworkFeeTotalInEth]),
}
: null
),
Expand Down

0 comments on commit a4f817e

Please sign in to comment.