Skip to content

Commit

Permalink
feat(multichain): Use new dynamic config for multichain features (#4265)
Browse files Browse the repository at this point in the history
### Description

For ACT-931. Replaces three of our existing feature gates with a single
Statsig Dynamic Config (available
[here](https://console.statsig.com/4plizaPmWwPL21ASV4QAO0/dynamic_configs/multi_chain_features)).

The `show_native_tokens` feature gate is a straggler here in terms of
multichain config. This was added as part of a quick and dirty hack to
get non-Celo transfers showing up in the home feed a while back, and
ought to be removed. I'll remove this in a followup PR.

### Test plan

Manual and unit tested.

### Related issues

- Fixes ACT-931

### Backwards compatibility

Yes.
  • Loading branch information
jophish authored Oct 9, 2023
1 parent d17825b commit e2dcd67
Show file tree
Hide file tree
Showing 14 changed files with 69 additions and 38 deletions.
5 changes: 4 additions & 1 deletion src/components/TokenBalance.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
import { LocalCurrencyCode } from 'src/localCurrency/consts'
import { navigate } from 'src/navigator/NavigationService'
import { Screens } from 'src/navigator/Screens'
import { getFeatureGate } from 'src/statsig'
import { getDynamicConfigParams, getFeatureGate } from 'src/statsig'
import * as tokenUtils from 'src/tokens/utils'
import { NetworkId } from 'src/transactions/types'
import { ONE_DAY_IN_MILLIS } from 'src/utils/time'
Expand Down Expand Up @@ -49,6 +49,9 @@ const defaultStore = {
}

jest.mocked(getFeatureGate).mockReturnValue(true)
jest.mocked(getDynamicConfigParams).mockReturnValue({
showBalances: [NetworkId['celo-alfajores']],
})

describe('FiatExchangeTokenBalance and HomeTokenBalance', () => {
const showAssetDetailsScreenSpy = jest.spyOn(tokenUtils, 'showAssetDetailsScreen')
Expand Down
14 changes: 10 additions & 4 deletions src/fiatExchanges/FiatExchangeCurrency.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,17 @@ import FiatExchangeCurrency from 'src/fiatExchanges/FiatExchangeCurrency'
import { fetchFiatConnectProviders } from 'src/fiatconnect/slice'
import { navigate } from 'src/navigator/NavigationService'
import { Screens } from 'src/navigator/Screens'
import { getFeatureGate } from 'src/statsig'
import { Network } from 'src/transactions/types'
import { Network, NetworkId } from 'src/transactions/types'
import { createMockStore, getMockStackScreenProps } from 'test/utils'
import { FiatExchangeFlow } from './utils'
import { getDynamicConfigParams } from 'src/statsig'

jest.mock('src/statsig', () => ({
getFeatureGate: jest.fn(() => false),
getDynamicConfigParams: jest.fn(() => {
return {
showCico: ['celo-alfajores'],
}
}),
}))

const mockScreenProps = (flow: FiatExchangeFlow) =>
Expand Down Expand Up @@ -79,7 +83,9 @@ describe('FiatExchangeCurrency', () => {
})
})
it('ETH Flow', () => {
jest.mocked(getFeatureGate).mockReturnValueOnce(true)
jest.mocked(getDynamicConfigParams).mockReturnValueOnce({
showCico: [NetworkId['celo-alfajores'], NetworkId['ethereum-sepolia']],
})
const store = createMockStore({})
const tree = render(
<Provider store={store}>
Expand Down
12 changes: 9 additions & 3 deletions src/fiatExchanges/FiatExchangeCurrency.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,14 @@ import fontStyles from 'src/styles/fonts'
import variables from 'src/styles/variables'
import { CiCoCurrency, currencyForAnalytics, resolveCurrency } from 'src/utils/currencies'
import { CICOFlow, FiatExchangeFlow } from './utils'
import { getFeatureGate } from 'src/statsig'
import { StatsigFeatureGates } from 'src/statsig/types'
import { getDynamicConfigParams } from 'src/statsig'
import { StatsigDynamicConfigs } from 'src/statsig/types'
import { DynamicConfigs } from 'src/statsig/constants'
import { CiCoCurrencyNetworkMap } from 'src/fiatExchanges/types'
import { fetchFiatConnectProviders } from 'src/fiatconnect/slice'
import { useDispatch } from 'react-redux'
import networkConfig from 'src/web3/networkConfig'
import { Network } from 'src/transactions/types'

type Props = NativeStackScreenProps<StackParamList, Screens.FiatExchangeCurrency>

Expand Down Expand Up @@ -104,7 +107,10 @@ function FiatExchangeCurrency({ route, navigation }: Props) {
const { flow } = route.params

const [selectedCurrency, setSelectedCurrency] = useState<CiCoCurrency>(CiCoCurrency.cUSD)
const showEth = getFeatureGate(StatsigFeatureGates.SHOW_ETH_IN_CICO)
// TODO: Update this to actually respect all possible networkIds correctly
const showEth = getDynamicConfigParams(
DynamicConfigs[StatsigDynamicConfigs.MULTI_CHAIN_FEATURES]
).showCico.includes(networkConfig.networkToNetworkId[Network.Ethereum])

// Fetch FiatConnect providers silently in the background early in the CICO funnel
useEffect(() => {
Expand Down
4 changes: 4 additions & 0 deletions src/home/WalletHome.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,10 @@ jest.mock('src/statsig', () => ({
cashInBottomSheetEnabled: true,
})),
getFeatureGate: jest.fn().mockReturnValue(false),
getDynamicConfigParams: jest.fn(() => ({
showBalances: ['celo-alfajores'],
showTransfers: ['celo-alfajores'],
})),
}))

jest.mock('src/fiatExchanges/utils', () => ({
Expand Down
3 changes: 3 additions & 0 deletions src/navigator/DrawerNavigator.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ import { createMockStore } from 'test/utils'
jest.mock('src/statsig', () => ({
getExperimentParams: jest.fn(),
getFeatureGate: jest.fn().mockReturnValue(false),
getDynamicConfigParams: jest.fn(() => ({
showBalances: ['celo-alfajores'],
})),
}))

// TODO avoid rendering WalletHome as we're mostly interested in testing the menu here
Expand Down
12 changes: 9 additions & 3 deletions src/statsig/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
StatsigFeatureGates,
StatsigLayers,
} from 'src/statsig/types'
import networkConfig from 'src/web3/networkConfig'

export const LayerParams = {
// TODO(ACT-659): refactor to imitate defaultExperimentParamValues (more type safe, less boilerplate)
Expand Down Expand Up @@ -33,10 +34,7 @@ export const FeatureGates = {
[StatsigFeatureGates.SHOW_NOTIFICATION_CENTER]: false,
[StatsigFeatureGates.SHOW_CLOUD_ACCOUNT_BACKUP_SETUP]: false,
[StatsigFeatureGates.SHOW_CLOUD_ACCOUNT_BACKUP_RESTORE]: false,
[StatsigFeatureGates.SHOW_MULTI_CHAIN_TRANSFERS]: false,
[StatsigFeatureGates.SHOW_NATIVE_TOKENS]: false,
[StatsigFeatureGates.SHOW_ETH_IN_CICO]: false,
[StatsigFeatureGates.FETCH_MULTI_CHAIN_BALANCES]: false,
[StatsigFeatureGates.USE_VIEM_FOR_SEND]: false,
}

Expand Down Expand Up @@ -91,4 +89,12 @@ export const DynamicConfigs = {
cico: 30,
},
},
[StatsigDynamicConfigs.MULTI_CHAIN_FEATURES]: {
configName: StatsigDynamicConfigs.MULTI_CHAIN_FEATURES,
defaultValues: {
showCico: [networkConfig.defaultNetworkId],
showBalances: [networkConfig.defaultNetworkId],
showTransfers: [networkConfig.defaultNetworkId],
},
},
}
4 changes: 1 addition & 3 deletions src/statsig/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export enum StatsigLayers {
export enum StatsigDynamicConfigs {
USERNAME_BLOCK_LIST = 'username_block_list',
WALLET_NETWORK_TIMEOUT_SECONDS = 'wallet_network_timeout_seconds',
MULTI_CHAIN_FEATURES = 'multi_chain_features',
}

export enum StatsigFeatureGates {
Expand All @@ -29,10 +30,7 @@ export enum StatsigFeatureGates {
SHOW_NOTIFICATION_CENTER = 'show_notification_center',
SHOW_CLOUD_ACCOUNT_BACKUP_SETUP = 'show_cloud_account_backup_setup',
SHOW_CLOUD_ACCOUNT_BACKUP_RESTORE = 'show_cloud_account_backup_restore',
SHOW_MULTI_CHAIN_TRANSFERS = 'show_multi_chain_transfers',
SHOW_NATIVE_TOKENS = 'show_native_tokens',
SHOW_ETH_IN_CICO = 'show_eth_in_cico',
FETCH_MULTI_CHAIN_BALANCES = 'fetch_multi_chain_balances',
USE_VIEM_FOR_SEND = 'use_viem_for_send',
}

Expand Down
6 changes: 3 additions & 3 deletions src/tokens/Assets.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ import {
jest.mock('src/statsig', () => {
return {
getFeatureGate: jest.fn(),
getDynamicConfigParams: jest.fn().mockReturnValue({
show_native_tokens: false,
}),
getDynamicConfigParams: jest.fn(() => ({
showBalances: ['celo-alfajores'],
})),
}
})

Expand Down
2 changes: 1 addition & 1 deletion src/tokens/TokenBalances.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jest.mock('src/statsig', () => {
return {
getFeatureGate: jest.fn(),
getDynamicConfigParams: jest.fn().mockReturnValue({
show_native_tokens: false,
showBalances: ['celo-alfajores'],
}),
}
})
Expand Down
10 changes: 7 additions & 3 deletions src/tokens/saga.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import {
import { FetchMock } from 'jest-fetch-mock'
import Logger from 'src/utils/Logger'
import { apolloClient } from 'src/apollo'
import { getFeatureGate } from 'src/statsig'
import { getDynamicConfigParams } from 'src/statsig'
import { ApolloQueryResult } from 'apollo-client'
import { NetworkId } from 'src/transactions/types'

Expand Down Expand Up @@ -168,7 +168,9 @@ describe(fetchTokenBalancesSaga, () => {

describe(fetchTokenBalancesForAddress, () => {
it('returns token balances for a single chain', async () => {
jest.mocked(getFeatureGate).mockReturnValueOnce(false)
jest.mocked(getDynamicConfigParams).mockReturnValueOnce({
showBalances: [NetworkId['celo-alfajores']],
})
jest
.mocked(apolloClient.query)
.mockImplementation(async (payload: any): Promise<ApolloQueryResult<unknown>> => {
Expand All @@ -185,7 +187,9 @@ describe(fetchTokenBalancesForAddress, () => {
expect(result).toEqual(expect.arrayContaining(['celo_alfajores balance']))
})
it('returns token balances for multiple chains', async () => {
jest.mocked(getFeatureGate).mockReturnValueOnce(true)
jest.mocked(getDynamicConfigParams).mockReturnValueOnce({
showBalances: [NetworkId['celo-alfajores'], NetworkId['ethereum-sepolia']],
})
jest
.mocked(apolloClient.query)
.mockImplementation(async (payload: any): Promise<ApolloQueryResult<unknown>> => {
Expand Down
7 changes: 2 additions & 5 deletions src/tokens/saga.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ import { SentryTransactionHub } from 'src/sentry/SentryTransactionHub'
import { SentryTransaction } from 'src/sentry/SentryTransactions'
import { Actions } from 'src/stableToken/actions'
import { lastKnownTokenBalancesSelector, tokensListWithAddressSelector } from 'src/tokens/selectors'
import { getFeatureGate } from 'src/statsig'
import { StatsigFeatureGates } from 'src/statsig/types'
import {
StoredTokenBalance,
StoredTokenBalances,
Expand All @@ -42,6 +40,7 @@ import networkConfig from 'src/web3/networkConfig'
import { getConnectedUnlockedAccount } from 'src/web3/saga'
import { walletAddressSelector } from 'src/web3/selectors'
import { call, put, select, spawn, take, takeEvery } from 'typed-redux-saga'
import { getSupportedNetworkIdsForTokenBalances } from 'src/tokens/utils'

import * as utf8 from 'utf8'

Expand Down Expand Up @@ -237,9 +236,7 @@ interface UserBalancesResponse {
export async function fetchTokenBalancesForAddress(
address: string
): Promise<FetchedTokenBalance[]> {
const chainsToFetch = getFeatureGate(StatsigFeatureGates.FETCH_MULTI_CHAIN_BALANCES)
? Object.values(networkConfig.networkToNetworkId)
: [networkConfig.defaultNetworkId]
const chainsToFetch = getSupportedNetworkIdsForTokenBalances()
const userBalances = await Promise.all(
chainsToFetch.map((networkId) => {
return apolloClient.query<UserBalancesResponse, { address: string; networkId: string }>({
Expand Down
13 changes: 6 additions & 7 deletions src/tokens/utils.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import BigNumber from 'bignumber.js'
import { getFeatureGate } from 'src/statsig'
import { StatsigFeatureGates } from 'src/statsig/types'
import { CurrencyTokens } from 'src/tokens/selectors'
import { NetworkId } from 'src/transactions/types'
import { Currency } from 'src/utils/currencies'
import networkConfig from 'src/web3/networkConfig'
import { TokenBalance } from './slice'
import { NetworkId } from 'src/transactions/types'
import { getDynamicConfigParams } from 'src/statsig'
import { StatsigDynamicConfigs } from 'src/statsig/types'
import { DynamicConfigs } from 'src/statsig/constants'

export function getHigherBalanceCurrency(
currencies: Currency[],
Expand Down Expand Up @@ -120,9 +120,8 @@ export function convertTokenToLocalAmount({
}

export function getSupportedNetworkIdsForTokenBalances(): NetworkId[] {
return getFeatureGate(StatsigFeatureGates.FETCH_MULTI_CHAIN_BALANCES)
? Object.values(networkConfig.networkToNetworkId)
: [networkConfig.defaultNetworkId]
return getDynamicConfigParams(DynamicConfigs[StatsigDynamicConfigs.MULTI_CHAIN_FEATURES])
.showBalances
}

export function showAssetDetailsScreen() {
Expand Down
5 changes: 5 additions & 0 deletions src/transactions/feed/TransactionFeed.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ import { mockCusdAddress } from 'test/values'

jest.mock('src/statsig', () => ({
getFeatureGate: jest.fn(() => false),
getDynamicConfigParams: jest.fn(() => ({
showCico: ['celo-alfajores'],
showBalances: ['celo-alfajores'],
showTransfers: ['celo-alfajores'],
})),
}))

const mockTransaction = (transactionHash: string): TokenTransaction => {
Expand Down
10 changes: 5 additions & 5 deletions src/transactions/feed/queryHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ import { TokenTransaction, NetworkId } from 'src/transactions/types'
import Logger from 'src/utils/Logger'
import config from 'src/web3/networkConfig'
import { walletAddressSelector } from 'src/web3/selectors'
import { getFeatureGate } from 'src/statsig/index'
import { StatsigFeatureGates } from 'src/statsig/types'
import { getDynamicConfigParams } from 'src/statsig/index'
import { StatsigDynamicConfigs } from 'src/statsig/types'
import { DynamicConfigs } from 'src/statsig/constants'

const MIN_NUM_TRANSACTIONS = 10

Expand Down Expand Up @@ -63,9 +64,8 @@ const deduplicateTransactions = (
}

export function getAllowedNetworkIds(): Array<NetworkId> {
return getFeatureGate(StatsigFeatureGates.SHOW_MULTI_CHAIN_TRANSFERS)
? Object.values(config.networkToNetworkId)
: [config.defaultNetworkId]
return getDynamicConfigParams(DynamicConfigs[StatsigDynamicConfigs.MULTI_CHAIN_FEATURES])
.showTransfers
}

export function useFetchTransactions(): QueryHookResult {
Expand Down

0 comments on commit e2dcd67

Please sign in to comment.