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

Commit

Permalink
[CLAIM - Approve] Wire new approve logic into app (fixes broken merge…
Browse files Browse the repository at this point in the history
… stuff also) (#2233)

* move approve logic from Claim > InvestOption

* helper utils

* tweak claim approve hook

* apply @nenadV91's suggested fix

* path
  • Loading branch information
W3stside committed Jan 24, 2022
1 parent 5ebc7d5 commit 8bb8cf4
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 100 deletions.
37 changes: 31 additions & 6 deletions src/custom/hooks/useApproveCallback/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Percent } from '@uniswap/sdk-core'
import { Currency, CurrencyAmount, MaxUint256, Percent } from '@uniswap/sdk-core'
import { useActiveWeb3React } from '@src/hooks/web3'
import { Field } from '@src/state/swap/actions'
import { computeSlippageAdjustedAmounts } from 'utils/prices'
Expand All @@ -9,6 +9,11 @@ import TradeGp from 'state/swap/TradeGp'
import { ApproveCallbackParams, useApproveCallback } from './useApproveCallbackMod'
export { ApprovalState, useApproveCallback } from './useApproveCallbackMod'

import { ClaimType } from 'state/claim/hooks'
import { supportedChainId } from 'utils/supportedChainId'
import { tryAtomsToCurrency } from 'state/swap/extension'
import { EnhancedUserClaimData } from 'pages/Claim/types'

type ApproveCallbackFromTradeParams = Pick<
ApproveCallbackParams,
'openTransactionConfirmationModal' | 'closeModals' | 'amountToCheckAgainstAllowance'
Expand Down Expand Up @@ -50,24 +55,44 @@ export type OptionalApproveCallbackParams = {
transactionSummary: string
}

type ApproveCallbackFromClaimParams = Omit<ApproveCallbackParams, 'spender'>
type ApproveCallbackFromClaimParams = Omit<
ApproveCallbackParams,
'spender' | 'amountToApprove' | 'amountToCheckAgainstAllowance'
> & {
claim: EnhancedUserClaimData
investmentAmount: string | undefined
}

