From f1d7b4d66ca4410c1556976f0d394d8ac9cdfde6 Mon Sep 17 00:00:00 2001
From: David W3stside
Date: Thu, 20 Jan 2022 11:59:03 +0000
Subject: [PATCH 1/3] move approve logic from Claim > InvestOption
---
.../Claim/InvestmentFlow/InvestOption.tsx | 68 +++++++++++++------
.../pages/Claim/InvestmentFlow/index.tsx | 46 +++----------
src/custom/pages/Claim/index.tsx | 42 +-----------
3 files changed, 59 insertions(+), 97 deletions(-)
diff --git a/src/custom/pages/Claim/InvestmentFlow/InvestOption.tsx b/src/custom/pages/Claim/InvestmentFlow/InvestOption.tsx
index 0dcc0182f..15b5f1357 100644
--- a/src/custom/pages/Claim/InvestmentFlow/InvestOption.tsx
+++ b/src/custom/pages/Claim/InvestmentFlow/InvestOption.tsx
@@ -6,11 +6,11 @@ import { InvestTokenGroup, TokenLogo, InvestSummary, InvestInput, InvestAvailabl
import { formatSmart } 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'
@@ -20,6 +20,8 @@ import { useErrorModal } from 'hooks/useErrorMessageAndModal'
import { tryParseAmount } from 'state/swap/hooks'
import { ONE_HUNDRED_PERCENT, ZERO_PERCENT } from 'constants/misc'
import { PERCENTAGE_PRECISION } from 'constants/index'
+import { EnhancedUserClaimData } from '../types'
+import { OperationType } from 'components/TransactionConfirmationModal'
enum ErrorMsgs {
Initial = 'Insufficient balance to cover the selected investment amount. Either modify the investment amount or unselect the investment option to move forward',
@@ -27,21 +29,50 @@ enum ErrorMsgs {
MaxCost = 'Selected amount is higher than available investment amount, please modify the input amount to move forward',
}
-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 } = 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,
+ claimType: claim.type,
+ investmentAmount,
+ })
+
+ const isEtherApproveState = approveState === ApprovalState.UNKNOWN
+
+ const { handleSetError, handleCloseError, ErrorModal } = useErrorModal()
const [percentage, setPercentage] = useState('0')
const [typedValue, setTypedValue] = useState('0')
const [inputError, setInputError] = useState('')
- const investedAmount = investFlowData[optionIndex].investedAmount
-
const token = currencyAmount?.currency
const balance = useCurrencyBalance(account || undefined, token)
@@ -101,9 +132,6 @@ export default function InvestOption({ approveData, claim, optionIndex }: Invest
[balance, maxCost, optionIndex, token, updateInvestAmount]
)
- // 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 () => {
@@ -125,13 +153,13 @@ export default function InvestOption({ approveData, claim, optionIndex }: Invest
}, [approveCallback, handleCloseError, handleSetError, token?.symbol])
const vCowAmount = useMemo(() => {
- if (!token || !price || !investedAmount) {
+ if (!token || !price || !investmentAmount) {
return
}
- const investA = CurrencyAmount.fromRawAmount(token, investedAmount)
+ const investA = CurrencyAmount.fromRawAmount(token, investmentAmount)
return price.quote(investA)
- }, [investedAmount, price, token])
+ }, [investmentAmount, price, token])
// if its claiming for someone else we will set values to max
// if there is not enough balance then we will set an error
@@ -177,9 +205,9 @@ export default function InvestOption({ approveData, claim, optionIndex }: Invest
Token approval
- {approveData ? (
+ {!isEtherApproveState ? (
- {approveData.approveState !== ApprovalState.APPROVED ? (
+ {approveState !== ApprovalState.APPROVED ? (
`${currencyAmount?.currency?.symbol} not approved`
) : (
@@ -196,8 +224,8 @@ export default function InvestOption({ approveData, claim, optionIndex }: Invest
)}
- {/* 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 && (
{approving || approveState === ApprovalState.PENDING ? (
- ) : approveData ? (
+ ) : (
Approve {currencyAmount?.currency?.symbol}
- ) : null}
+ )}
)}
diff --git a/src/custom/pages/Claim/InvestmentFlow/index.tsx b/src/custom/pages/Claim/InvestmentFlow/index.tsx
index 186b66c14..915b1bf98 100644
--- a/src/custom/pages/Claim/InvestmentFlow/index.tsx
+++ b/src/custom/pages/Claim/InvestmentFlow/index.tsx
@@ -10,46 +10,23 @@ import {
AccountClaimSummary,
TokenLogo,
} from 'pages/Claim/styled'
-import { ClaimType, useClaimState, useUserEnhancedClaimData, useClaimDispatchers } from 'state/claim/hooks'
-import { ClaimCommonTypes, EnhancedUserClaimData } from '../types'
+import { useClaimState, useUserEnhancedClaimData, useClaimDispatchers } from 'state/claim/hooks'
+import { ClaimCommonTypes } from '../types'
import { ClaimStatus } from 'state/claim/actions'
import { useActiveWeb3React } from 'hooks/web3'
-import { ApprovalState, OptionalApproveCallbackParams } from 'hooks/useApproveCallback'
import InvestOption from './InvestOption'
import CowProtocolLogo from 'components/CowProtocolLogo'
+import { OperationType } from 'components/TransactionConfirmationModal'
-export type InvestOptionProps = {
- claim: EnhancedUserClaimData
- optionIndex: number
- approveData:
- | { approveState: ApprovalState; approveCallback: (optionalParams?: OptionalApproveCallbackParams) => void }
- | undefined
-}
-
-type InvestmentFlowProps = Pick & {
+export type InvestmentFlowProps = Pick & {
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
}
}
-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 } = useClaimState()
const { initInvestFlowData } = useClaimDispatchers()
@@ -99,12 +76,7 @@ export default function InvestmentFlow({ hasClaims, isAirdropOnly, ...tokenAppro
{selectedClaims.map((claim, index) => (
-
+
))}
{/* TODO: Update this with real data */}
diff --git a/src/custom/pages/Claim/index.tsx b/src/custom/pages/Claim/index.tsx
index ab5563f97..3a89c7bf3 100644
--- a/src/custom/pages/Claim/index.tsx
+++ b/src/custom/pages/Claim/index.tsx
@@ -1,6 +1,5 @@
import { useEffect, useMemo } from 'react'
import { Trans } from '@lingui/macro'
-import { CurrencyAmount, MaxUint256 } from '@uniswap/sdk-core'
import { useActiveWeb3React } from 'hooks/web3'
import { useUserEnhancedClaimData, useUserUnclaimedAmount, useClaimCallback, ClaimInput } from 'state/claim/hooks'
import { ButtonPrimary, ButtonSecondary } from 'components/Button'
@@ -23,20 +22,14 @@ 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 { EnhancedUserClaimData } from './types'
-const GNO_CLAIM_APPROVE_MESSAGE = 'Approving GNO for investing in vCOW'
-const USDC_CLAIM_APPROVE_MESSAGE = 'Approving USDC for investing in vCOW'
-
export default function Claim() {
- const { account, chainId } = useActiveWeb3React()
+ const { account } = useActiveWeb3React()
const {
// address/ENS address
@@ -197,26 +190,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 (
{/* Approve confirmation modal */}
@@ -248,18 +221,7 @@ export default function Claim() {
hasClaims={hasClaims}
/>
{/* Investing vCOW flow (advanced) */}
-
+
{/* General claim vCOW button (no invest) */}
From 0cc5d203d343f46fa9e4591abf5817e8470c5b85 Mon Sep 17 00:00:00 2001
From: David W3stside
Date: Thu, 20 Jan 2022 11:59:33 +0000
Subject: [PATCH 2/3] helper utils
---
src/custom/state/claim/hooks/utils.ts | 21 ++++++++++++++++++---
src/custom/state/swap/extension.ts | 6 ++++++
2 files changed, 24 insertions(+), 3 deletions(-)
diff --git a/src/custom/state/claim/hooks/utils.ts b/src/custom/state/claim/hooks/utils.ts
index b16cf522e..e811a3047 100644
--- a/src/custom/state/claim/hooks/utils.ts
+++ b/src/custom/state/claim/hooks/utils.ts
@@ -159,17 +159,32 @@ export type PaidClaimTypeToPriceMap = {
[type in ClaimType]: { token: Token; amount: string } | undefined
}
+export function claimTypeToToken(type: ClaimType, chainId: SupportedChainId) {
+ switch (type) {
+ case ClaimType.GnoOption:
+ return GNO[chainId]
+ case ClaimType.Investor:
+ return USDC_BY_CHAIN[chainId]
+ case ClaimType.UserOption:
+ return GpEther.onChain(chainId)
+ case ClaimType.Advisor:
+ case ClaimType.Airdrop:
+ case ClaimType.Team:
+ return undefined
+ }
+}
+
/**
* Helper function to get vCow price based on claim type and chainId
*/
export function claimTypeToTokenAmount(type: ClaimType, chainId: SupportedChainId, prices: VCowPrices) {
switch (type) {
case ClaimType.GnoOption:
- return { token: GNO[chainId], amount: prices.gno as string }
+ return { token: claimTypeToToken(ClaimType.GnoOption, chainId) as Token, amount: prices.gno as string }
case ClaimType.Investor:
- return { token: USDC_BY_CHAIN[chainId], amount: prices.usdc as string }
+ return { token: claimTypeToToken(ClaimType.Investor, chainId) as Token, amount: prices.usdc as string }
case ClaimType.UserOption:
- return { token: GpEther.onChain(chainId), amount: prices.native as string }
+ return { token: claimTypeToToken(ClaimType.UserOption, chainId) as GpEther, amount: prices.native as string }
default:
return undefined
}
diff --git a/src/custom/state/swap/extension.ts b/src/custom/state/swap/extension.ts
index a15d5a440..082644396 100644
--- a/src/custom/state/swap/extension.ts
+++ b/src/custom/state/swap/extension.ts
@@ -15,6 +15,12 @@ interface TradeParams {
export const stringToCurrency = (amount: string, currency: Currency) =>
CurrencyAmount.fromRawAmount(currency, JSBI.BigInt(amount))
+export const tryAtomsToCurrency = (atoms: string | undefined, currency: Currency | undefined) => {
+ if (!atoms || !currency) return undefined
+
+ return stringToCurrency(atoms, currency)
+}
+
/**
* useTradeExactInWithFee
* @description wraps useTradeExactIn and returns an extended trade object with the fee adjusted values
From 3a4bbac9204354f77a144195c8d10a7debfe47ab Mon Sep 17 00:00:00 2001
From: David W3stside
Date: Thu, 20 Jan 2022 11:59:39 +0000
Subject: [PATCH 3/3] tweak claim approve hook
---
src/custom/hooks/useApproveCallback/index.ts | 37 ++++++++++++++++----
1 file changed, 31 insertions(+), 6 deletions(-)
diff --git a/src/custom/hooks/useApproveCallback/index.ts b/src/custom/hooks/useApproveCallback/index.ts
index c8d6f6512..c9b6396d7 100644
--- a/src/custom/hooks/useApproveCallback/index.ts
+++ b/src/custom/hooks/useApproveCallback/index.ts
@@ -1,4 +1,4 @@
-import { Percent } from '@uniswap/sdk-core'
+import { CurrencyAmount, MaxUint256, Percent, Token } from '@uniswap/sdk-core'
import { useActiveWeb3React } from '@src/hooks/web3'
import { Field } from '@src/state/swap/actions'
import { computeSlippageAdjustedAmounts } from 'utils/prices'
@@ -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 { claimTypeToToken } from 'state/claim/hooks/utils'
+
type ApproveCallbackFromTradeParams = Pick<
ApproveCallbackParams,
'openTransactionConfirmationModal' | 'closeModals' | 'amountToCheckAgainstAllowance'
@@ -50,24 +55,44 @@ export type OptionalApproveCallbackParams = {
transactionSummary: string
}
-type ApproveCallbackFromClaimParams = Omit
+type ApproveCallbackFromClaimParams = Omit<
+ ApproveCallbackParams,
+ 'spender' | 'amountToApprove' | 'amountToCheckAgainstAllowance'
+> & {
+ claimType: ClaimType
+ investmentAmount: string | undefined
+}
export function useApproveCallbackFromClaim({
openTransactionConfirmationModal,
closeModals,
- amountToApprove,
- amountToCheckAgainstAllowance,
+ claimType,
+ 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 && (claimType === ClaimType.GnoOption || claimType === ClaimType.Investor)) {
+ const investmentCurrency = claimTypeToToken(claimType, supportedChain) as Token
+ const amountToCheckAgainstAllowance = tryAtomsToCurrency(investmentAmount, investmentCurrency)
+ return {
+ amountToApprove: CurrencyAmount.fromRawAmount(investmentCurrency, MaxUint256),
+ amountToCheckAgainstAllowance,
+ }
+ }
+ return undefined
+ }, [claimType, 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,
})
}