Skip to content
This repository was archived by the owner on Jun 24, 2022. It is now read-only.

Commit

Permalink
Pr2256/follow up (#2279)
Browse files Browse the repository at this point in the history
* Do not block on EOAs low native balance

* Updated InsufficientNativeBalance error message

* Added estimatedGas and related boilerplate to claim redux state

* Refactored useClaimCallback hook

Split claimCallback in 3:
- claimCallback - does the same as before
- estimateGasCallback - exposed externally to estimate gas usage based
  on claim input
- getClaimInput - internal callback to prepare claimMany call args

* Refactored when claimInputData is calculated to be used when estimating gas

* Estimating gas usage based on claimInput and storing it on redux

* Refactored gas cost calculation and displayig it in the UI when needed

* Using the gasMargin only for executing the call

* We don't need to track whether it's a smart contract wallet

Co-authored-by: Leandro <[email protected]>
  • Loading branch information
alfetopito and Leandro authored Jan 25, 2022
1 parent f58f3f0 commit 9b3cde3
Show file tree
Hide file tree
Showing 5 changed files with 157 additions and 81 deletions.
45 changes: 24 additions & 21 deletions src/custom/pages/Claim/InvestmentFlow/InvestOption.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useCallback, useMemo, useState, useEffect } from 'react'
import { Percent } from '@uniswap/sdk-core'
import { CurrencyAmount, Percent } from '@uniswap/sdk-core'
import { BigNumber } from '@ethersproject/bignumber'

import CowProtocolLogo from 'components/CowProtocolLogo'
import { InvestTokenGroup, TokenLogo, InvestSummary, InvestInput, InvestAvailableBar } from '../styled'
Expand All @@ -21,27 +22,25 @@ import { tryParseAmount } from 'state/swap/hooks'
import { calculateInvestmentAmounts, calculatePercentage } from 'state/claim/hooks/utils'
import { AMOUNT_PRECISION, PERCENTAGE_PRECISION } from 'constants/index'
import { useGasPrices } from 'state/gas/hooks'
import { _estimateTxCost } from 'components/swap/EthWethWrap/helpers'
import { useWalletInfo } from 'hooks/useWalletInfo'
import { AVG_APPROVE_COST_GWEI } from 'components/swap/EthWethWrap/helpers'

const ErrorMsgs = {
InsufficientBalance: (symbol = '') => `Insufficient ${symbol} balance to cover investment amount`,
OverMaxInvestment: `Your investment amount can't be above the maximum investment allowed`,
InvestmentIsZero: `Your investment amount can't be zero`,
NotApproved: (symbol = '') => `Please approve ${symbol} token`,
InsufficientNativeBalance: (symbol = '', action = "won't") =>
`You ${action} have enough ${symbol} to pay the network transaction fee`,
InsufficientNativeBalance: (symbol = '', amount = '') =>
`You might not have enough ${symbol} to pay for the network transaction fee (estimated ${amount} ${symbol})`,
}

