wallet-stack 1.0.0-alpha.133 → 1.0.0-alpha.135
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/analytics/Properties.tsx +1 -1
- package/src/components/ReviewTransaction.test.tsx +49 -8
- package/src/components/ReviewTransaction.tsx +58 -12
- package/src/icons/VerifiedBadge.tsx +27 -0
- package/src/identity/actions.ts +0 -17
- package/src/identity/contactMapping.test.ts +78 -19
- package/src/identity/contactMapping.ts +50 -20
- package/src/identity/reducer.ts +7 -21
- package/src/identity/selectors.ts +0 -2
- package/src/recipients/RecipientItemV2.test.tsx +11 -72
- package/src/recipients/RecipientItemV2.tsx +1 -34
- package/src/recipients/recipient.test.ts +6 -5
- package/src/recipients/recipient.ts +7 -12
- package/src/recipients/verifier.ts +20 -0
- package/src/redux/migrations.test.ts +25 -0
- package/src/redux/migrations.ts +21 -0
- package/src/redux/store.test.ts +1 -2
- package/src/redux/store.ts +1 -1
- package/src/send/EnterAmount.tsx +106 -83
- package/src/send/SelectRecipientAddress.tsx +11 -13
- package/src/send/SendConfirmation.test.tsx +3 -3
- package/src/send/SendConfirmation.tsx +3 -3
- package/src/send/SendEnterAmount.test.tsx +27 -0
- package/src/send/SendSelectRecipient.test.tsx +37 -51
- package/src/send/useFetchRecipientVerificationStatus.ts +6 -11
- package/src/transactions/UserSection.tsx +37 -11
- package/src/transactions/feed/TransactionDetailsScreen.test.tsx +6 -6
- package/src/utils/phoneNumbers.ts +0 -11
package/src/identity/reducer.ts
CHANGED
|
@@ -31,12 +31,11 @@ export interface ImportContactProgress {
|
|
|
31
31
|
total: number
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
export interface AddressToVerificationStatus {
|
|
35
|
-
[address: string]: boolean | undefined
|
|
36
|
-
}
|
|
37
|
-
|
|
38
34
|
export interface AddressToVerifiedByType {
|
|
39
|
-
|
|
35
|
+
// undefined = never checked / unknown
|
|
36
|
+
// null = checked, no known verifier
|
|
37
|
+
// string = checked, verified by that verifier (e.g. "valora", "minipay")
|
|
38
|
+
[address: string]: string | null | undefined
|
|
40
39
|
}
|
|
41
40
|
|
|
42
41
|
interface State {
|
|
@@ -48,8 +47,6 @@ interface State {
|
|
|
48
47
|
// Has the user already been asked for contacts permission
|
|
49
48
|
askedContactsPermission: boolean
|
|
50
49
|
importContactsProgress: ImportContactProgress
|
|
51
|
-
// Mapping of address to verification status; undefined entries represent a loading state
|
|
52
|
-
addressToVerificationStatus: AddressToVerificationStatus
|
|
53
50
|
// Mapping of address to the entity that verified it (e.g. "valora", "minipay")
|
|
54
51
|
addressToVerifiedBy: AddressToVerifiedByType
|
|
55
52
|
lastSavedContactsHash: string | null
|
|
@@ -66,7 +63,6 @@ const initialState: State = {
|
|
|
66
63
|
current: 0,
|
|
67
64
|
total: 0,
|
|
68
65
|
},
|
|
69
|
-
addressToVerificationStatus: {},
|
|
70
66
|
addressToVerifiedBy: {},
|
|
71
67
|
lastSavedContactsHash: null,
|
|
72
68
|
shouldRefreshStoredPasswordHash: false,
|
|
@@ -144,21 +140,11 @@ export const reducer = (
|
|
|
144
140
|
e164NumberToAddress: state.e164NumberToAddress,
|
|
145
141
|
}
|
|
146
142
|
case Actions.FETCH_ADDRESS_VERIFICATION_STATUS:
|
|
147
|
-
// If the current status is false or does not exist, we set it to undefined
|
|
148
|
-
// to mark it as being in a loading state.
|
|
149
|
-
return {
|
|
150
|
-
...state,
|
|
151
|
-
addressToVerificationStatus: {
|
|
152
|
-
...state.addressToVerificationStatus,
|
|
153
|
-
[action.address]: state.addressToVerificationStatus[action.address] || undefined,
|
|
154
|
-
},
|
|
155
|
-
}
|
|
156
|
-
case Actions.ADDRESS_VERIFICATION_STATUS_RECEIVED:
|
|
157
143
|
return {
|
|
158
144
|
...state,
|
|
159
|
-
|
|
160
|
-
...state.
|
|
161
|
-
[action.address]:
|
|
145
|
+
addressToVerifiedBy: {
|
|
146
|
+
...state.addressToVerifiedBy,
|
|
147
|
+
[action.address]: undefined,
|
|
162
148
|
},
|
|
163
149
|
}
|
|
164
150
|
case Actions.CONTACTS_SAVED:
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { RootState } from 'src/redux/reducers'
|
|
2
2
|
|
|
3
3
|
export const e164NumberToAddressSelector = (state: RootState) => state.identity.e164NumberToAddress
|
|
4
|
-
export const addressToVerificationStatusSelector = (state: RootState) =>
|
|
5
|
-
state.identity.addressToVerificationStatus
|
|
6
4
|
export const addressToE164NumberSelector = (state: RootState) => state.identity.addressToE164Number
|
|
7
5
|
export const addressToVerifiedBySelector = (state: RootState) => state.identity.addressToVerifiedBy
|
|
8
6
|
export const importContactsProgressSelector = (state: RootState) =>
|
|
@@ -4,23 +4,12 @@ import 'react-native'
|
|
|
4
4
|
import { Provider } from 'react-redux'
|
|
5
5
|
import RecipientItem from 'src/recipients/RecipientItemV2'
|
|
6
6
|
import { createMockStore } from 'test/utils'
|
|
7
|
-
import {
|
|
8
|
-
mockAddressRecipient,
|
|
9
|
-
mockInvitableRecipient,
|
|
10
|
-
mockPhoneRecipient,
|
|
11
|
-
mockRecipient,
|
|
12
|
-
} from 'test/values'
|
|
7
|
+
import { mockAddressRecipient, mockInvitableRecipient, mockPhoneRecipient } from 'test/values'
|
|
13
8
|
|
|
14
9
|
describe('RecipientItemV2', () => {
|
|
15
|
-
it('renders
|
|
16
|
-
const {
|
|
17
|
-
<Provider
|
|
18
|
-
store={createMockStore({
|
|
19
|
-
identity: {
|
|
20
|
-
e164NumberToAddress: {},
|
|
21
|
-
},
|
|
22
|
-
})}
|
|
23
|
-
>
|
|
10
|
+
it('renders contact name and phone number', () => {
|
|
11
|
+
const { getByText } = render(
|
|
12
|
+
<Provider store={createMockStore()}>
|
|
24
13
|
<RecipientItem
|
|
25
14
|
recipient={mockInvitableRecipient}
|
|
26
15
|
onSelectRecipient={jest.fn()}
|
|
@@ -30,35 +19,23 @@ describe('RecipientItemV2', () => {
|
|
|
30
19
|
)
|
|
31
20
|
expect(getByText(mockInvitableRecipient.name)).toBeTruthy()
|
|
32
21
|
expect(getByText(mockInvitableRecipient.displayNumber)).toBeTruthy()
|
|
33
|
-
expect(queryByTestId('RecipientItem/AppIcon')).toBeFalsy()
|
|
34
|
-
expect(queryByTestId('RecipientItem/ActivityIndicator')).toBeFalsy()
|
|
35
22
|
})
|
|
36
23
|
|
|
37
|
-
it('renders
|
|
38
|
-
const {
|
|
39
|
-
<Provider
|
|
40
|
-
store={createMockStore({
|
|
41
|
-
identity: {
|
|
42
|
-
e164NumberToAddress: { [mockInvitableRecipient.e164PhoneNumber]: null },
|
|
43
|
-
},
|
|
44
|
-
})}
|
|
45
|
-
>
|
|
24
|
+
it('renders spinner while loading', () => {
|
|
25
|
+
const { getByTestId } = render(
|
|
26
|
+
<Provider store={createMockStore()}>
|
|
46
27
|
<RecipientItem
|
|
47
28
|
recipient={mockInvitableRecipient}
|
|
48
29
|
onSelectRecipient={jest.fn()}
|
|
49
|
-
loading={
|
|
30
|
+
loading={true}
|
|
50
31
|
/>
|
|
51
32
|
</Provider>
|
|
52
33
|
)
|
|
53
|
-
expect(
|
|
54
|
-
expect(getByText(mockInvitableRecipient.displayNumber)).toBeTruthy()
|
|
55
|
-
expect(queryByTestId('RecipientItem/AppIcon')).toBeFalsy()
|
|
56
|
-
expect(queryByTestId('RecipientItem/ActivityIndicator')).toBeFalsy()
|
|
34
|
+
expect(getByTestId('RecipientItem/ActivityIndicator')).toBeTruthy()
|
|
57
35
|
})
|
|
58
36
|
|
|
59
|
-
it('
|
|
60
|
-
const { queryByTestId
|
|
61
|
-
// default store includes a cached mapping
|
|
37
|
+
it('hides spinner when not loading', () => {
|
|
38
|
+
const { queryByTestId } = render(
|
|
62
39
|
<Provider store={createMockStore()}>
|
|
63
40
|
<RecipientItem
|
|
64
41
|
recipient={mockInvitableRecipient}
|
|
@@ -67,47 +44,9 @@ describe('RecipientItemV2', () => {
|
|
|
67
44
|
/>
|
|
68
45
|
</Provider>
|
|
69
46
|
)
|
|
70
|
-
expect(getByText(mockInvitableRecipient.name)).toBeTruthy()
|
|
71
|
-
expect(getByText(mockInvitableRecipient.displayNumber)).toBeTruthy()
|
|
72
|
-
expect(getByTestId('RecipientItem/AppIcon')).toBeTruthy()
|
|
73
|
-
expect(queryByTestId('RecipientItem/ActivityIndicator')).toBeFalsy()
|
|
74
|
-
})
|
|
75
|
-
|
|
76
|
-
it('renders correctly with app icon if address recipient is an app user', () => {
|
|
77
|
-
const { queryByTestId, getByText, getByTestId } = render(
|
|
78
|
-
// default store includes a cached mapping
|
|
79
|
-
<Provider
|
|
80
|
-
store={createMockStore({
|
|
81
|
-
identity: {
|
|
82
|
-
addressToVerificationStatus: {
|
|
83
|
-
[mockRecipient.address]: true,
|
|
84
|
-
},
|
|
85
|
-
},
|
|
86
|
-
})}
|
|
87
|
-
>
|
|
88
|
-
<RecipientItem recipient={mockRecipient} onSelectRecipient={jest.fn()} loading={false} />
|
|
89
|
-
</Provider>
|
|
90
|
-
)
|
|
91
|
-
expect(getByText(mockRecipient.name)).toBeTruthy()
|
|
92
|
-
expect(getByTestId('RecipientItem/AppIcon')).toBeTruthy()
|
|
93
47
|
expect(queryByTestId('RecipientItem/ActivityIndicator')).toBeFalsy()
|
|
94
48
|
})
|
|
95
49
|
|
|
96
|
-
it('renders correctly if loading is set to true', () => {
|
|
97
|
-
const { getByText, getByTestId } = render(
|
|
98
|
-
<Provider store={createMockStore()}>
|
|
99
|
-
<RecipientItem
|
|
100
|
-
recipient={mockInvitableRecipient}
|
|
101
|
-
onSelectRecipient={jest.fn()}
|
|
102
|
-
loading={true}
|
|
103
|
-
/>
|
|
104
|
-
</Provider>
|
|
105
|
-
)
|
|
106
|
-
expect(getByText(mockInvitableRecipient.name)).toBeTruthy()
|
|
107
|
-
expect(getByText(mockInvitableRecipient.displayNumber)).toBeTruthy()
|
|
108
|
-
expect(getByTestId('RecipientItem/ActivityIndicator')).toBeTruthy()
|
|
109
|
-
})
|
|
110
|
-
|
|
111
50
|
it('tapping item invokes onSelectRecipient', () => {
|
|
112
51
|
const mockSelectRecipient = jest.fn()
|
|
113
52
|
const { getByTestId } = render(
|
|
@@ -1,23 +1,16 @@
|
|
|
1
|
-
import React, { memo
|
|
1
|
+
import React, { memo } from 'react'
|
|
2
2
|
import { useTranslation } from 'react-i18next'
|
|
3
3
|
import { ActivityIndicator, Keyboard, StyleSheet, Text, View } from 'react-native'
|
|
4
4
|
import ContactCircle from 'src/components/ContactCircle'
|
|
5
5
|
import Touchable from 'src/components/Touchable'
|
|
6
6
|
import PhoneIcon from 'src/icons/Phone'
|
|
7
7
|
import WalletIcon from 'src/icons/navigator/Wallet'
|
|
8
|
-
import {
|
|
9
|
-
addressToVerificationStatusSelector,
|
|
10
|
-
e164NumberToAddressSelector,
|
|
11
|
-
} from 'src/identity/selectors'
|
|
12
|
-
import Checkmark from 'src/icons/Checkmark'
|
|
13
8
|
import {
|
|
14
9
|
Recipient,
|
|
15
|
-
RecipientType,
|
|
16
10
|
getDisplayDetail,
|
|
17
11
|
getDisplayName,
|
|
18
12
|
recipientHasNumber,
|
|
19
13
|
} from 'src/recipients/recipient'
|
|
20
|
-
import { useSelector } from 'src/redux/hooks'
|
|
21
14
|
import Colors from 'src/styles/colors'
|
|
22
15
|
import { typeScale } from 'src/styles/fonts'
|
|
23
16
|
import { Spacing } from 'src/styles/styles'
|
|
@@ -29,8 +22,6 @@ interface Props {
|
|
|
29
22
|
selected?: boolean
|
|
30
23
|
}
|
|
31
24
|
|
|
32
|
-
const ICON_SIZE = 10
|
|
33
|
-
|
|
34
25
|
function RecipientItem({ recipient, onSelectRecipient, loading, selected }: Props) {
|
|
35
26
|
const { t } = useTranslation()
|
|
36
27
|
|
|
@@ -39,17 +30,6 @@ function RecipientItem({ recipient, onSelectRecipient, loading, selected }: Prop
|
|
|
39
30
|
onSelectRecipient(recipient)
|
|
40
31
|
}
|
|
41
32
|
|
|
42
|
-
const e164NumberToAddress = useSelector(e164NumberToAddressSelector)
|
|
43
|
-
const addressToVerificationStatus = useSelector(addressToVerificationStatusSelector)
|
|
44
|
-
|
|
45
|
-
// TODO(ACT-980): avoid icon flash when a known contact is clicked
|
|
46
|
-
const showAppIcon = useMemo(() => {
|
|
47
|
-
if (recipient.recipientType === RecipientType.PhoneNumber) {
|
|
48
|
-
return recipient.e164PhoneNumber && !!e164NumberToAddress[recipient.e164PhoneNumber]
|
|
49
|
-
}
|
|
50
|
-
return recipient.address && addressToVerificationStatus[recipient.address]
|
|
51
|
-
}, [e164NumberToAddress, recipient])
|
|
52
|
-
|
|
53
33
|
return (
|
|
54
34
|
<Touchable onPress={onPress} testID="RecipientItem">
|
|
55
35
|
<View style={[styles.row, selected && styles.rowSelected]}>
|
|
@@ -62,11 +42,6 @@ function RecipientItem({ recipient, onSelectRecipient, loading, selected }: Prop
|
|
|
62
42
|
borderColor={Colors.borderPrimary}
|
|
63
43
|
DefaultIcon={() => renderDefaultIcon(recipient)} // no need to honor color props here since the color we need match the defaults
|
|
64
44
|
/>
|
|
65
|
-
{!!showAppIcon && (
|
|
66
|
-
<View style={styles.appIcon} testID="RecipientItem/AppIcon">
|
|
67
|
-
<Checkmark color={Colors.contentTertiary} height={ICON_SIZE} width={ICON_SIZE} />
|
|
68
|
-
</View>
|
|
69
|
-
)}
|
|
70
45
|
</View>
|
|
71
46
|
<View style={styles.contentContainer}>
|
|
72
47
|
<Text numberOfLines={1} ellipsizeMode={'tail'} style={styles.name}>
|
|
@@ -121,14 +96,6 @@ const styles = StyleSheet.create({
|
|
|
121
96
|
justifyContent: 'center',
|
|
122
97
|
alignItems: 'center',
|
|
123
98
|
},
|
|
124
|
-
appIcon: {
|
|
125
|
-
position: 'absolute',
|
|
126
|
-
top: 22,
|
|
127
|
-
left: 22,
|
|
128
|
-
backgroundColor: Colors.accent,
|
|
129
|
-
borderRadius: 100,
|
|
130
|
-
padding: 2,
|
|
131
|
-
},
|
|
132
99
|
})
|
|
133
100
|
|
|
134
101
|
export default memo(RecipientItem)
|
|
@@ -76,15 +76,16 @@ describe('getRecipientVerificationStatus', () => {
|
|
|
76
76
|
{ recipient: mockRecipient, type: 'with phone number' },
|
|
77
77
|
])('address recipient $type', ({ recipient }) => {
|
|
78
78
|
it('returns appropriate status', () => {
|
|
79
|
-
|
|
79
|
+
const key = recipient.address.toLowerCase()
|
|
80
|
+
expect(getRecipientVerificationStatus(recipient, {}, { [key]: 'valora' })).toEqual(
|
|
80
81
|
RecipientVerificationStatus.VERIFIED
|
|
81
82
|
)
|
|
82
|
-
expect(getRecipientVerificationStatus(recipient, {}, { [
|
|
83
|
+
expect(getRecipientVerificationStatus(recipient, {}, { [key]: null })).toEqual(
|
|
83
84
|
RecipientVerificationStatus.UNVERIFIED
|
|
84
85
|
)
|
|
85
|
-
expect(
|
|
86
|
-
|
|
87
|
-
)
|
|
86
|
+
expect(getRecipientVerificationStatus(recipient, {}, { [key]: undefined })).toEqual(
|
|
87
|
+
RecipientVerificationStatus.UNKNOWN
|
|
88
|
+
)
|
|
88
89
|
expect(getRecipientVerificationStatus(recipient, {}, {})).toEqual(
|
|
89
90
|
RecipientVerificationStatus.UNKNOWN
|
|
90
91
|
)
|
|
@@ -5,7 +5,7 @@ import { formatShortenedAddress } from 'src/account/utils'
|
|
|
5
5
|
import {
|
|
6
6
|
AddressToDisplayNameType,
|
|
7
7
|
AddressToE164NumberType,
|
|
8
|
-
|
|
8
|
+
AddressToVerifiedByType,
|
|
9
9
|
E164NumberToAddressType,
|
|
10
10
|
} from 'src/identity/reducer'
|
|
11
11
|
import { RecipientVerificationStatus } from 'src/identity/types'
|
|
@@ -168,7 +168,7 @@ export function getRecipientFromAddress(
|
|
|
168
168
|
export function getRecipientVerificationStatus(
|
|
169
169
|
recipient: Recipient,
|
|
170
170
|
e164NumberToAddress: E164NumberToAddressType,
|
|
171
|
-
|
|
171
|
+
addressToVerifiedBy: AddressToVerifiedByType
|
|
172
172
|
): RecipientVerificationStatus {
|
|
173
173
|
// phone recipients should always have a number, the extra check is to ensure typing
|
|
174
174
|
if (recipient.recipientType === RecipientType.PhoneNumber && recipientHasNumber(recipient)) {
|
|
@@ -183,18 +183,13 @@ export function getRecipientVerificationStatus(
|
|
|
183
183
|
|
|
184
184
|
return RecipientVerificationStatus.VERIFIED
|
|
185
185
|
}
|
|
186
|
-
if (recipientHasAddress(recipient)
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
case false:
|
|
191
|
-
return RecipientVerificationStatus.UNVERIFIED
|
|
192
|
-
case undefined:
|
|
193
|
-
return RecipientVerificationStatus.UNKNOWN
|
|
194
|
-
}
|
|
195
|
-
} else {
|
|
186
|
+
if (recipientHasAddress(recipient)) {
|
|
187
|
+
const entry = addressToVerifiedBy[recipient.address.toLowerCase()]
|
|
188
|
+
if (entry) return RecipientVerificationStatus.VERIFIED
|
|
189
|
+
if (entry === null) return RecipientVerificationStatus.UNVERIFIED
|
|
196
190
|
return RecipientVerificationStatus.UNKNOWN
|
|
197
191
|
}
|
|
192
|
+
return RecipientVerificationStatus.UNKNOWN
|
|
198
193
|
}
|
|
199
194
|
|
|
200
195
|
type PreparedRecipient = Recipient & {
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { addressToVerifiedBySelector } from 'src/identity/selectors'
|
|
2
|
+
import { miniPay, valora } from 'src/images/Images'
|
|
3
|
+
import { useSelector } from 'src/redux/hooks'
|
|
4
|
+
|
|
5
|
+
export const VERIFIERS = {
|
|
6
|
+
valora: { name: 'Valora', icon: valora },
|
|
7
|
+
minipay: { name: 'MiniPay', icon: miniPay },
|
|
8
|
+
} as const
|
|
9
|
+
|
|
10
|
+
export type Verifier = keyof typeof VERIFIERS
|
|
11
|
+
|
|
12
|
+
export function isKnownVerifier(verifier: string | null | undefined): verifier is Verifier {
|
|
13
|
+
return !!verifier && Object.hasOwn(VERIFIERS, verifier)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function useVerifierName(address: string | undefined): string | undefined {
|
|
17
|
+
const addressToVerifiedBy = useSelector(addressToVerifiedBySelector)
|
|
18
|
+
const verifier = address ? addressToVerifiedBy[address.toLowerCase()] : undefined
|
|
19
|
+
return isKnownVerifier(verifier) ? VERIFIERS[verifier].name : undefined
|
|
20
|
+
}
|
|
@@ -69,6 +69,7 @@ import {
|
|
|
69
69
|
v253Schema,
|
|
70
70
|
v254Schema,
|
|
71
71
|
v255Schema,
|
|
72
|
+
v256Schema,
|
|
72
73
|
v28Schema,
|
|
73
74
|
v2Schema,
|
|
74
75
|
v35Schema,
|
|
@@ -1959,4 +1960,28 @@ describe('Redux persist migrations', () => {
|
|
|
1959
1960
|
const migratedSchema = migrations[256](oldSchema)
|
|
1960
1961
|
expect(migratedSchema.identity.secureSendPhoneNumberMapping).toBeUndefined()
|
|
1961
1962
|
})
|
|
1963
|
+
|
|
1964
|
+
it('works from 256 to 257', () => {
|
|
1965
|
+
const oldSchema = {
|
|
1966
|
+
...v256Schema,
|
|
1967
|
+
identity: {
|
|
1968
|
+
...v256Schema.identity,
|
|
1969
|
+
addressToVerificationStatus: {
|
|
1970
|
+
'0xAAA': true,
|
|
1971
|
+
'0xbbb': false,
|
|
1972
|
+
'0xccc': undefined,
|
|
1973
|
+
},
|
|
1974
|
+
addressToVerifiedBy: {
|
|
1975
|
+
'0xddd': 'minipay',
|
|
1976
|
+
},
|
|
1977
|
+
},
|
|
1978
|
+
}
|
|
1979
|
+
const migratedSchema = migrations[257](oldSchema)
|
|
1980
|
+
expect(migratedSchema.identity.addressToVerificationStatus).toBeUndefined()
|
|
1981
|
+
expect(migratedSchema.identity.addressToVerifiedBy).toStrictEqual({
|
|
1982
|
+
'0xddd': 'minipay',
|
|
1983
|
+
'0xaaa': 'valora', // `true` carried over (and lowercased)
|
|
1984
|
+
// `false` and `undefined` entries are dropped — `false` was ambiguous in the old schema
|
|
1985
|
+
})
|
|
1986
|
+
})
|
|
1962
1987
|
})
|
package/src/redux/migrations.ts
CHANGED
|
@@ -2081,4 +2081,25 @@ export const migrations = {
|
|
|
2081
2081
|
...state,
|
|
2082
2082
|
identity: _.omit(state.identity, 'secureSendPhoneNumberMapping'),
|
|
2083
2083
|
}),
|
|
2084
|
+
257: (state: any) => {
|
|
2085
|
+
// Carry over previously confirmed verifications (all Valora)
|
|
2086
|
+
const oldMap: Record<string, boolean | undefined> =
|
|
2087
|
+
state.identity?.addressToVerificationStatus ?? {}
|
|
2088
|
+
const carriedOver: Record<string, string> = {}
|
|
2089
|
+
for (const [address, verified] of Object.entries(oldMap)) {
|
|
2090
|
+
if (verified === true) {
|
|
2091
|
+
carriedOver[address.toLowerCase()] = 'valora'
|
|
2092
|
+
}
|
|
2093
|
+
}
|
|
2094
|
+
return {
|
|
2095
|
+
...state,
|
|
2096
|
+
identity: {
|
|
2097
|
+
..._.omit(state.identity, 'addressToVerificationStatus'),
|
|
2098
|
+
addressToVerifiedBy: {
|
|
2099
|
+
...state.identity.addressToVerifiedBy,
|
|
2100
|
+
...carriedOver,
|
|
2101
|
+
},
|
|
2102
|
+
},
|
|
2103
|
+
}
|
|
2104
|
+
},
|
|
2084
2105
|
}
|
package/src/redux/store.test.ts
CHANGED
|
@@ -143,7 +143,7 @@ describe('store state', () => {
|
|
|
143
143
|
{
|
|
144
144
|
"_persist": {
|
|
145
145
|
"rehydrated": true,
|
|
146
|
-
"version":
|
|
146
|
+
"version": 257,
|
|
147
147
|
},
|
|
148
148
|
"account": {
|
|
149
149
|
"acceptedTerms": false,
|
|
@@ -244,7 +244,6 @@ describe('store state', () => {
|
|
|
244
244
|
"identity": {
|
|
245
245
|
"addressToDisplayName": {},
|
|
246
246
|
"addressToE164Number": {},
|
|
247
|
-
"addressToVerificationStatus": {},
|
|
248
247
|
"addressToVerifiedBy": {},
|
|
249
248
|
"askedContactsPermission": false,
|
|
250
249
|
"e164NumberToAddress": {},
|
package/src/redux/store.ts
CHANGED
|
@@ -30,7 +30,7 @@ const persistConfig: PersistConfig<ReducersRootState> = {
|
|
|
30
30
|
key: 'root',
|
|
31
31
|
// default is -1, increment as we make migrations
|
|
32
32
|
// See https://github.com/valora-xyz/wallet/tree/main/WALLET.md#redux-state-migration
|
|
33
|
-
version:
|
|
33
|
+
version: 257,
|
|
34
34
|
keyPrefix: `reduxStore-`, // the redux-persist default is `persist:` which doesn't work with some file systems.
|
|
35
35
|
storage: FSStorage(),
|
|
36
36
|
blacklist: ['networkInfo', 'alert', 'imports', 'keylessBackup', transactionFeedV2Api.reducerPath],
|