fix: remove version check in redux lists update + migrate outdated USDC saved tokens (#7544)
* fix: remove version check lists update * add migration and test * pr review
This commit is contained in:
parent
9eaa22f644
commit
443a00a777
@ -12,7 +12,6 @@ import { useAllLists } from 'state/lists/hooks'
|
||||
import { useFetchListCallback } from '../../hooks/useFetchListCallback'
|
||||
import useIsWindowVisible from '../../hooks/useIsWindowVisible'
|
||||
import { acceptListUpdate } from './actions'
|
||||
import { shouldAcceptVersionUpdate } from './utils'
|
||||
|
||||
export default function Updater(): null {
|
||||
const { provider } = useWeb3React()
|
||||
@ -61,7 +60,7 @@ export default function Updater(): null {
|
||||
})
|
||||
}, [dispatch, fetchList, lists, rehydrated])
|
||||
|
||||
// automatically update lists if versions are minor/patch
|
||||
// automatically update lists for every version update
|
||||
useEffect(() => {
|
||||
Object.keys(lists).forEach((listUrl) => {
|
||||
const list = lists[listUrl]
|
||||
@ -71,13 +70,7 @@ export default function Updater(): null {
|
||||
case VersionUpgrade.NONE:
|
||||
throw new Error('unexpected no version bump')
|
||||
case VersionUpgrade.PATCH:
|
||||
case VersionUpgrade.MINOR: {
|
||||
if (shouldAcceptVersionUpdate(listUrl, list.current, list.pendingUpdate, bump)) {
|
||||
dispatch(acceptListUpdate(listUrl))
|
||||
}
|
||||
break
|
||||
}
|
||||
// update any active or inactive lists
|
||||
case VersionUpgrade.MINOR:
|
||||
case VersionUpgrade.MAJOR:
|
||||
dispatch(acceptListUpdate(listUrl))
|
||||
}
|
||||
|
@ -1,68 +0,0 @@
|
||||
import { TokenList, VersionUpgrade } from '@uniswap/token-lists'
|
||||
|
||||
import { shouldAcceptVersionUpdate } from './utils'
|
||||
|
||||
function buildTokenList(count: number): TokenList {
|
||||
const tokens = []
|
||||
for (let i = 0; i < count; i++) {
|
||||
tokens.push({
|
||||
name: `Token ${i}`,
|
||||
address: `0x${i.toString().padStart(40, '0')}`,
|
||||
symbol: `T${i}`,
|
||||
decimals: 18,
|
||||
chainId: 1,
|
||||
logoURI: `https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0x${i
|
||||
.toString()
|
||||
.padStart(40, '0')}/logo.png`,
|
||||
})
|
||||
}
|
||||
return {
|
||||
name: 'Defi',
|
||||
logoURI:
|
||||
'https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0x514910771AF9Ca656af840dff83E8264EcF986CA/logo.png',
|
||||
keywords: ['defi', 'uniswap'],
|
||||
timestamp: '2021-03-12T00:00:00.000Z',
|
||||
version: {
|
||||
major: 1,
|
||||
minor: 0,
|
||||
patch: 0,
|
||||
},
|
||||
tokens,
|
||||
}
|
||||
}
|
||||
|
||||
describe('shouldAcceptMinorVersionUpdate', () => {
|
||||
it('returns false for patch when tokens have changed', () => {
|
||||
jest.spyOn(console, 'debug').mockReturnValue(undefined)
|
||||
expect(shouldAcceptVersionUpdate('test_list', buildTokenList(1), buildTokenList(2), VersionUpgrade.PATCH)).toEqual(
|
||||
false
|
||||
)
|
||||
expect(console.debug).toHaveBeenCalledWith(expect.stringMatching(/should have been MAJOR/))
|
||||
})
|
||||
|
||||
it('returns true for patch when tokens are the same', () => {
|
||||
expect(shouldAcceptVersionUpdate('test_list', buildTokenList(1), buildTokenList(1), VersionUpgrade.PATCH)).toEqual(
|
||||
true
|
||||
)
|
||||
})
|
||||
|
||||
it('returns true for minor version bump with tokens added', () => {
|
||||
expect(shouldAcceptVersionUpdate('test_list', buildTokenList(1), buildTokenList(2), VersionUpgrade.MINOR)).toEqual(
|
||||
true
|
||||
)
|
||||
})
|
||||
|
||||
it('returns true for no version bump', () => {
|
||||
expect(shouldAcceptVersionUpdate('test_list', buildTokenList(1), buildTokenList(2), VersionUpgrade.MINOR)).toEqual(
|
||||
true
|
||||
)
|
||||
})
|
||||
|
||||
it('returns false for minor version bump with tokens removed', () => {
|
||||
jest.spyOn(console, 'debug').mockReturnValue(undefined)
|
||||
expect(shouldAcceptVersionUpdate('test_list', buildTokenList(2), buildTokenList(1), VersionUpgrade.MINOR)).toEqual(
|
||||
false
|
||||
)
|
||||
expect(console.debug).toHaveBeenCalledWith(expect.stringMatching(/should have been MAJOR/))
|
||||
})
|
||||
})
|
@ -1,19 +0,0 @@
|
||||
import { minVersionBump, TokenList, VersionUpgrade } from '@uniswap/token-lists'
|
||||
|
||||
export function shouldAcceptVersionUpdate(
|
||||
listUrl: string,
|
||||
current: TokenList,
|
||||
update: TokenList,
|
||||
targetBump: VersionUpgrade.PATCH | VersionUpgrade.MINOR
|
||||
): boolean {
|
||||
const min = minVersionBump(current.tokens, update.tokens)
|
||||
// Automatically update minor/patch as long as bump matches the min update.
|
||||
if (targetBump >= min) {
|
||||
return true
|
||||
} else {
|
||||
console.debug(
|
||||
`List at url ${listUrl} could not automatically update because the version bump was only PATCH/MINOR while the update had breaking changes and should have been MAJOR`
|
||||
)
|
||||
return false
|
||||
}
|
||||
}
|
74
src/state/migrations/3.test.ts
Normal file
74
src/state/migrations/3.test.ts
Normal file
@ -0,0 +1,74 @@
|
||||
import { ChainId, Token } from '@uniswap/sdk-core'
|
||||
import { createMigrate } from 'redux-persist'
|
||||
import { RouterPreference } from 'state/routing/types'
|
||||
import { SlippageTolerance } from 'state/user/types'
|
||||
|
||||
import { migration1 } from './1'
|
||||
import { migration2 } from './2'
|
||||
import { migration3, PersistAppStateV3 } from './3'
|
||||
|
||||
const previousState: PersistAppStateV3 = {
|
||||
user: {
|
||||
userLocale: null,
|
||||
userRouterPreference: RouterPreference.API,
|
||||
userHideClosedPositions: false,
|
||||
userSlippageTolerance: SlippageTolerance.Auto,
|
||||
userSlippageToleranceHasBeenMigratedToAuto: true,
|
||||
userDeadline: 1800,
|
||||
tokens: {
|
||||
// wrong tokens
|
||||
[ChainId.OPTIMISM]: {
|
||||
'0x7F5c764cBc14f9669B88837ca1490cCa17c31607': new Token(
|
||||
ChainId.OPTIMISM,
|
||||
'0x7F5c764cBc14f9669B88837ca1490cCa17c31607',
|
||||
6,
|
||||
'USDC',
|
||||
'USD Coin'
|
||||
),
|
||||
},
|
||||
[ChainId.BASE]: {
|
||||
'0xd9aAEc86B65D86f6A7B5B1b0c42FFA531710b6CA': new Token(
|
||||
ChainId.BASE,
|
||||
'0xd9aAEc86B65D86f6A7B5B1b0c42FFA531710b6CA',
|
||||
6,
|
||||
'USDC',
|
||||
'USD Coin'
|
||||
),
|
||||
},
|
||||
},
|
||||
pairs: {},
|
||||
timestamp: Date.now(),
|
||||
hideBaseWalletBanner: false,
|
||||
},
|
||||
_persist: {
|
||||
version: 2,
|
||||
rehydrated: true,
|
||||
},
|
||||
}
|
||||
|
||||
describe('migration to v3', () => {
|
||||
it('should migrate users who currently have outdated USDC.e saved', async () => {
|
||||
const migrator = createMigrate(
|
||||
{
|
||||
1: migration1,
|
||||
2: migration2,
|
||||
3: migration3,
|
||||
},
|
||||
{ debug: false }
|
||||
)
|
||||
const result: any = await migrator(previousState, 3)
|
||||
expect(Object.keys(result?.user?.tokens).length).toEqual(2)
|
||||
expect(result?.user?.tokens[ChainId.OPTIMISM]?.['0x7F5c764cBc14f9669B88837ca1490cCa17c31607'].symbol).toEqual(
|
||||
'USDC.e'
|
||||
)
|
||||
expect(result?.user?.tokens[ChainId.OPTIMISM]?.['0x7F5c764cBc14f9669B88837ca1490cCa17c31607'].name).toEqual(
|
||||
'Bridged USDC'
|
||||
)
|
||||
expect(result?.user?.tokens[ChainId.BASE]?.['0xd9aAEc86B65D86f6A7B5B1b0c42FFA531710b6CA'].symbol).toEqual('USDbC')
|
||||
expect(result?.user?.tokens[ChainId.BASE]?.['0xd9aAEc86B65D86f6A7B5B1b0c42FFA531710b6CA'].name).toEqual(
|
||||
'USD Base Coin'
|
||||
)
|
||||
|
||||
expect(result?._persist.version).toEqual(3)
|
||||
})
|
||||
})
|
55
src/state/migrations/3.ts
Normal file
55
src/state/migrations/3.ts
Normal file
@ -0,0 +1,55 @@
|
||||
import { Token } from '@uniswap/sdk-core'
|
||||
import { ChainId } from '@uniswap/sdk-core'
|
||||
import { PersistState } from 'redux-persist'
|
||||
import { serializeToken } from 'state/user/hooks'
|
||||
import { UserState } from 'state/user/reducer'
|
||||
|
||||
export type PersistAppStateV3 = {
|
||||
_persist: PersistState
|
||||
} & { user?: UserState }
|
||||
|
||||
/**
|
||||
* Migration to clear users' imported token lists, after
|
||||
* breaking changes to token info for multichain native USDC.
|
||||
*/
|
||||
export const migration3 = (state: PersistAppStateV3 | undefined) => {
|
||||
if (state?.user) {
|
||||
// Update USDC.e tokens to use the the new USDC.e symbol (from USDC)
|
||||
const USDCe_ADDRESSES: { [key in ChainId]?: string } = {
|
||||
[ChainId.OPTIMISM]: '0x7F5c764cBc14f9669B88837ca1490cCa17c31607',
|
||||
[ChainId.OPTIMISM_GOERLI]: '0x7E07E15D2a87A24492740D16f5bdF58c16db0c4E',
|
||||
[ChainId.ARBITRUM_ONE]: '0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8',
|
||||
[ChainId.ARBITRUM_GOERLI]: '0x8FB1E3fC51F3b789dED7557E680551d93Ea9d892',
|
||||
[ChainId.AVALANCHE]: '0xA7D7079b0FEaD91F3e65f86E8915Cb59c1a4C664',
|
||||
[ChainId.POLYGON]: '0x2791bca1f2de4661ed88a30c99a7a9449aa84174',
|
||||
[ChainId.POLYGON_MUMBAI]: '0xe11a86849d99f524cac3e7a0ec1241828e332c62',
|
||||
}
|
||||
for (const [chainId, address] of Object.entries(USDCe_ADDRESSES)) {
|
||||
const chainIdKey = Number(chainId) as ChainId
|
||||
if (state.user.tokens[chainIdKey]?.[address]) {
|
||||
state.user.tokens[chainIdKey][address] = serializeToken(
|
||||
new Token(chainIdKey, address, 6, 'USDC.e', 'Bridged USDC')
|
||||
)
|
||||
}
|
||||
}
|
||||
// Update USDbC token to use the new USDbC symbol (from USDC)
|
||||
const USDbC_BASE = new Token(
|
||||
ChainId.BASE,
|
||||
'0xd9aAEc86B65D86f6A7B5B1b0c42FFA531710b6CA',
|
||||
6,
|
||||
'USDbC',
|
||||
'USD Base Coin'
|
||||
)
|
||||
if (state.user.tokens[ChainId.BASE]?.[USDbC_BASE.address]) {
|
||||
state.user.tokens[ChainId.BASE][USDbC_BASE.address] = serializeToken(USDbC_BASE)
|
||||
}
|
||||
return {
|
||||
...state,
|
||||
_persist: {
|
||||
...state._persist,
|
||||
version: 3,
|
||||
},
|
||||
}
|
||||
}
|
||||
return state
|
||||
}
|
Loading…
Reference in New Issue
Block a user