export default function InvestOption({ approveData, claim, optionIndex }: InvestOptionProps) {
const { currencyAmount, price, cost: maxCost } = claim
const { updateInvestAmount, updateInvestError } = useClaimDispatchers()
const { investFlowData, activeClaimAccount } = useClaimState()
const { investFlowData, activeClaimAccount, estimatedGas } = useClaimState()

const { handleSetError, handleCloseError, ErrorModal } = useErrorModal()

const { account, chainId } = useActiveWeb3React()
const { isSmartContractWallet } = useWalletInfo()

const [percentage, setPercentage] = useState<string>('0')
const [typedValue, setTypedValue] = useState<string>('')
Expand All @@ -65,19 +64,28 @@ export default function InvestOption({ approveData, claim, optionIndex }: Invest
)

const token = currencyAmount?.currency
const isNative = token?.isNative
const balance = useCurrencyBalance(account || undefined, token)

const gasPrice = useGasPrices(chainId)
const { singleTxCost } = useMemo(
() => _estimateTxCost(gasPrice, token?.isNative ? token : undefined),
[gasPrice, token]
)
const gasPrice = useGasPrices(isNative ? chainId : undefined)

const isSelfClaiming = account === activeClaimAccount
const noBalance = !balance || balance.equalTo('0')

const isApproved = approveData?.approveState === ApprovalState.APPROVED
const isNative = token?.isNative

const gasCost = useMemo(() => {
if (!estimatedGas || !isNative) {
return
}

// Based on how much gas will be used (estimatedGas) and current gas prices (if available)
// calculate how much that would cost in native currency.
// We pick `fast` to be conservative. Also, it's non-blocking, so the user is aware but can proceed
const amount = BigNumber.from(estimatedGas).mul(gasPrice?.fast || AVG_APPROVE_COST_GWEI)

return CurrencyAmount.fromRawAmount(token, amount.toString())
}, [estimatedGas, gasPrice?.fast, isNative, token])

// on invest max amount click handler
const setMaxAmount = useCallback(() => {
Expand Down Expand Up @@ -164,12 +172,8 @@ export default function InvestOption({ approveData, claim, optionIndex }: Invest
error = ErrorMsgs.OverMaxInvestment
} else if (parsedAmount.greaterThan(balance)) {
error = ErrorMsgs.InsufficientBalance(token?.symbol)
} else if (isNative && parsedAmount && singleTxCost?.add(parsedAmount).greaterThan(balance)) {
if (isSmartContractWallet) {
warning = ErrorMsgs.InsufficientNativeBalance(token?.symbol, 'might not')
} else {
error = ErrorMsgs.InsufficientNativeBalance(token?.symbol)
}
} else if (isNative && gasCost && parsedAmount.add(gasCost).greaterThan(balance)) {
warning = ErrorMsgs.InsufficientNativeBalance(token?.symbol, formatSmartLocaleAware(gasCost))
}
setInputWarning(warning || '')

Expand Down Expand Up @@ -203,8 +207,7 @@ export default function InvestOption({ approveData, claim, optionIndex }: Invest
setInputError,
resetInputError,
setInvestedAmount,
isSmartContractWallet,
singleTxCost,
gasCost,
])

return (
Expand Down
35 changes: 21 additions & 14 deletions src/custom/pages/Claim/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ export default function Claim() {
// claiming
setClaimStatus,
setClaimedAmount,
setEstimatedGas,
// investing
setIsInvestFlowActive,
// claim row selection
Expand Down Expand Up @@ -96,7 +97,7 @@ export default function Claim() {
const isPaidClaimsOnly = useMemo(() => hasPaidClaim(userClaimData) && !hasFreeClaim(userClaimData), [userClaimData])

// claim callback
const { claimCallback } = useClaimCallback(activeClaimAccount)
const { claimCallback, estimateGasCallback } = useClaimCallback(activeClaimAccount)

// handle change account
const handleChangeAccount = () => {
Expand All @@ -113,6 +114,20 @@ export default function Claim() {
setInputAddress('')
}

// aggregate the input for claim callback
const claimInputData = useMemo(() => {
const freeClaims = getFreeClaims(userClaimData)
const paidClaims = prepareInvestClaims(investFlowData, userClaimData)

const inputData = freeClaims.map(({ index }) => ({ index }))
return inputData.concat(paidClaims)
}, [investFlowData, userClaimData])

// track gas price estimation for given input data
useEffect(() => {
estimateGasCallback(claimInputData).then((gas) => setEstimatedGas(gas?.toString() || ''))
}, [claimInputData, estimateGasCallback, setEstimatedGas])

// handle submit claim
const handleSubmitClaim = useCallback(() => {
// Reset error handling
Expand All @@ -121,8 +136,6 @@ export default function Claim() {
// just to be sure
if (!activeClaimAccount) return

const freeClaims = getFreeClaims(userClaimData)

const sendTransaction = (inputData: ClaimInput[]) => {
setClaimStatus(ClaimStatus.ATTEMPTING)
claimCallback(inputData)
Expand All @@ -137,32 +150,26 @@ export default function Claim() {
})
}

const inputData = freeClaims.map(({ index }) => ({ index }))

// check if there are any selected (paid) claims
if (!selected.length) {
console.log('Starting claiming with', inputData)
sendTransaction(inputData)
console.log('Starting claiming with', claimInputData)
sendTransaction(claimInputData)
} else if (investFlowStep == 2) {
// Free claims + selected investment opportunities
const investClaims = prepareInvestClaims(investFlowData, userClaimData)
inputData.push(...investClaims)
console.log('Starting claiming with', inputData)
sendTransaction(inputData)
console.log('Starting claiming with', claimInputData)
sendTransaction(claimInputData)
} else {
setIsInvestFlowActive(true)
}
}, [
handleCloseError,
activeClaimAccount,
userClaimData,
selected.length,
investFlowStep,
setClaimStatus,
claimCallback,
setClaimedAmount,
handleSetError,
investFlowData,
claimInputData,
setIsInvestFlowActive,
])

Expand Down
2 changes: 2 additions & 0 deletions src/custom/state/claim/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export type ClaimActions = {
// claiming
setClaimStatus: (payload: ClaimStatus) => void
setClaimedAmount: (payload: string) => void
setEstimatedGas: (payload: string) => void

// investing
setIsInvestFlowActive: (payload: boolean) => void
Expand All @@ -43,6 +44,7 @@ export const setIsSearchUsed = createAction<boolean>('claim/setIsSearchUsed')
// claiming
export const setClaimedAmount = createAction<string>('claim/setClaimedAmount')
export const setClaimStatus = createAction<ClaimStatus>('claim/setClaimStatus')
export const setEstimatedGas = createAction<string>('claim/setEstimatedGas')

// investing
export const setIsInvestFlowActive = createAction<boolean>('claim/setIsInvestFlowActive')
Expand Down
Loading

0 comments on commit 9b3cde3

Please sign in to comment.