export function useApproveCallbackFromClaim({
openTransactionConfirmationModal,
closeModals,
amountToApprove,
amountToCheckAgainstAllowance,
claim,
investmentAmount,
}: ApproveCallbackFromClaimParams) {
const { chainId } = useActiveWeb3React()
const supportedChain = supportedChainId(chainId)

const vCowContract = chainId ? V_COW_CONTRACT_ADDRESS[chainId] : undefined

// Claim only approves GNO and USDC (GnoOption & Investor, respectively.)
const approveAmounts = useMemo(() => {
if (supportedChain && (claim.type === ClaimType.GnoOption || claim.type === ClaimType.Investor)) {
const investmentCurrency = claim.currencyAmount?.currency as Currency
const amountToCheckAgainstAllowance = tryAtomsToCurrency(investmentAmount, investmentCurrency)
return {
amountToApprove: CurrencyAmount.fromRawAmount(investmentCurrency, MaxUint256),
amountToCheckAgainstAllowance,
}
}
return undefined
}, [claim, investmentAmount, supportedChain])

// Params: modal cbs, amountToApprove: token user is investing e.g, spender: vcow token contract
return useApproveCallback({
openTransactionConfirmationModal,
closeModals,
amountToApprove,
spender: vCowContract,
amountToCheckAgainstAllowance,
amountToApprove: approveAmounts?.amountToApprove,
amountToCheckAgainstAllowance: approveAmounts?.amountToCheckAgainstAllowance,
})
}
66 changes: 48 additions & 18 deletions src/custom/pages/Claim/InvestmentFlow/InvestOption.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ import { InvestTokenGroup, TokenLogo, InvestSummary, InvestInput, InvestAvailabl
import { formatSmartLocaleAware } from 'utils/format'
import Row from 'components/Row'
import CheckCircle from 'assets/cow-swap/check.svg'
import { InvestOptionProps } from '.'
import { ApprovalState } from 'hooks/useApproveCallback'
import { InvestmentFlowProps } from '.'
import { ApprovalState, useApproveCallbackFromClaim } from 'hooks/useApproveCallback'
import { useCurrencyBalance } from 'state/wallet/hooks'
import { useActiveWeb3React } from 'hooks/web3'
import { useClaimDispatchers, useClaimState } from 'state/claim/hooks'
import { ClaimType, useClaimDispatchers, useClaimState } from 'state/claim/hooks'
import { StyledNumericalInput } from 'components/CurrencyInputPanel/CurrencyInputPanelMod'

import { ButtonConfirmed } from 'components/Button'
Expand All @@ -20,6 +20,8 @@ import { useErrorModal } from 'hooks/useErrorMessageAndModal'
import { tryParseAmount } from 'state/swap/hooks'
import { calculateInvestmentAmounts, calculatePercentage } from 'state/claim/hooks/utils'
import { AMOUNT_PRECISION, PERCENTAGE_PRECISION } from 'constants/index'
import { EnhancedUserClaimData } from '../types'
import { OperationType } from 'components/TransactionConfirmationModal'

const ErrorMsgs = {
InsufficientBalance: (symbol = '') => `Insufficient ${symbol} balance to cover investment amount`,
Expand All @@ -28,14 +30,45 @@ const ErrorMsgs = {
NotApproved: (symbol = '') => `Please approve ${symbol} token`,
}

export default function InvestOption({ approveData, claim, optionIndex }: InvestOptionProps) {
type InvestOptionProps = {
claim: EnhancedUserClaimData
optionIndex: number
openModal: InvestmentFlowProps['modalCbs']['openModal']
closeModal: InvestmentFlowProps['modalCbs']['closeModal']
}

const _claimApproveMessageMap = (type: ClaimType) => {
switch (type) {
case ClaimType.GnoOption:
return 'Approving GNO for investing in vCOW'
case ClaimType.Investor:
return 'Approving USDC for investing in vCOW'
// Shouldn't happen, type safe
default:
return 'Unknown token approval. Please check configuration.'
}
}

export default function InvestOption({ claim, optionIndex, openModal, closeModal }: InvestOptionProps) {
const { currencyAmount, price, cost: maxCost } = claim

const { account } = useActiveWeb3React()
const { updateInvestAmount, updateInvestError } = useClaimDispatchers()
const { investFlowData, activeClaimAccount } = useClaimState()

const { handleSetError, handleCloseError, ErrorModal } = useErrorModal()
const investmentAmount = investFlowData[optionIndex].investedAmount

const { account } = useActiveWeb3React()
// Approve hooks
const [approveState, approveCallback] = useApproveCallbackFromClaim({
openTransactionConfirmationModal: () => openModal(_claimApproveMessageMap(claim.type), OperationType.APPROVE_TOKEN),
closeModals: closeModal,
claim,
investmentAmount,
})

const isEtherApproveState = approveState === ApprovalState.UNKNOWN

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

const [percentage, setPercentage] = useState<string>('0')
const [typedValue, setTypedValue] = useState<string>('0')
Expand Down Expand Up @@ -63,7 +96,7 @@ export default function InvestOption({ approveData, claim, optionIndex }: Invest
const isSelfClaiming = account === activeClaimAccount
const noBalance = !balance || balance.equalTo('0')

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

// on invest max amount click handler
Expand All @@ -76,9 +109,6 @@ export default function InvestOption({ approveData, claim, optionIndex }: Invest
setTypedValue(value.toExact() || '')
}, [balance, maxCost, noBalance])

// Cache approveData methods
const approveCallback = approveData?.approveCallback
const approveState = approveData?.approveState
// Save "local" approving state (pre-BC) for rendering spinners etc
const [approving, setApproving] = useState(false)
const handleApprove = useCallback(async () => {
Expand All @@ -100,8 +130,8 @@ export default function InvestOption({ approveData, claim, optionIndex }: Invest
}, [approveCallback, handleCloseError, handleSetError, token?.symbol])

const vCowAmount = useMemo(
() => calculateInvestmentAmounts(claim, investedAmount)?.vCowAmount,
[claim, investedAmount]
() => calculateInvestmentAmounts(claim, investmentAmount)?.vCowAmount,
[claim, investmentAmount]
)

// if there is investmentAmount in redux state for this option set it as typedValue
Expand Down Expand Up @@ -212,9 +242,9 @@ export default function InvestOption({ approveData, claim, optionIndex }: Invest

<span>
<b>Token approval</b>
{approveData ? (
{!isEtherApproveState ? (
<i>
{approveData.approveState !== ApprovalState.APPROVED ? (
{approveState !== ApprovalState.APPROVED ? (
`${currencyAmount?.currency?.symbol} not approved`
) : (
<Row>
Expand All @@ -231,8 +261,8 @@ export default function InvestOption({ approveData, claim, optionIndex }: Invest
</Row>
</i>
)}
{/* Approve button - @biocom styles for this found in ./styled > InputSummary > ${ButtonPrimary}*/}
{approveData && approveState !== ApprovalState.APPROVED && (
{/* Token Approve buton - not shown for ETH */}
{!isEtherApproveState && approveState !== ApprovalState.APPROVED && (
<ButtonConfirmed
buttonSize={ButtonSize.SMALL}
onClick={handleApprove}
Expand All @@ -243,9 +273,9 @@ export default function InvestOption({ approveData, claim, optionIndex }: Invest
>
{approving || approveState === ApprovalState.PENDING ? (
<Loader stroke="white" />
) : approveData ? (
) : (
<span>Approve {currencyAmount?.currency?.symbol}</span>
) : null}
)}
</ButtonConfirmed>
)}
</span>
Expand Down
43 changes: 7 additions & 36 deletions src/custom/pages/Claim/InvestmentFlow/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import { ClaimSummaryView } from 'pages/Claim/ClaimSummary'
import { Stepper } from 'components/Stepper'

import {
ClaimType,
useClaimState,
useUserEnhancedClaimData,
useClaimDispatchers,
Expand All @@ -25,13 +24,13 @@ import { ClaimStatus } from 'state/claim/actions'
import { InvestClaim } from 'state/claim/reducer'
import { calculateInvestmentAmounts } from 'state/claim/hooks/utils'

import { ApprovalState, OptionalApproveCallbackParams } from 'hooks/useApproveCallback'
import { useActiveWeb3React } from 'hooks/web3'

import InvestOption from './InvestOption'
import { ClaimCommonTypes, ClaimWithInvestmentData, EnhancedUserClaimData } from '../types'
import { COW_LINKS } from 'pages/Claim'
import { ExternalLink } from 'theme'
import { OperationType } from 'components/TransactionConfirmationModal'

const STEPS_DATA = [
{
Expand All @@ -47,34 +46,11 @@ const STEPS_DATA = [
},
]

export type InvestOptionProps = {
claim: EnhancedUserClaimData
optionIndex: number
approveData:
| { approveState: ApprovalState; approveCallback: (optionalParams?: OptionalApproveCallbackParams) => void }
| undefined
}

type InvestmentFlowProps = Pick<ClaimCommonTypes, 'hasClaims'> & {
export type InvestmentFlowProps = Pick<ClaimCommonTypes, 'hasClaims'> & {
isAirdropOnly: boolean
gnoApproveData: InvestOptionProps['approveData']
usdcApproveData: InvestOptionProps['approveData']
}

type TokenApproveName = 'gnoApproveData' | 'usdcApproveData'
type TokenApproveData = {
[key in TokenApproveName]: InvestOptionProps['approveData'] | undefined
}

// map claim type to token approve data
function _claimToTokenApproveData(claimType: ClaimType, tokenApproveData: TokenApproveData) {
switch (claimType) {
case ClaimType.GnoOption:
return tokenApproveData.gnoApproveData
case ClaimType.Investor:
return tokenApproveData.usdcApproveData
default:
return undefined
modalCbs: {
openModal: (message: string, operationType: OperationType) => void
closeModal: () => void
}
}

Expand Down Expand Up @@ -118,7 +94,7 @@ function _calculateTotalVCow(allClaims: ClaimWithInvestmentData[]) {
)
}

export default function InvestmentFlow({ hasClaims, isAirdropOnly, ...tokenApproveData }: InvestmentFlowProps) {
export default function InvestmentFlow({ hasClaims, isAirdropOnly, modalCbs }: InvestmentFlowProps) {
const { account } = useActiveWeb3React()
const { selected, activeClaimAccount, claimStatus, isInvestFlowActive, investFlowStep, investFlowData } =
useClaimState()
Expand Down Expand Up @@ -202,12 +178,7 @@ export default function InvestmentFlow({ hasClaims, isAirdropOnly, ...tokenAppro
</p>

{selectedClaims.map((claim, index) => (
<InvestOption
key={claim.index}
optionIndex={index}
approveData={_claimToTokenApproveData(claim.type, tokenApproveData)}
claim={claim}
/>
<InvestOption key={claim.index} optionIndex={index} claim={claim} {...modalCbs} />
))}

{hasError && <InvestFlowValidation>Fix the errors before continuing</InvestFlowValidation>}
Expand Down
39 changes: 2 additions & 37 deletions src/custom/pages/Claim/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { useCallback, useEffect, useMemo } from 'react'
import { CurrencyAmount, MaxUint256 } from '@uniswap/sdk-core'
import { useActiveWeb3React } from 'hooks/web3'
import { useUserEnhancedClaimData, useUserUnclaimedAmount, useClaimCallback, ClaimInput } from 'state/claim/hooks'
import { PageWrapper } from 'pages/Claim/styled'
Expand All @@ -21,12 +20,9 @@ import InvestmentFlow from './InvestmentFlow'
import { useClaimDispatchers, useClaimState } from 'state/claim/hooks'
import { ClaimStatus } from 'state/claim/actions'

import { useApproveCallbackFromClaim } from 'hooks/useApproveCallback'
import { OperationType } from 'components/TransactionConfirmationModal'
import useTransactionConfirmationModal from 'hooks/useTransactionConfirmationModal'

import { GNO, USDC_BY_CHAIN } from 'constants/tokens'
import { isSupportedChain } from 'utils/supportedChainId'
import { useErrorModal } from 'hooks/useErrorMessageAndModal'
import FooterNavButtons from './FooterNavButtons'

Expand All @@ -40,7 +36,7 @@ export const COW_LINKS = {
}

export default function Claim() {
const { account, chainId } = useActiveWeb3React()
const { account } = useActiveWeb3React()

const {
// address/ENS address
Expand Down Expand Up @@ -182,26 +178,6 @@ export default function Claim() {
OperationType.APPROVE_TOKEN
)

const [gnoApproveState, gnoApproveCallback] = useApproveCallbackFromClaim({
openTransactionConfirmationModal: () => openModal(GNO_CLAIM_APPROVE_MESSAGE, OperationType.APPROVE_TOKEN),
closeModals: closeModal,
// approve max unit256 amount
amountToApprove: isSupportedChain(chainId) ? CurrencyAmount.fromRawAmount(GNO[chainId], MaxUint256) : undefined,
// TODO: enable, fix this
// amountToCheckAgainstAllowance: investmentAmountAsCurrency,
})

const [usdcApproveState, usdcApproveCallback] = useApproveCallbackFromClaim({
openTransactionConfirmationModal: () => openModal(USDC_CLAIM_APPROVE_MESSAGE, OperationType.APPROVE_TOKEN),
closeModals: closeModal,
// approve max unit256 amount
amountToApprove: isSupportedChain(chainId)
? CurrencyAmount.fromRawAmount(USDC_BY_CHAIN[chainId], MaxUint256)
: undefined,
// TODO: enable, fix this
// amountToCheckAgainstAllowance: investmentAmountAsCurrency,
})

return (
<PageWrapper>
{/* Approve confirmation modal */}
Expand Down Expand Up @@ -231,18 +207,7 @@ export default function Claim() {
{/* IS Airdrop + investing (advanced) */}
<ClaimsTable isAirdropOnly={isAirdropOnly} hasClaims={hasClaims} />
{/* Investing vCOW flow (advanced) */}
<InvestmentFlow
isAirdropOnly={isAirdropOnly}
hasClaims={hasClaims}
gnoApproveData={{
approveCallback: gnoApproveCallback,
approveState: gnoApproveState,
}}
usdcApproveData={{
approveCallback: usdcApproveCallback,
approveState: usdcApproveState,
}}
/>
<InvestmentFlow isAirdropOnly={isAirdropOnly} hasClaims={hasClaims} modalCbs={{ openModal, closeModal }} />

<FooterNavButtons
handleCheckClaim={handleCheckClaim}
Expand Down
Loading

0 comments on commit 8bb8cf4

Please sign in to comment.