feat: add amount to local copy of Approval transactions (#6726)
* feat: add amount to local copy of Approval transactions * fix: use alternate * fix: type problem * feat: add test
This commit is contained in:
parent
094664dc7a
commit
8b16f454ca
@ -1,5 +1,6 @@
|
|||||||
import { Trans } from '@lingui/macro'
|
import { Trans } from '@lingui/macro'
|
||||||
import { Fraction, TradeType } from '@uniswap/sdk-core'
|
import { Fraction, TradeType } from '@uniswap/sdk-core'
|
||||||
|
import { BigNumber } from 'ethers/lib/ethers'
|
||||||
import JSBI from 'jsbi'
|
import JSBI from 'jsbi'
|
||||||
|
|
||||||
import { nativeOnChain } from '../../constants/tokens'
|
import { nativeOnChain } from '../../constants/tokens'
|
||||||
@ -87,7 +88,11 @@ function SubmitProposalTransactionSummary() {
|
|||||||
function ApprovalSummary({ info }: { info: ApproveTransactionInfo }) {
|
function ApprovalSummary({ info }: { info: ApproveTransactionInfo }) {
|
||||||
const token = useToken(info.tokenAddress)
|
const token = useToken(info.tokenAddress)
|
||||||
|
|
||||||
return <Trans>Approve {token?.symbol}</Trans>
|
return BigNumber.from(info.amount)?.eq(0) ? (
|
||||||
|
<Trans>Revoke {token?.symbol}</Trans>
|
||||||
|
) : (
|
||||||
|
<Trans>Approve {token?.symbol}</Trans>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function VoteSummary({ info }: { info: VoteTransactionInfo }) {
|
function VoteSummary({ info }: { info: VoteTransactionInfo }) {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { SupportedChainId, Token, TradeType as MockTradeType } from '@uniswap/sdk-core'
|
import { SupportedChainId, Token, TradeType as MockTradeType } from '@uniswap/sdk-core'
|
||||||
import { PERMIT2_ADDRESS } from '@uniswap/universal-router-sdk'
|
import { PERMIT2_ADDRESS } from '@uniswap/universal-router-sdk'
|
||||||
import { DAI as MockDAI, nativeOnChain, USDC_MAINNET as MockUSDC_MAINNET } from 'constants/tokens'
|
import { DAI as MockDAI, nativeOnChain, USDC_MAINNET as MockUSDC_MAINNET, USDT as MockUSDT } from 'constants/tokens'
|
||||||
import { TransactionStatus as MockTxStatus } from 'graphql/data/__generated__/types-and-hooks'
|
import { TransactionStatus as MockTxStatus } from 'graphql/data/__generated__/types-and-hooks'
|
||||||
import { ChainTokenMap } from 'hooks/Tokens'
|
import { ChainTokenMap } from 'hooks/Tokens'
|
||||||
import {
|
import {
|
||||||
@ -50,6 +50,7 @@ const mockChainId = SupportedChainId.MAINNET
|
|||||||
const mockSpenderAddress = PERMIT2_ADDRESS[mockChainId]
|
const mockSpenderAddress = PERMIT2_ADDRESS[mockChainId]
|
||||||
const mockCurrencyAmountRaw = '1000000000000000000'
|
const mockCurrencyAmountRaw = '1000000000000000000'
|
||||||
const mockCurrencyAmountRawUSDC = '1000000'
|
const mockCurrencyAmountRawUSDC = '1000000'
|
||||||
|
const mockApprovalAmountRaw = '10000000'
|
||||||
|
|
||||||
function mockHash(id: string, status: MockTxStatus = MockTxStatus.Confirmed) {
|
function mockHash(id: string, status: MockTxStatus = MockTxStatus.Confirmed) {
|
||||||
return id + status
|
return id + status
|
||||||
@ -93,6 +94,7 @@ const mockTokenAddressMap: ChainTokenMap = {
|
|||||||
[mockChainId]: {
|
[mockChainId]: {
|
||||||
[MockDAI.address]: MockDAI,
|
[MockDAI.address]: MockDAI,
|
||||||
[MockUSDC_MAINNET.address]: MockUSDC_MAINNET,
|
[MockUSDC_MAINNET.address]: MockUSDC_MAINNET,
|
||||||
|
[MockUSDT.address]: MockUSDT,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,9 +144,19 @@ jest.mock('../../../../state/transactions/hooks', () => {
|
|||||||
type: MockTxType.APPROVAL,
|
type: MockTxType.APPROVAL,
|
||||||
tokenAddress: MockDAI.address,
|
tokenAddress: MockDAI.address,
|
||||||
spender: mockSpenderAddress,
|
spender: mockSpenderAddress,
|
||||||
|
amount: mockApprovalAmountRaw,
|
||||||
},
|
},
|
||||||
'0xapproval'
|
'0xapproval'
|
||||||
),
|
),
|
||||||
|
...mockMultiStatus(
|
||||||
|
{
|
||||||
|
type: MockTxType.APPROVAL,
|
||||||
|
tokenAddress: MockUSDT.address,
|
||||||
|
spender: mockSpenderAddress,
|
||||||
|
amount: '0',
|
||||||
|
},
|
||||||
|
'0xrevoke_approval'
|
||||||
|
),
|
||||||
...mockMultiStatus(
|
...mockMultiStatus(
|
||||||
{
|
{
|
||||||
type: MockTxType.WRAP,
|
type: MockTxType.WRAP,
|
||||||
@ -315,7 +327,7 @@ describe('parseLocalActivity', () => {
|
|||||||
const account2Activites = renderHook(() => useLocalActivities(mockAccount2)).result.current
|
const account2Activites = renderHook(() => useLocalActivities(mockAccount2)).result.current
|
||||||
|
|
||||||
expect(Object.values(account1Activites)).toHaveLength(1)
|
expect(Object.values(account1Activites)).toHaveLength(1)
|
||||||
expect(Object.values(account2Activites)).toHaveLength(30)
|
expect(Object.values(account2Activites)).toHaveLength(33)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Properly uses correct tense of activity title based on tx status', () => {
|
it('Properly uses correct tense of activity title based on tx status', () => {
|
||||||
@ -380,6 +392,23 @@ describe('parseLocalActivity', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('Adapts Revoke Approval to Activity type', () => {
|
||||||
|
const hash = mockHash('0xrevoke_approval')
|
||||||
|
const activity = renderHook(() => useLocalActivities(mockAccount2)).result.current[hash]
|
||||||
|
expect(activity).toMatchObject({
|
||||||
|
chainId: mockChainId,
|
||||||
|
currencies: [MockUSDT],
|
||||||
|
title: 'Revoked approval',
|
||||||
|
descriptor: MockUSDT.symbol,
|
||||||
|
hash,
|
||||||
|
status: MockTxStatus.Confirmed,
|
||||||
|
receipt: {
|
||||||
|
id: hash,
|
||||||
|
status: MockTxStatus.Confirmed,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
it('Adapts Wrap to Activity type', () => {
|
it('Adapts Wrap to Activity type', () => {
|
||||||
const hash = mockHash('0xwrap')
|
const hash = mockHash('0xwrap')
|
||||||
const activity = renderHook(() => useLocalActivities(mockAccount2)).result.current[hash]
|
const activity = renderHook(() => useLocalActivities(mockAccount2)).result.current[hash]
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { BigNumber } from '@ethersproject/bignumber'
|
||||||
import { t } from '@lingui/macro'
|
import { t } from '@lingui/macro'
|
||||||
import { formatCurrencyAmount } from '@uniswap/conedison/format'
|
import { formatCurrencyAmount } from '@uniswap/conedison/format'
|
||||||
import { Currency, CurrencyAmount, TradeType } from '@uniswap/sdk-core'
|
import { Currency, CurrencyAmount, TradeType } from '@uniswap/sdk-core'
|
||||||
@ -76,12 +77,17 @@ function parseWrap(wrap: WrapTransactionInfo, chainId: SupportedChainId, status:
|
|||||||
function parseApproval(
|
function parseApproval(
|
||||||
approval: ApproveTransactionInfo,
|
approval: ApproveTransactionInfo,
|
||||||
chainId: SupportedChainId,
|
chainId: SupportedChainId,
|
||||||
tokens: ChainTokenMap
|
tokens: ChainTokenMap,
|
||||||
|
status: TransactionStatus
|
||||||
): Partial<Activity> {
|
): Partial<Activity> {
|
||||||
// TODO: Add 'amount' approved to ApproveTransactionInfo so we can distinguish between revoke and approve
|
|
||||||
const currency = getCurrency(approval.tokenAddress, chainId, tokens)
|
const currency = getCurrency(approval.tokenAddress, chainId, tokens)
|
||||||
const descriptor = currency?.symbol ?? currency?.name ?? t`Unknown`
|
const descriptor = currency?.symbol ?? currency?.name ?? t`Unknown`
|
||||||
return {
|
return {
|
||||||
|
title: getActivityTitle(
|
||||||
|
TransactionType.APPROVAL,
|
||||||
|
status,
|
||||||
|
BigNumber.from(approval.amount).eq(0) /* use alternate if it's a revoke */
|
||||||
|
),
|
||||||
descriptor,
|
descriptor,
|
||||||
currencies: [currency],
|
currencies: [currency],
|
||||||
}
|
}
|
||||||
@ -165,7 +171,7 @@ export function parseLocalActivity(
|
|||||||
if (info.type === TransactionType.SWAP) {
|
if (info.type === TransactionType.SWAP) {
|
||||||
additionalFields = parseSwap(info, chainId, tokens)
|
additionalFields = parseSwap(info, chainId, tokens)
|
||||||
} else if (info.type === TransactionType.APPROVAL) {
|
} else if (info.type === TransactionType.APPROVAL) {
|
||||||
additionalFields = parseApproval(info, chainId, tokens)
|
additionalFields = parseApproval(info, chainId, tokens, status)
|
||||||
} else if (info.type === TransactionType.WRAP) {
|
} else if (info.type === TransactionType.WRAP) {
|
||||||
additionalFields = parseWrap(info, chainId, status)
|
additionalFields = parseWrap(info, chainId, status)
|
||||||
} else if (
|
} else if (
|
||||||
|
@ -144,6 +144,11 @@ const AlternateTransactionTitleTable: { [key in TransactionType]?: { [state in T
|
|||||||
[TransactionStatus.Confirmed]: t`Unwrapped`,
|
[TransactionStatus.Confirmed]: t`Unwrapped`,
|
||||||
[TransactionStatus.Failed]: t`Unwrap failed`,
|
[TransactionStatus.Failed]: t`Unwrap failed`,
|
||||||
},
|
},
|
||||||
|
[TransactionType.APPROVAL]: {
|
||||||
|
[TransactionStatus.Pending]: t`Revoking approval`,
|
||||||
|
[TransactionStatus.Confirmed]: t`Revoked approval`,
|
||||||
|
[TransactionStatus.Failed]: t`Revoke approval failed`,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getActivityTitle(type: TransactionType, status: TransactionStatus, alternate?: boolean) {
|
export function getActivityTitle(type: TransactionType, status: TransactionStatus, alternate?: boolean) {
|
||||||
|
@ -11,8 +11,13 @@ function useGetAndTrackApproval(getApproval: ReturnType<typeof useApproval>[1])
|
|||||||
return useCallback(() => {
|
return useCallback(() => {
|
||||||
return getApproval().then((pending) => {
|
return getApproval().then((pending) => {
|
||||||
if (pending) {
|
if (pending) {
|
||||||
const { response, tokenAddress, spenderAddress: spender } = pending
|
const { response, tokenAddress, spenderAddress: spender, amount } = pending
|
||||||
addTransaction(response, { type: TransactionType.APPROVAL, tokenAddress, spender })
|
addTransaction(response, {
|
||||||
|
type: TransactionType.APPROVAL,
|
||||||
|
tokenAddress,
|
||||||
|
spender,
|
||||||
|
amount: amount.quotient.toString(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}, [addTransaction, getApproval])
|
}, [addTransaction, getApproval])
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import { BigNumberish } from '@ethersproject/bignumber'
|
|
||||||
import { ContractTransaction } from '@ethersproject/contracts'
|
import { ContractTransaction } from '@ethersproject/contracts'
|
||||||
import { CurrencyAmount, MaxUint256, Token } from '@uniswap/sdk-core'
|
import { CurrencyAmount, MaxUint256, Token } from '@uniswap/sdk-core'
|
||||||
import { useTokenContract } from 'hooks/useContract'
|
import { useTokenContract } from 'hooks/useContract'
|
||||||
@ -49,7 +48,7 @@ export function useUpdateTokenAllowance(
|
|||||||
if (!contract) throw new Error('missing contract')
|
if (!contract) throw new Error('missing contract')
|
||||||
if (!spender) throw new Error('missing spender')
|
if (!spender) throw new Error('missing spender')
|
||||||
|
|
||||||
const allowance: BigNumberish = MaxUint256.toString()
|
const allowance = MaxUint256.toString()
|
||||||
const response = await contract.approve(spender, allowance)
|
const response = await contract.approve(spender, allowance)
|
||||||
return {
|
return {
|
||||||
response,
|
response,
|
||||||
@ -57,6 +56,7 @@ export function useUpdateTokenAllowance(
|
|||||||
type: TransactionType.APPROVAL,
|
type: TransactionType.APPROVAL,
|
||||||
tokenAddress: contract.address,
|
tokenAddress: contract.address,
|
||||||
spender,
|
spender,
|
||||||
|
amount: allowance,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
} catch (e: unknown) {
|
} catch (e: unknown) {
|
||||||
|
@ -49,7 +49,10 @@ export function useApproval(
|
|||||||
useIsPendingApproval: (token?: Token, spender?: string) => boolean
|
useIsPendingApproval: (token?: Token, spender?: string) => boolean
|
||||||
): [
|
): [
|
||||||
ApprovalState,
|
ApprovalState,
|
||||||
() => Promise<{ response: TransactionResponse; tokenAddress: string; spenderAddress: string } | undefined>
|
() => Promise<
|
||||||
|
| { response: TransactionResponse; tokenAddress: string; spenderAddress: string; amount: CurrencyAmount<Currency> }
|
||||||
|
| undefined
|
||||||
|
>
|
||||||
] {
|
] {
|
||||||
const { chainId } = useWeb3React()
|
const { chainId } = useWeb3React()
|
||||||
const token = amountToApprove?.currency?.isToken ? amountToApprove.currency : undefined
|
const token = amountToApprove?.currency?.isToken ? amountToApprove.currency : undefined
|
||||||
@ -102,6 +105,7 @@ export function useApproval(
|
|||||||
response,
|
response,
|
||||||
tokenAddress: token.address,
|
tokenAddress: token.address,
|
||||||
spenderAddress: spender,
|
spenderAddress: spender,
|
||||||
|
amount: amountToApprove,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((error: Error) => {
|
.catch((error: Error) => {
|
||||||
|
@ -58,6 +58,7 @@ describe('transaction reducer', () => {
|
|||||||
type: TransactionType.APPROVAL,
|
type: TransactionType.APPROVAL,
|
||||||
tokenAddress: 'abc',
|
tokenAddress: 'abc',
|
||||||
spender: 'def',
|
spender: 'def',
|
||||||
|
amount: '10000',
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
@ -73,6 +74,7 @@ describe('transaction reducer', () => {
|
|||||||
type: TransactionType.APPROVAL,
|
type: TransactionType.APPROVAL,
|
||||||
tokenAddress: 'abc',
|
tokenAddress: 'abc',
|
||||||
spender: 'def',
|
spender: 'def',
|
||||||
|
amount: '10000',
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -103,7 +105,7 @@ describe('transaction reducer', () => {
|
|||||||
hash: '0x0',
|
hash: '0x0',
|
||||||
chainId: SupportedChainId.MAINNET,
|
chainId: SupportedChainId.MAINNET,
|
||||||
nonce: 2,
|
nonce: 2,
|
||||||
info: { type: TransactionType.APPROVAL, spender: '0x0', tokenAddress: '0x0' },
|
info: { type: TransactionType.APPROVAL, spender: '0x0', tokenAddress: '0x0', amount: '10000' },
|
||||||
from: '0x0',
|
from: '0x0',
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
@ -156,7 +158,7 @@ describe('transaction reducer', () => {
|
|||||||
hash: '0x0',
|
hash: '0x0',
|
||||||
chainId: SupportedChainId.MAINNET,
|
chainId: SupportedChainId.MAINNET,
|
||||||
nonce: 3,
|
nonce: 3,
|
||||||
info: { type: TransactionType.APPROVAL, spender: '0x0', tokenAddress: '0x0' },
|
info: { type: TransactionType.APPROVAL, spender: '0x0', tokenAddress: '0x0', amount: '10000' },
|
||||||
from: '0x0',
|
from: '0x0',
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
@ -176,7 +178,7 @@ describe('transaction reducer', () => {
|
|||||||
hash: '0x0',
|
hash: '0x0',
|
||||||
chainId: SupportedChainId.MAINNET,
|
chainId: SupportedChainId.MAINNET,
|
||||||
nonce: 4,
|
nonce: 4,
|
||||||
info: { type: TransactionType.APPROVAL, spender: '0x0', tokenAddress: '0x0' },
|
info: { type: TransactionType.APPROVAL, spender: '0x0', tokenAddress: '0x0', amount: '10000' },
|
||||||
from: '0x0',
|
from: '0x0',
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
@ -206,7 +208,7 @@ describe('transaction reducer', () => {
|
|||||||
chainId: SupportedChainId.MAINNET,
|
chainId: SupportedChainId.MAINNET,
|
||||||
hash: '0x0',
|
hash: '0x0',
|
||||||
nonce: 5,
|
nonce: 5,
|
||||||
info: { type: TransactionType.APPROVAL, spender: 'abc', tokenAddress: 'def' },
|
info: { type: TransactionType.APPROVAL, spender: 'abc', tokenAddress: 'def', amount: '10000' },
|
||||||
from: 'abc',
|
from: 'abc',
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
@ -215,7 +217,7 @@ describe('transaction reducer', () => {
|
|||||||
chainId: SupportedChainId.OPTIMISM,
|
chainId: SupportedChainId.OPTIMISM,
|
||||||
nonce: 6,
|
nonce: 6,
|
||||||
hash: '0x1',
|
hash: '0x1',
|
||||||
info: { type: TransactionType.APPROVAL, spender: 'abc', tokenAddress: 'def' },
|
info: { type: TransactionType.APPROVAL, spender: 'abc', tokenAddress: 'def', amount: '10000' },
|
||||||
from: 'abc',
|
from: 'abc',
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
@ -79,6 +79,7 @@ export interface ApproveTransactionInfo extends BaseTransactionInfo {
|
|||||||
type: TransactionType.APPROVAL
|
type: TransactionType.APPROVAL
|
||||||
tokenAddress: string
|
tokenAddress: string
|
||||||
spender: string
|
spender: string
|
||||||
|
amount: string
|
||||||
}
|
}
|
||||||
|
|
||||||
interface BaseSwapTransactionInfo extends BaseTransactionInfo {
|
interface BaseSwapTransactionInfo extends BaseTransactionInfo {
|
||||||
|
Loading…
Reference in New Issue
Block a user