Skip to content

Commit

Permalink
feat(transfers): Remove old feature flag, support tokenId in transfer…
Browse files Browse the repository at this point in the history
… feed and CICO (#4275)

### Description

This PR cleans up an old hacky feature flag we had laying around, and in
the process adds support for native tokens to appear _correctly_ in the
transfer feed. This also has the effect of refactoring some of our CICO
code to support tokenIds as well, in order to use the new `TokenDisplay`
component in the case of `ETH` being selected.

### Test plan

Unit and manual tested. See video below for ETH information showing up
where it previously was not (namely: transfer feed items, transfer feed
details page, CICO header balance). The second video shows the existing
behavior, where ETH is kinda broken all over the place.



https://github.com/valora-inc/wallet/assets/569401/c7931d12-87a2-42a6-80de-516a18a343b8



https://github.com/valora-inc/wallet/assets/569401/b2bbb8e3-cee1-467b-85da-d7ce3ab0690c



### Related issues

N/A

### Backwards compatibility

Yes.
  • Loading branch information
jophish authored Oct 11, 2023
1 parent 74c9546 commit 91f9fc7
Show file tree
Hide file tree
Showing 52 changed files with 428 additions and 147 deletions.
11 changes: 0 additions & 11 deletions src/components/LegacyTokenDisplay.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { LocalCurrencyCode } from 'src/localCurrency/consts'
import { RootState } from 'src/redux/reducers'
import { Currency } from 'src/utils/currencies'
import { createMockStore, getElementText, RecursivePartial } from 'test/utils'
import { getFeatureGate } from 'src/statsig'
import { NetworkId } from 'src/transactions/types'
import {
mockCusdTokenId,
Expand Down Expand Up @@ -91,16 +90,6 @@ describe('LegacyTokenDisplay', () => {
)
).toThrow()
})
it('allows currency and tokenAddress to be empty when native tokens are permitted', () => {
jest.mocked(getFeatureGate).mockReturnValueOnce(true)
expect(() =>
render(
<Provider store={store()}>
<LegacyTokenDisplay showLocalAmount={false} amount={10} testID="test" />
</Provider>
)
).not.toThrow()
})
it('shows token amount when showLocalAmount is false', () => {
const { getByTestId } = render(
<Provider store={store()}>
Expand Down
9 changes: 1 addition & 8 deletions src/components/LegacyTokenDisplay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import { StyleProp, TextStyle } from 'react-native'
import { useTokenInfoByAddress, useTokenInfoWithAddressBySymbol } from 'src/tokens/hooks'
import { LocalAmount } from 'src/transactions/types'
import { Currency } from 'src/utils/currencies'
import { getFeatureGate } from 'src/statsig'
import { StatsigFeatureGates } from 'src/statsig/types'
import TokenDisplay from 'src/components/TokenDisplay'

interface Props {
Expand Down Expand Up @@ -36,15 +34,10 @@ function LegacyTokenDisplay({
style,
testID,
}: Props) {
const showNativeTokens = getFeatureGate(StatsigFeatureGates.SHOW_NATIVE_TOKENS)
if (!showNativeTokens && (tokenAddress ? currency : !currency)) {
if (tokenAddress ? currency : !currency) {
throw new Error(
'LegacyTokenDisplay must be passed either "currency" or "tokenAddress" and not both'
)
} else if (tokenAddress && currency) {
throw new Error(
'LegacyTokenDisplay must be passed tokenAddress, currency, or nethier, but not both'
)
}

const tokenInfoFromAddress = useTokenInfoByAddress(tokenAddress)
Expand Down
90 changes: 90 additions & 0 deletions src/components/LegacyTokenTotalLineItem.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { render } from '@testing-library/react-native'
import BigNumber from 'bignumber.js'
import * as React from 'react'
import 'react-native'
import { Provider } from 'react-redux'
import LegacyTokenTotalLineItem from 'src/components/LegacyTokenTotalLineItem'
import { LocalCurrencyCode } from 'src/localCurrency/consts'
import { LocalAmount, NetworkId } from 'src/transactions/types'
import { createMockStore, getElementText } from 'test/utils'
import { mockCusdAddress, mockCusdTokenId } from 'test/values'

const mockBtcAddress = '0xbtc'
const mockBtcTokenId = `celo-alfajores:${mockBtcAddress}`

const defaultAmount = new BigNumber(10)
const defaultTokenAddress = mockCusdAddress

// This component is primarily tested via TokenTotalLineItem.test.tsx
describe('LegacyTokenTotalLineItem', () => {
function renderComponent({
amount = defaultAmount,
tokenAddress = defaultTokenAddress,
localAmount,
localCurrencyCode = LocalCurrencyCode.BRL,
usdToLocalRate = '1.5',
feeToAddInUsd = undefined,
hideSign = undefined,
}: {
amount?: BigNumber
tokenAddress?: string
localAmount?: LocalAmount
localCurrencyCode?: LocalCurrencyCode
usdToLocalRate?: string
feeToAddInUsd?: BigNumber
hideSign?: boolean
}) {
return render(
<Provider
store={createMockStore({
localCurrency: {
preferredCurrencyCode: LocalCurrencyCode.BRL,
fetchedCurrencyCode: LocalCurrencyCode.BRL,
usdToLocalRate,
},
tokens: {
tokenBalances: {
[mockCusdTokenId]: {
networkId: NetworkId['celo-alfajores'],
address: mockCusdAddress,
tokenId: mockCusdTokenId,
symbol: 'cUSD',
priceUsd: '1',
balance: '10',
priceFetchedAt: Date.now(),
},
[mockBtcTokenId]: {
networkId: NetworkId['celo-alfajores'],
address: mockBtcAddress,
tokenId: mockBtcTokenId,
symbol: 'WBTC',
priceUsd: '65000',
balance: '0.5',
priceFetchedAt: Date.now(),
},
},
},
})}
>
<LegacyTokenTotalLineItem
tokenAmount={amount}
tokenAddress={tokenAddress}
localAmount={localAmount}
feeToAddInUsd={feeToAddInUsd}
hideSign={hideSign}
/>
</Provider>
)
}

describe('When rendering normally', () => {
it('shows the right amounts', () => {
const { getByTestId } = renderComponent({})
expect(getElementText(getByTestId('TotalLineItem/Total'))).toEqual('R$15.00')
expect(getElementText(getByTestId('TotalLineItem/ExchangeRate'))).toEqual(
'tokenExchanteRate, {"symbol":"cUSD"}R$1.50'
)
expect(getElementText(getByTestId('TotalLineItem/Subtotal'))).toEqual('10.00 cUSD')
})
})
})
38 changes: 38 additions & 0 deletions src/components/LegacyTokenTotalLineItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import BigNumber from 'bignumber.js'
import * as React from 'react'
import { useTokenInfoByAddress } from 'src/tokens/hooks'
import TokenTotalLineItem from 'src/components/TokenTotalLineItem'
import { LocalAmount } from 'src/transactions/types'

interface Props {
tokenAmount: BigNumber
tokenAddress?: string
localAmount?: LocalAmount
feeToAddInUsd?: BigNumber | undefined
hideSign?: boolean
title?: string | null
}

/**
* @deprecated Use TokenTotalLineItem instead
*/
export default function LegacyTokenTotalLineItem({
tokenAmount,
tokenAddress,
localAmount,
feeToAddInUsd,
hideSign,
title,
}: Props) {
const tokenInfo = useTokenInfoByAddress(tokenAddress)
return (
<TokenTotalLineItem
tokenAmount={tokenAmount}
tokenId={tokenInfo?.tokenId}
localAmount={localAmount}
feeToAddInUsd={feeToAddInUsd}
hideSign={hideSign}
title={title}
/>
)
}
10 changes: 5 additions & 5 deletions src/components/TokenTotalLineItem.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,20 @@ const mockBtcAddress = '0xbtc'
const mockBtcTokenId = `celo-alfajores:${mockBtcAddress}`

const defaultAmount = new BigNumber(10)
const defaultTokenAddress = mockCusdAddress
const defaultTokenId = mockCusdTokenId

describe('TokenTotalLineItem', () => {
function renderComponent({
amount = defaultAmount,
tokenAddress = defaultTokenAddress,
tokenId = defaultTokenId,
localAmount,
localCurrencyCode = LocalCurrencyCode.BRL,
usdToLocalRate = '1.5',
feeToAddInUsd = undefined,
hideSign = undefined,
}: {
amount?: BigNumber
tokenAddress?: string
tokenId?: string
localAmount?: LocalAmount
localCurrencyCode?: LocalCurrencyCode
usdToLocalRate?: string
Expand Down Expand Up @@ -67,7 +67,7 @@ describe('TokenTotalLineItem', () => {
>
<TokenTotalLineItem
tokenAmount={amount}
tokenAddress={tokenAddress}
tokenId={tokenId}
localAmount={localAmount}
feeToAddInUsd={feeToAddInUsd}
hideSign={hideSign}
Expand Down Expand Up @@ -104,7 +104,7 @@ describe('TokenTotalLineItem', () => {
it('we show some significant values', () => {
const { getByTestId } = renderComponent({
amount: new BigNumber(0.000123456),
tokenAddress: mockBtcAddress,
tokenId: mockBtcTokenId,
usdToLocalRate: '1',
})
expect(getElementText(getByTestId('TotalLineItem/Total'))).toEqual('R$8.02')
Expand Down
24 changes: 10 additions & 14 deletions src/components/TokenTotalLineItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@ import * as React from 'react'
import { Trans, useTranslation } from 'react-i18next'
import { StyleSheet, Text } from 'react-native'
import LineItemRow from 'src/components/LineItemRow'
import LegacyTokenDisplay from 'src/components/LegacyTokenDisplay'
import TokenDisplay from 'src/components/TokenDisplay'
import { LocalCurrencyCode, LocalCurrencySymbol } from 'src/localCurrency/consts'
import colors from 'src/styles/colors'
import fontStyles from 'src/styles/fonts'
import { useTokenInfoByAddress } from 'src/tokens/hooks'
import { useTokenInfo } from 'src/tokens/hooks'
import { LocalAmount } from 'src/transactions/types'
import { formatValueToDisplay } from 'src/components/TokenDisplay'

interface Props {
tokenAmount: BigNumber
tokenAddress?: string
tokenId?: string
localAmount?: LocalAmount
feeToAddInUsd?: BigNumber | undefined
hideSign?: boolean
Expand All @@ -22,14 +22,14 @@ interface Props {

export default function TokenTotalLineItem({
tokenAmount,
tokenAddress,
tokenId,
localAmount,
feeToAddInUsd,
hideSign,
title,
}: Props) {
const { t } = useTranslation()
const tokenInfo = useTokenInfoByAddress(tokenAddress)
const tokenInfo = useTokenInfo(tokenId)
const feeInToken = tokenInfo?.priceUsd ? feeToAddInUsd?.dividedBy(tokenInfo.priceUsd) : undefined

return (
Expand All @@ -38,9 +38,9 @@ export default function TokenTotalLineItem({
title={title ?? t('total')}
textStyle={fontStyles.regular600}
amount={
<LegacyTokenDisplay
<TokenDisplay
amount={tokenAmount.plus(feeInToken ?? 0)}
tokenAddress={tokenAddress}
tokenId={tokenId}
localAmount={localAmount}
hideSign={hideSign}
testID="TotalLineItem/Total"
Expand All @@ -56,19 +56,15 @@ export default function TokenTotalLineItem({
LocalCurrencySymbol[localAmount.currencyCode as LocalCurrencyCode]
}${formatValueToDisplay(new BigNumber(localAmount.exchangeRate))}`
) : (
<LegacyTokenDisplay
amount={new BigNumber(1)}
tokenAddress={tokenAddress}
showLocalAmount={true}
/>
<TokenDisplay amount={new BigNumber(1)} tokenId={tokenId} showLocalAmount={true} />
)}
</Trans>
</Text>
}
amount={
<LegacyTokenDisplay
<TokenDisplay
amount={tokenAmount}
tokenAddress={tokenAddress}
tokenId={tokenId}
showLocalAmount={false}
hideSign={hideSign}
testID="TotalLineItem/Subtotal"
Expand Down
2 changes: 2 additions & 0 deletions src/consumerIncentives/saga.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import { getConnectedUnlockedAccount } from 'src/web3/saga'
import { walletAddressSelector } from 'src/web3/selectors'
import { buildTxo, getContract } from 'src/web3/utils'
import { all, call, put, select, spawn, take, takeEvery, takeLatest } from 'typed-redux-saga'
import { getTokenId } from 'src/tokens/utils'

const TAG = 'SuperchargeRewardsClaimer'
export const SUPERCHARGE_FETCH_TIMEOUT = 45_000
Expand Down Expand Up @@ -93,6 +94,7 @@ export function* claimRewardsSaga({ payload: rewards }: ReturnType<typeof claimR
status: TransactionStatus.Complete,
value: reward.amount,
tokenAddress: reward.tokenAddress,
tokenId: getTokenId(networkConfig.defaultNetworkId, reward.tokenAddress),
comment: '',
timestamp: Math.floor(Date.now() / 1000),
address: reward.fundsSource,
Expand Down
4 changes: 2 additions & 2 deletions src/escrow/ReclaimPaymentConfirmationCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { SecurityFeeIcon } from 'src/components/FeeIcon'
import HorizontalLine from 'src/components/HorizontalLine'
import LineItemRow from 'src/components/LineItemRow'
import LegacyTokenDisplay from 'src/components/LegacyTokenDisplay'
import TokenTotalLineItem from 'src/components/TokenTotalLineItem'
import LegacyTokenTotalLineItem from 'src/components/LegacyTokenTotalLineItem'
import { FeeType } from 'src/fees/reducer'
import { feeEstimatesSelector } from 'src/fees/selectors'
import { MobileRecipient } from 'src/recipients/recipient'
Expand Down Expand Up @@ -69,7 +69,7 @@ export default function ReclaimPaymentConfirmationCard({
hasError={!!feeEstimate?.error}
/>
<HorizontalLine />
<TokenTotalLineItem
<LegacyTokenTotalLineItem
title={t('totalRefunded')}
tokenAmount={totalAmount}
tokenAddress={tokenAddress}
Expand Down
2 changes: 1 addition & 1 deletion src/fees/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export function usePaidFees(fees: Fee[]) {
// Returns the maximum amount a user can send, taking into acount gas fees required for the transaction
// also optionally fetches new fee estimations if the current ones are missing or out of date
export function useMaxSendAmount(
tokenAddress: string | undefined,
tokenAddress: string | undefined | null,
feeType: FeeType.SEND | FeeType.SWAP,
shouldRefresh: boolean = true
) {
Expand Down
Loading

0 comments on commit 91f9fc7

Please sign in to comment.