wallet-stack 1.0.0-alpha.132 → 1.0.0-alpha.133
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/locales/base/translation.json +5 -0
- package/package.json +1 -2
- package/src/analytics/Events.tsx +3 -10
- package/src/analytics/Properties.tsx +9 -25
- package/src/analytics/docs.ts +11 -8
- package/src/app/ErrorMessages.ts +0 -7
- package/src/identity/actions.ts +1 -97
- package/src/identity/contactMapping.test.ts +3 -28
- package/src/identity/contactMapping.ts +2 -88
- package/src/identity/reducer.ts +0 -77
- package/src/identity/saga.ts +2 -85
- package/src/identity/selectors.ts +0 -2
- package/src/images/Images.ts +2 -0
- package/src/images/assets/minipay.png +0 -0
- package/src/images/assets/minipay@1.5x.png +0 -0
- package/src/images/assets/minipay@2x.png +0 -0
- package/src/images/assets/minipay@3x.png +0 -0
- package/src/images/assets/minipay@4x.png +0 -0
- package/src/images/assets/valora.png +0 -0
- package/src/images/assets/valora@1.5x.png +0 -0
- package/src/images/assets/valora@2x.png +0 -0
- package/src/images/assets/valora@3x.png +0 -0
- package/src/images/assets/valora@4x.png +0 -0
- package/src/index.d.ts +0 -1
- package/src/navigator/Navigator.tsx +4 -14
- package/src/navigator/Screens.tsx +1 -2
- package/src/navigator/types.tsx +4 -6
- package/src/qrcode/utils.test.tsx +4 -96
- package/src/qrcode/utils.ts +5 -114
- package/src/redux/migrations.test.ts +13 -0
- package/src/redux/migrations.ts +4 -0
- package/src/redux/store.test.ts +1 -2
- package/src/redux/store.ts +1 -1
- package/src/send/SelectRecipientAddress.test.tsx +146 -0
- package/src/send/SelectRecipientAddress.tsx +166 -0
- package/src/send/SendSelectRecipient.test.tsx +16 -87
- package/src/send/SendSelectRecipient.tsx +12 -27
- package/src/send/actions.ts +0 -26
- package/src/send/saga.ts +1 -6
- package/src/components/AccountNumberCard.tsx +0 -23
- package/src/components/ErrorMessageInline.tsx +0 -78
- package/src/components/SingleDigitInput.tsx +0 -53
- package/src/icons/HamburgerCard.tsx +0 -55
- package/src/identity/saga.test.ts +0 -103
- package/src/identity/secureSend.ts +0 -171
- package/src/send/ValidateRecipientAccount.test.tsx +0 -182
- package/src/send/ValidateRecipientAccount.tsx +0 -392
- package/src/send/ValidateRecipientIntro.test.tsx +0 -61
- package/src/send/ValidateRecipientIntro.tsx +0 -136
- package/src/send/__snapshots__/ValidateRecipientAccount.test.tsx.snap +0 -777
|
@@ -2169,6 +2169,11 @@
|
|
|
2169
2169
|
"importSuccess": "Successfully imported {{tokenSymbol}} token",
|
|
2170
2170
|
"importButton": "Import"
|
|
2171
2171
|
},
|
|
2172
|
+
"selectRecipientAddress": {
|
|
2173
|
+
"header": "Select wallet",
|
|
2174
|
+
"recipient": "Recipient",
|
|
2175
|
+
"explanation": "<0>{{name}}</0> has more than one wallet linked to the phone number. Choose which one to send to."
|
|
2176
|
+
},
|
|
2172
2177
|
"sendSelectRecipient": {
|
|
2173
2178
|
"searchText": "Search by name, phone, wallet...",
|
|
2174
2179
|
"searchInputLabel": "To",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wallet-stack",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.133",
|
|
4
4
|
"author": "Valora Inc",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -148,7 +148,6 @@
|
|
|
148
148
|
"bignumber.js": "^9.1.2",
|
|
149
149
|
"country-data": "^0.0.31",
|
|
150
150
|
"date-fns": "^4.1.0",
|
|
151
|
-
"dot-prop-immutable": "^2.1.1",
|
|
152
151
|
"expo": "^53.0.22",
|
|
153
152
|
"expo-image": "~2.4.0",
|
|
154
153
|
"fast-levenshtein": "^3.0.0",
|
package/src/analytics/Events.tsx
CHANGED
|
@@ -269,16 +269,6 @@ export enum SendEvents {
|
|
|
269
269
|
send_confirm_back = 'send_confirm_back',
|
|
270
270
|
send_confirm_send = 'send_confirm_send',
|
|
271
271
|
|
|
272
|
-
send_secure_start = 'send_secure_start',
|
|
273
|
-
send_secure_back = 'send_secure_back',
|
|
274
|
-
send_secure_cancel = 'send_secure_cancel',
|
|
275
|
-
|
|
276
|
-
send_secure_info = 'send_secure_info',
|
|
277
|
-
send_secure_info_dismissed = 'send_secure_info_dismissed',
|
|
278
|
-
send_secure_submit = 'send_secure_submit',
|
|
279
|
-
send_secure_incorrect = 'send_secure_incorrect',
|
|
280
|
-
send_secure_complete = 'send_secure_complete',
|
|
281
|
-
|
|
282
272
|
send_tx_start = 'send_tx_start',
|
|
283
273
|
send_tx_complete = 'send_tx_complete',
|
|
284
274
|
send_tx_error = 'send_tx_error',
|
|
@@ -305,6 +295,9 @@ export enum SendEvents {
|
|
|
305
295
|
send_select_recipient_invite_press = 'send_select_recipient_invite_press',
|
|
306
296
|
send_select_recipient_send_press = 'send_select_recipient_send_press',
|
|
307
297
|
send_select_recipient_recent_press = 'send_select_recipient_recent_press',
|
|
298
|
+
send_select_recipient_address_open = 'send_select_recipient_address_open',
|
|
299
|
+
send_select_recipient_address_select = 'send_select_recipient_address_select',
|
|
300
|
+
send_select_recipient_address_back = 'send_select_recipient_address_back',
|
|
308
301
|
}
|
|
309
302
|
|
|
310
303
|
export enum QrScreenEvents {
|
|
@@ -71,6 +71,7 @@ import { NftOrigin } from 'src/nfts/types'
|
|
|
71
71
|
import { NotificationReceiveState } from 'src/notifications/types'
|
|
72
72
|
import { PointsActivityId } from 'src/points/types'
|
|
73
73
|
import { RecipientType } from 'src/recipients/recipient'
|
|
74
|
+
import { Verifier } from 'src/send/SelectRecipientAddress'
|
|
74
75
|
import { AmountEnteredIn, QrCode } from 'src/send/types'
|
|
75
76
|
import { Field, SwapType } from 'src/swap/types'
|
|
76
77
|
import { TokenActionName } from 'src/tokens/types'
|
|
@@ -521,31 +522,6 @@ interface SendEventsProperties {
|
|
|
521
522
|
isTokenManuallyImported: boolean
|
|
522
523
|
}
|
|
523
524
|
|
|
524
|
-
[SendEvents.send_secure_start]: {
|
|
525
|
-
confirmByScan: boolean
|
|
526
|
-
}
|
|
527
|
-
[SendEvents.send_secure_back]: undefined
|
|
528
|
-
[SendEvents.send_secure_cancel]: undefined
|
|
529
|
-
[SendEvents.send_secure_submit]: {
|
|
530
|
-
partialAddressValidation: boolean
|
|
531
|
-
address: string
|
|
532
|
-
}
|
|
533
|
-
[SendEvents.send_secure_complete]: {
|
|
534
|
-
confirmByScan: boolean
|
|
535
|
-
partialAddressValidation?: boolean
|
|
536
|
-
}
|
|
537
|
-
[SendEvents.send_secure_incorrect]: {
|
|
538
|
-
confirmByScan: boolean
|
|
539
|
-
partialAddressValidation?: boolean
|
|
540
|
-
error: string
|
|
541
|
-
}
|
|
542
|
-
[SendEvents.send_secure_info]: {
|
|
543
|
-
partialAddressValidation: boolean
|
|
544
|
-
}
|
|
545
|
-
[SendEvents.send_secure_info_dismissed]: {
|
|
546
|
-
partialAddressValidation: boolean
|
|
547
|
-
}
|
|
548
|
-
|
|
549
525
|
[SendEvents.send_tx_start]: undefined
|
|
550
526
|
[SendEvents.send_tx_complete]: {
|
|
551
527
|
txId: string
|
|
@@ -605,6 +581,14 @@ interface SendEventsProperties {
|
|
|
605
581
|
[SendEvents.send_select_recipient_recent_press]: {
|
|
606
582
|
recipientType: RecipientType
|
|
607
583
|
}
|
|
584
|
+
|
|
585
|
+
[SendEvents.send_select_recipient_address_open]: {
|
|
586
|
+
addressCount: number
|
|
587
|
+
}
|
|
588
|
+
[SendEvents.send_select_recipient_address_select]: {
|
|
589
|
+
verifier: Verifier
|
|
590
|
+
}
|
|
591
|
+
[SendEvents.send_select_recipient_address_back]: undefined
|
|
608
592
|
}
|
|
609
593
|
|
|
610
594
|
interface FeeEventsProperties {
|
package/src/analytics/docs.ts
CHANGED
|
@@ -259,14 +259,6 @@ export const eventDocs: Record<AnalyticsEventType, string> = {
|
|
|
259
259
|
[SendEvents.send_amount_continue]: `when next button pressed on amount enter page`,
|
|
260
260
|
[SendEvents.send_confirm_back]: `when back button pressed on send confirmation screen`,
|
|
261
261
|
[SendEvents.send_confirm_send]: `when send button pressed on send confirmation screen`,
|
|
262
|
-
[SendEvents.send_secure_start]: `when either secure send scan or manual confirm button pressed`,
|
|
263
|
-
[SendEvents.send_secure_back]: `when back button is pressed during secure send`,
|
|
264
|
-
[SendEvents.send_secure_cancel]: `when secure send flow is canceled`,
|
|
265
|
-
[SendEvents.send_secure_info]: `when "help" button is pressed`,
|
|
266
|
-
[SendEvents.send_secure_info_dismissed]: `when "help" button is dismissed`,
|
|
267
|
-
[SendEvents.send_secure_submit]: `when an account is submitted for validation`,
|
|
268
|
-
[SendEvents.send_secure_incorrect]: `when there's been an error validating the account`,
|
|
269
|
-
[SendEvents.send_secure_complete]: `when an account has been validated`,
|
|
270
262
|
[SendEvents.send_tx_start]: `issued from the sendPayment saga, after a user confirms their intent to send and right before we build and send the transaction to the network`,
|
|
271
263
|
[SendEvents.send_tx_complete]: `when a send transaction has successfully completed`,
|
|
272
264
|
[SendEvents.send_tx_error]: `when there is an error sending a transaction`,
|
|
@@ -292,6 +284,9 @@ export const eventDocs: Record<AnalyticsEventType, string> = {
|
|
|
292
284
|
[SendEvents.send_select_recipient_send_press]: `When the send button is pressed after selecting a recipient`,
|
|
293
285
|
[SendEvents.send_select_recipient_invite_press]: `When the invite button is pressed after selecting a recipient`,
|
|
294
286
|
[SendEvents.send_select_recipient_recent_press]: `When a recent recipient is pressed`,
|
|
287
|
+
[SendEvents.send_select_recipient_address_open]: `When the address picker screen is shown (a phone recipient has multiple verified addresses)`,
|
|
288
|
+
[SendEvents.send_select_recipient_address_select]: `When a verified address is picked from the address picker screen`,
|
|
289
|
+
[SendEvents.send_select_recipient_address_back]: `When the back button is pressed on the address picker screen`,
|
|
295
290
|
[JumpstartEvents.jumpstart_reclaim_press]:
|
|
296
291
|
'When user taps on "Reclaim" button on the Jumpstart screen',
|
|
297
292
|
[JumpstartEvents.jumpstart_reclaim_start]:
|
|
@@ -578,6 +573,14 @@ export const eventDocs: Record<AnalyticsEventType, string> = {
|
|
|
578
573
|
|
|
579
574
|
// Legacy event docs
|
|
580
575
|
// The below events had docs, but are no longer produced by the latest app version.
|
|
576
|
+
// [SendEvents.send_secure_start]: `when either secure send scan or manual confirm button pressed`,
|
|
577
|
+
// [SendEvents.send_secure_back]: `when back button is pressed during secure send`,
|
|
578
|
+
// [SendEvents.send_secure_cancel]: `when secure send flow is canceled`,
|
|
579
|
+
// [SendEvents.send_secure_info]: `when "help" button is pressed`,
|
|
580
|
+
// [SendEvents.send_secure_info_dismissed]: `when "help" button is dismissed`,
|
|
581
|
+
// [SendEvents.send_secure_submit]: `when an account is submitted for validation`,
|
|
582
|
+
// [SendEvents.send_secure_incorrect]: `when there's been an error validating the account`,
|
|
583
|
+
// [SendEvents.send_secure_complete]: `when an account has been validated`,
|
|
581
584
|
// [HomeEvents.home_send]: `when "send" button is pressed from home screen send or request bar (NOT from home screen actions)`,
|
|
582
585
|
// [HomeEvents.view_nft_home_assets]: `When "NFTs" is clicked in Home Assets Pages`,
|
|
583
586
|
// [DappExplorerEvents.dapp_open_info]: `when a user taps on the help icon`,
|
package/src/app/ErrorMessages.ts
CHANGED
|
@@ -16,13 +16,6 @@ export enum ErrorMessages {
|
|
|
16
16
|
FIREBASE_FAILED = 'firebaseFailed',
|
|
17
17
|
IMPORT_CONTACTS_FAILED = 'importContactsFailed',
|
|
18
18
|
QR_FAILED_INVALID_ADDRESS = 'qrFailedInvalidAddress',
|
|
19
|
-
QR_FAILED_INVALID_RECIPIENT = 'qrFailedInvalidRecipient',
|
|
20
|
-
ADDRESS_VALIDATION_ERROR = 'addressValidationError',
|
|
21
|
-
ADDRESS_VALIDATION_NO_MATCH = 'addressValidationNoMatch',
|
|
22
|
-
ADDRESS_VALIDATION_FULL_POORLY_FORMATTED = 'addressValidationFullPoorlyFormatted',
|
|
23
|
-
ADDRESS_VALIDATION_PARTIAL_POORLY_FORMATTED = 'addressValidationPartialPoorlyFormatted',
|
|
24
|
-
ADDRESS_VALIDATION_FULL_OWN_ADDRESS = 'addressValidationFullOwnAddress',
|
|
25
|
-
ADDRESS_VALIDATION_PARTIAL_OWN_ADDRESS = 'addressValidationPartialOwnAddress',
|
|
26
19
|
ACCOUNT_CLEAR_FAILED = 'accountClearFailed',
|
|
27
20
|
KEYCHAIN_FETCH_ACCOUNTS = 'keychainFetchAccounts',
|
|
28
21
|
KEYCHAIN_ACCOUNT_ALREADY_EXISTS = 'keychainAccountAlreadyExists',
|
package/src/identity/actions.ts
CHANGED
|
@@ -2,26 +2,18 @@ import {
|
|
|
2
2
|
AddressToDisplayNameType,
|
|
3
3
|
AddressToE164NumberType,
|
|
4
4
|
AddressToVerifiedByType,
|
|
5
|
-
AddressValidationType,
|
|
6
5
|
E164NumberToAddressType,
|
|
7
6
|
} from 'src/identity/reducer'
|
|
8
7
|
import { ImportContactsStatus } from 'src/identity/types'
|
|
9
|
-
import { Recipient } from 'src/recipients/recipient'
|
|
10
|
-
import { type E164Number } from 'src/utils/io'
|
|
11
8
|
|
|
12
9
|
export enum Actions {
|
|
13
10
|
UPDATE_E164_PHONE_NUMBER_ADDRESSES = 'IDENTITY/UPDATE_E164_PHONE_NUMBER_ADDRESSES',
|
|
14
11
|
UPDATE_KNOWN_ADDRESSES = 'IDENTITY/UPDATE_KNOWN_ADDRESSES',
|
|
15
12
|
FETCH_ADDRESSES_AND_VALIDATION_STATUS = 'IDENTITY/FETCH_ADDRESSES_AND_VALIDATION_STATUS',
|
|
16
|
-
END_FETCHING_ADDRESSES = 'IDENTITY/END_FETCHING_ADDRESSES',
|
|
17
13
|
IMPORT_CONTACTS = 'IDENTITY/IMPORT_CONTACTS',
|
|
18
14
|
UPDATE_IMPORT_CONTACT_PROGRESS = 'IDENTITY/UPDATE_IMPORT_CONTACT_PROGRESS',
|
|
19
15
|
CANCEL_IMPORT_CONTACTS = 'IDENTITY/CANCEL_IMPORT_CONTACTS',
|
|
20
16
|
END_IMPORT_CONTACTS = 'IDENTITY/END_IMPORT_CONTACTS',
|
|
21
|
-
VALIDATE_RECIPIENT_ADDRESS = 'IDENTITY/VALIDATE_RECIPIENT_ADDRESS',
|
|
22
|
-
VALIDATE_RECIPIENT_ADDRESS_SUCCESS = 'IDENTITY/VALIDATE_RECIPIENT_ADDRESS_SUCCESS',
|
|
23
|
-
VALIDATE_RECIPIENT_ADDRESS_RESET = 'IDENTITY/VALIDATE_RECIPIENT_ADDRESS_RESET',
|
|
24
|
-
REQUIRE_SECURE_SEND = 'IDENTITY/REQUIRE_SECURE_SEND',
|
|
25
17
|
FETCH_ADDRESS_VERIFICATION_STATUS = 'IDENTITY/FETCH_ADDRESS_VERIFICATION_STATUS',
|
|
26
18
|
ADDRESS_VERIFICATION_STATUS_RECEIVED = 'IDENTITY/ADDRESS_VERIFICATION_STATUS_RECEIVED',
|
|
27
19
|
CONTACTS_SAVED = 'IDENTITY/CONTACTS_SAVED',
|
|
@@ -43,13 +35,6 @@ export interface UpdateKnownAddressesAction {
|
|
|
43
35
|
export interface FetchAddressesAndValidateAction {
|
|
44
36
|
type: Actions.FETCH_ADDRESSES_AND_VALIDATION_STATUS
|
|
45
37
|
e164Number: string
|
|
46
|
-
requesterAddress?: string
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export interface EndFetchingAddressesAction {
|
|
50
|
-
type: Actions.END_FETCHING_ADDRESSES
|
|
51
|
-
e164Number: string
|
|
52
|
-
lastFetchSuccessful: boolean
|
|
53
38
|
}
|
|
54
39
|
|
|
55
40
|
export interface ImportContactsAction {
|
|
@@ -68,31 +53,6 @@ export interface EndImportContactsAction {
|
|
|
68
53
|
success: boolean
|
|
69
54
|
}
|
|
70
55
|
|
|
71
|
-
export interface ValidateRecipientAddressAction {
|
|
72
|
-
type: Actions.VALIDATE_RECIPIENT_ADDRESS
|
|
73
|
-
userInputOfFullAddressOrLastFourDigits: string
|
|
74
|
-
addressValidationType: AddressValidationType
|
|
75
|
-
recipient: Recipient
|
|
76
|
-
requesterAddress?: string
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
export interface ValidateRecipientAddressSuccessAction {
|
|
80
|
-
type: Actions.VALIDATE_RECIPIENT_ADDRESS_SUCCESS
|
|
81
|
-
e164Number: string
|
|
82
|
-
validatedAddress: string
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
export interface ValidateRecipientAddressResetAction {
|
|
86
|
-
type: Actions.VALIDATE_RECIPIENT_ADDRESS_RESET
|
|
87
|
-
e164Number: string
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
export interface RequireSecureSendAction {
|
|
91
|
-
type: Actions.REQUIRE_SECURE_SEND
|
|
92
|
-
e164Number: E164Number
|
|
93
|
-
addressValidationType: AddressValidationType
|
|
94
|
-
}
|
|
95
|
-
|
|
96
56
|
export interface FetchAddressVerificationAction {
|
|
97
57
|
type: Actions.FETCH_ADDRESS_VERIFICATION_STATUS
|
|
98
58
|
address: string
|
|
@@ -119,24 +79,15 @@ export type ActionTypes =
|
|
|
119
79
|
| ImportContactsAction
|
|
120
80
|
| UpdateImportContactProgress
|
|
121
81
|
| EndImportContactsAction
|
|
122
|
-
| ValidateRecipientAddressAction
|
|
123
|
-
| ValidateRecipientAddressSuccessAction
|
|
124
|
-
| ValidateRecipientAddressResetAction
|
|
125
|
-
| RequireSecureSendAction
|
|
126
82
|
| FetchAddressesAndValidateAction
|
|
127
|
-
| EndFetchingAddressesAction
|
|
128
83
|
| FetchAddressVerificationAction
|
|
129
84
|
| AddressVerificationStatusReceivedAction
|
|
130
85
|
| ContactsSavedAction
|
|
131
86
|
| StoredPasswordRefreshedAction
|
|
132
87
|
|
|
133
|
-
export const fetchAddressesAndValidate = (
|
|
134
|
-
e164Number: string,
|
|
135
|
-
requesterAddress?: string
|
|
136
|
-
): FetchAddressesAndValidateAction => ({
|
|
88
|
+
export const fetchAddressesAndValidate = (e164Number: string): FetchAddressesAndValidateAction => ({
|
|
137
89
|
type: Actions.FETCH_ADDRESSES_AND_VALIDATION_STATUS,
|
|
138
90
|
e164Number,
|
|
139
|
-
requesterAddress,
|
|
140
91
|
})
|
|
141
92
|
|
|
142
93
|
export const addressVerificationStatusReceived = (
|
|
@@ -153,15 +104,6 @@ export const fetchAddressVerification = (address: string): FetchAddressVerificat
|
|
|
153
104
|
address,
|
|
154
105
|
})
|
|
155
106
|
|
|
156
|
-
export const endFetchingAddresses = (
|
|
157
|
-
e164Number: string,
|
|
158
|
-
lastFetchSuccessful: boolean
|
|
159
|
-
): EndFetchingAddressesAction => ({
|
|
160
|
-
type: Actions.END_FETCHING_ADDRESSES,
|
|
161
|
-
e164Number,
|
|
162
|
-
lastFetchSuccessful,
|
|
163
|
-
})
|
|
164
|
-
|
|
165
107
|
export const updateE164PhoneNumberAddresses = (
|
|
166
108
|
e164NumberToAddress: E164NumberToAddressType,
|
|
167
109
|
addressToE164Number: AddressToE164NumberType,
|
|
@@ -200,44 +142,6 @@ export const endImportContacts = (success: boolean): EndImportContactsAction =>
|
|
|
200
142
|
success,
|
|
201
143
|
})
|
|
202
144
|
|
|
203
|
-
export const validateRecipientAddress = (
|
|
204
|
-
userInputOfFullAddressOrLastFourDigits: string,
|
|
205
|
-
addressValidationType: AddressValidationType,
|
|
206
|
-
recipient: Recipient,
|
|
207
|
-
requesterAddress?: string
|
|
208
|
-
): ValidateRecipientAddressAction => ({
|
|
209
|
-
type: Actions.VALIDATE_RECIPIENT_ADDRESS,
|
|
210
|
-
userInputOfFullAddressOrLastFourDigits,
|
|
211
|
-
addressValidationType,
|
|
212
|
-
recipient,
|
|
213
|
-
requesterAddress,
|
|
214
|
-
})
|
|
215
|
-
|
|
216
|
-
export const validateRecipientAddressSuccess = (
|
|
217
|
-
e164Number: E164Number,
|
|
218
|
-
validatedAddress: string
|
|
219
|
-
): ValidateRecipientAddressSuccessAction => ({
|
|
220
|
-
type: Actions.VALIDATE_RECIPIENT_ADDRESS_SUCCESS,
|
|
221
|
-
e164Number,
|
|
222
|
-
validatedAddress,
|
|
223
|
-
})
|
|
224
|
-
|
|
225
|
-
export const validateRecipientAddressReset = (
|
|
226
|
-
e164Number: E164Number
|
|
227
|
-
): ValidateRecipientAddressResetAction => ({
|
|
228
|
-
type: Actions.VALIDATE_RECIPIENT_ADDRESS_RESET,
|
|
229
|
-
e164Number,
|
|
230
|
-
})
|
|
231
|
-
|
|
232
|
-
export const requireSecureSend = (
|
|
233
|
-
e164Number: E164Number,
|
|
234
|
-
addressValidationType: AddressValidationType
|
|
235
|
-
): RequireSecureSendAction => ({
|
|
236
|
-
type: Actions.REQUIRE_SECURE_SEND,
|
|
237
|
-
e164Number,
|
|
238
|
-
addressValidationType,
|
|
239
|
-
})
|
|
240
|
-
|
|
241
145
|
export const contactsSaved = (hash: string): ContactsSavedAction => ({
|
|
242
146
|
type: Actions.CONTACTS_SAVED,
|
|
243
147
|
hash,
|
|
@@ -16,7 +16,6 @@ import {
|
|
|
16
16
|
contactsSaved,
|
|
17
17
|
fetchAddressVerification,
|
|
18
18
|
fetchAddressesAndValidate,
|
|
19
|
-
requireSecureSend,
|
|
20
19
|
updateE164PhoneNumberAddresses,
|
|
21
20
|
} from 'src/identity/actions'
|
|
22
21
|
import {
|
|
@@ -25,12 +24,9 @@ import {
|
|
|
25
24
|
fetchAddressesAndValidateSaga,
|
|
26
25
|
saveContacts,
|
|
27
26
|
} from 'src/identity/contactMapping'
|
|
28
|
-
import { AddressValidationType } from 'src/identity/reducer'
|
|
29
27
|
import {
|
|
30
28
|
addressToVerificationStatusSelector,
|
|
31
|
-
e164NumberToAddressSelector,
|
|
32
29
|
lastSavedContactsHashSelector,
|
|
33
|
-
secureSendPhoneNumberMappingSelector,
|
|
34
30
|
} from 'src/identity/selectors'
|
|
35
31
|
import { retrieveSignedMessage } from 'src/pincode/authentication'
|
|
36
32
|
import { contactsToRecipients } from 'src/recipients/recipient'
|
|
@@ -98,18 +94,13 @@ describe('Fetch Addresses Saga', () => {
|
|
|
98
94
|
})
|
|
99
95
|
|
|
100
96
|
it('fetches and caches addresses correctly', async () => {
|
|
101
|
-
const mockE164NumberToAddress = {
|
|
102
|
-
[mockE164Number]: [mockAccount.toLowerCase()],
|
|
103
|
-
}
|
|
104
97
|
const updatedAccount = '0xAbC'
|
|
105
98
|
mockFetch.mockResponseOnce(JSON.stringify({ data: { addresses: [updatedAccount] } }))
|
|
106
99
|
|
|
107
100
|
await expectSaga(fetchAddressesAndValidateSaga, fetchAddressesAndValidate(mockE164Number))
|
|
108
101
|
.provide([
|
|
109
|
-
[select(e164NumberToAddressSelector), mockE164NumberToAddress],
|
|
110
102
|
[select(walletAddressSelector), '0xxyz'],
|
|
111
103
|
[call(retrieveSignedMessage), 'some signed message'],
|
|
112
|
-
[select(secureSendPhoneNumberMappingSelector), {}],
|
|
113
104
|
])
|
|
114
105
|
.put(updateE164PhoneNumberAddresses({ [mockE164Number]: undefined }, {}))
|
|
115
106
|
.put(
|
|
@@ -135,18 +126,13 @@ describe('Fetch Addresses Saga', () => {
|
|
|
135
126
|
})
|
|
136
127
|
|
|
137
128
|
it('fetches and caches multiple addresses correctly', async () => {
|
|
138
|
-
const mockE164NumberToAddress = {
|
|
139
|
-
[mockE164Number]: [mockAccount.toLowerCase()],
|
|
140
|
-
}
|
|
141
129
|
const updatedAccounts = ['0xAbC', '0xdef']
|
|
142
130
|
mockFetch.mockResponseOnce(JSON.stringify({ data: { addresses: updatedAccounts } }))
|
|
143
131
|
|
|
144
132
|
await expectSaga(fetchAddressesAndValidateSaga, fetchAddressesAndValidate(mockE164Number))
|
|
145
133
|
.provide([
|
|
146
|
-
[select(
|
|
147
|
-
[select(walletAddressSelector), mockAccount],
|
|
134
|
+
[select(walletAddressSelector), '0xxyz'],
|
|
148
135
|
[call(retrieveSignedMessage), 'some signed message'],
|
|
149
|
-
[select(secureSendPhoneNumberMappingSelector), {}],
|
|
150
136
|
])
|
|
151
137
|
.put(updateE164PhoneNumberAddresses({ [mockE164Number]: undefined }, {}))
|
|
152
138
|
.put(
|
|
@@ -156,14 +142,10 @@ describe('Fetch Addresses Saga', () => {
|
|
|
156
142
|
{}
|
|
157
143
|
)
|
|
158
144
|
)
|
|
159
|
-
.put(requireSecureSend(mockE164Number, AddressValidationType.PARTIAL))
|
|
160
145
|
.run()
|
|
161
146
|
})
|
|
162
147
|
|
|
163
148
|
it('uses verifiedAddresses as source of truth when present', async () => {
|
|
164
|
-
const mockE164NumberToAddress = {
|
|
165
|
-
[mockE164Number]: [mockAccount.toLowerCase()],
|
|
166
|
-
}
|
|
167
149
|
// addresses only contains DB-verified addresses (backward compat),
|
|
168
150
|
// verifiedAddresses contains all (DB + SC) and is the source of truth
|
|
169
151
|
mockFetch.mockResponseOnce(
|
|
@@ -180,10 +162,8 @@ describe('Fetch Addresses Saga', () => {
|
|
|
180
162
|
|
|
181
163
|
await expectSaga(fetchAddressesAndValidateSaga, fetchAddressesAndValidate(mockE164Number))
|
|
182
164
|
.provide([
|
|
183
|
-
[select(
|
|
184
|
-
[select(walletAddressSelector), mockAccount],
|
|
165
|
+
[select(walletAddressSelector), '0xxyz'],
|
|
185
166
|
[call(retrieveSignedMessage), 'some signed message'],
|
|
186
|
-
[select(secureSendPhoneNumberMappingSelector), {}],
|
|
187
167
|
])
|
|
188
168
|
.put(updateE164PhoneNumberAddresses({ [mockE164Number]: undefined }, {}))
|
|
189
169
|
.put(
|
|
@@ -193,20 +173,15 @@ describe('Fetch Addresses Saga', () => {
|
|
|
193
173
|
{ '0xabc': 'valora', '0xdef': 'minipay' }
|
|
194
174
|
)
|
|
195
175
|
)
|
|
196
|
-
.put(requireSecureSend(mockE164Number, AddressValidationType.PARTIAL))
|
|
197
176
|
.run()
|
|
198
177
|
})
|
|
199
178
|
|
|
200
179
|
it('handles lookup errors correctly', async () => {
|
|
201
|
-
const mockE164NumberToAddress = {
|
|
202
|
-
[mockE164Number]: [mockAccount.toLowerCase()],
|
|
203
|
-
}
|
|
204
180
|
mockFetch.mockReject()
|
|
205
181
|
|
|
206
182
|
await expectSaga(fetchAddressesAndValidateSaga, fetchAddressesAndValidate(mockE164Number))
|
|
207
183
|
.provide([
|
|
208
|
-
[select(
|
|
209
|
-
[select(walletAddressSelector), mockAccount],
|
|
184
|
+
[select(walletAddressSelector), '0xxyz'],
|
|
210
185
|
[call(retrieveSignedMessage), 'some signed message'],
|
|
211
186
|
])
|
|
212
187
|
.put(showErrorOrFallback(expect.anything(), ErrorMessages.ADDRESS_LOOKUP_FAILURE))
|
|
@@ -13,24 +13,14 @@ import {
|
|
|
13
13
|
FetchAddressesAndValidateAction,
|
|
14
14
|
addressVerificationStatusReceived,
|
|
15
15
|
contactsSaved,
|
|
16
|
-
endFetchingAddresses,
|
|
17
16
|
endImportContacts,
|
|
18
|
-
requireSecureSend,
|
|
19
17
|
updateE164PhoneNumberAddresses,
|
|
20
18
|
updateImportContactsProgress,
|
|
21
19
|
} from 'src/identity/actions'
|
|
22
|
-
import {
|
|
23
|
-
AddressToE164NumberType,
|
|
24
|
-
AddressValidationType,
|
|
25
|
-
E164NumberToAddressType,
|
|
26
|
-
SecureSendPhoneNumberMapping,
|
|
27
|
-
} from 'src/identity/reducer'
|
|
28
|
-
import { checkIfValidationRequired } from 'src/identity/secureSend'
|
|
20
|
+
import { AddressToE164NumberType, E164NumberToAddressType } from 'src/identity/reducer'
|
|
29
21
|
import {
|
|
30
22
|
addressToVerificationStatusSelector,
|
|
31
|
-
e164NumberToAddressSelector,
|
|
32
23
|
lastSavedContactsHashSelector,
|
|
33
|
-
secureSendPhoneNumberMappingSelector,
|
|
34
24
|
} from 'src/identity/selectors'
|
|
35
25
|
import { ImportContactsStatus } from 'src/identity/types'
|
|
36
26
|
import { retrieveSignedMessage } from 'src/pincode/authentication'
|
|
@@ -144,17 +134,10 @@ function* updateUserContact(e164NumberToRecipients: NumberToRecipient) {
|
|
|
144
134
|
yield* put(setUserContactDetails(userRecipient.contactId, userRecipient.thumbnailPath || null))
|
|
145
135
|
}
|
|
146
136
|
|
|
147
|
-
export function* fetchAddressesAndValidateSaga({
|
|
148
|
-
e164Number,
|
|
149
|
-
requesterAddress,
|
|
150
|
-
}: FetchAddressesAndValidateAction) {
|
|
137
|
+
export function* fetchAddressesAndValidateSaga({ e164Number }: FetchAddressesAndValidateAction) {
|
|
151
138
|
AppAnalytics.track(IdentityEvents.phone_number_lookup_start)
|
|
152
139
|
try {
|
|
153
140
|
Logger.debug(TAG + '@fetchAddressesAndValidate', `Fetching addresses for number`)
|
|
154
|
-
const oldE164NumberToAddress: E164NumberToAddressType = yield* select(
|
|
155
|
-
e164NumberToAddressSelector
|
|
156
|
-
)
|
|
157
|
-
const oldAddresses = oldE164NumberToAddress[e164Number] || []
|
|
158
141
|
|
|
159
142
|
// Clear existing entries for those numbers so our mapping consumers know new status is pending.
|
|
160
143
|
yield* put(updateE164PhoneNumberAddresses({ [e164Number]: undefined }, {}))
|
|
@@ -186,28 +169,6 @@ export function* fetchAddressesAndValidateSaga({
|
|
|
186
169
|
walletAddresses.map((a) => (addressToE164NumberUpdates[a] = e164Number))
|
|
187
170
|
}
|
|
188
171
|
|
|
189
|
-
const userAddress = yield* select(walletAddressSelector)
|
|
190
|
-
if (!userAddress) {
|
|
191
|
-
throw new Error('Wallet address not set')
|
|
192
|
-
}
|
|
193
|
-
const secureSendPossibleAddresses = [...walletAddresses]
|
|
194
|
-
const secureSendPhoneNumberMapping = yield* select(secureSendPhoneNumberMappingSelector)
|
|
195
|
-
// If fetch is being done as part of a payment request from an unverified address,
|
|
196
|
-
// the unverified address should be considered in the Secure Send check
|
|
197
|
-
if (requesterAddress && !secureSendPossibleAddresses.includes(requesterAddress)) {
|
|
198
|
-
secureSendPossibleAddresses.push(requesterAddress)
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
const addressValidationType = checkIfValidationRequired(
|
|
202
|
-
oldAddresses,
|
|
203
|
-
secureSendPossibleAddresses,
|
|
204
|
-
userAddress,
|
|
205
|
-
secureSendPhoneNumberMapping,
|
|
206
|
-
e164Number
|
|
207
|
-
)
|
|
208
|
-
if (addressValidationType !== AddressValidationType.NONE) {
|
|
209
|
-
yield* put(requireSecureSend(e164Number, addressValidationType))
|
|
210
|
-
}
|
|
211
172
|
yield* put(
|
|
212
173
|
updateE164PhoneNumberAddresses(
|
|
213
174
|
e164NumberToAddressUpdates,
|
|
@@ -215,13 +176,11 @@ export function* fetchAddressesAndValidateSaga({
|
|
|
215
176
|
addressToVerifiedByUpdates
|
|
216
177
|
)
|
|
217
178
|
)
|
|
218
|
-
yield* put(endFetchingAddresses(e164Number, true))
|
|
219
179
|
AppAnalytics.track(IdentityEvents.phone_number_lookup_complete)
|
|
220
180
|
} catch (err) {
|
|
221
181
|
const error = ensureError(err)
|
|
222
182
|
Logger.debug(TAG + '@fetchAddressesAndValidate', `Error fetching addresses`, error)
|
|
223
183
|
yield* put(showErrorOrFallback(error, ErrorMessages.ADDRESS_LOOKUP_FAILURE))
|
|
224
|
-
yield* put(endFetchingAddresses(e164Number, false))
|
|
225
184
|
AppAnalytics.track(IdentityEvents.phone_number_lookup_error, {
|
|
226
185
|
error: error.message,
|
|
227
186
|
})
|
|
@@ -340,51 +299,6 @@ function* fetchAddressVerification(address: string) {
|
|
|
340
299
|
}
|
|
341
300
|
}
|
|
342
301
|
|
|
343
|
-
// Only use with multiple addresses if user has
|
|
344
|
-
// gone through SecureSend
|
|
345
|
-
export function getAddressFromPhoneNumber(
|
|
346
|
-
e164Number: string,
|
|
347
|
-
e164NumberToAddress: E164NumberToAddressType,
|
|
348
|
-
secureSendPhoneNumberMapping: SecureSendPhoneNumberMapping,
|
|
349
|
-
requesterAddress?: string
|
|
350
|
-
): string | null | undefined {
|
|
351
|
-
const addresses = e164NumberToAddress[e164Number]
|
|
352
|
-
|
|
353
|
-
// If there are no verified addresses for the number,
|
|
354
|
-
// use the requester's given address
|
|
355
|
-
if (!addresses && requesterAddress) {
|
|
356
|
-
return requesterAddress
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
// If address is null (unverified) or undefined (in the process
|
|
360
|
-
// of being updated) then just return that falsy value
|
|
361
|
-
if (!addresses) {
|
|
362
|
-
return addresses
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
// If there are multiple addresses, need to determine which to use
|
|
366
|
-
if (addresses.length > 1) {
|
|
367
|
-
// Check if the user has gone through Secure Send and validated a
|
|
368
|
-
// recipient address
|
|
369
|
-
const validatedAddress = secureSendPhoneNumberMapping[e164Number]
|
|
370
|
-
? secureSendPhoneNumberMapping[e164Number].address
|
|
371
|
-
: undefined
|
|
372
|
-
|
|
373
|
-
// If they have not, they shouldn't have been able to
|
|
374
|
-
// get to this point
|
|
375
|
-
if (!validatedAddress) {
|
|
376
|
-
throw new Error(
|
|
377
|
-
'Multiple addresses but none were validated. Should have routed through Secure Send.'
|
|
378
|
-
)
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
return validatedAddress
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
// Normal case when there is only one address in the mapping
|
|
385
|
-
return addresses[0]
|
|
386
|
-
}
|
|
387
|
-
|
|
388
302
|
export function* saveContacts() {
|
|
389
303
|
try {
|
|
390
304
|
const saveContactsGate = getFeatureGate(StatsigFeatureGates.SAVE_CONTACTS)
|
package/src/identity/reducer.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import dotProp from 'dot-prop-immutable'
|
|
2
1
|
import { RehydrateAction } from 'redux-persist'
|
|
3
2
|
import { Actions as AccountActions, ClearStoredAccountAction } from 'src/account/actions'
|
|
4
3
|
import { ActionTypes, Actions } from 'src/identity/actions'
|
|
@@ -32,24 +31,6 @@ export interface ImportContactProgress {
|
|
|
32
31
|
total: number
|
|
33
32
|
}
|
|
34
33
|
|
|
35
|
-
export enum AddressValidationType {
|
|
36
|
-
FULL = 'full',
|
|
37
|
-
PARTIAL = 'partial',
|
|
38
|
-
NONE = 'none',
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export interface SecureSendPhoneNumberMapping {
|
|
42
|
-
[e164Number: string]: SecureSendDetails
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export interface SecureSendDetails {
|
|
46
|
-
address?: string
|
|
47
|
-
addressValidationType: AddressValidationType
|
|
48
|
-
isFetchingAddresses?: boolean
|
|
49
|
-
lastFetchSuccessful?: boolean
|
|
50
|
-
validationSuccessful?: boolean
|
|
51
|
-
}
|
|
52
|
-
|
|
53
34
|
export interface AddressToVerificationStatus {
|
|
54
35
|
[address: string]: boolean | undefined
|
|
55
36
|
}
|
|
@@ -67,8 +48,6 @@ interface State {
|
|
|
67
48
|
// Has the user already been asked for contacts permission
|
|
68
49
|
askedContactsPermission: boolean
|
|
69
50
|
importContactsProgress: ImportContactProgress
|
|
70
|
-
// Contacts found during the matchmaking process
|
|
71
|
-
secureSendPhoneNumberMapping: SecureSendPhoneNumberMapping
|
|
72
51
|
// Mapping of address to verification status; undefined entries represent a loading state
|
|
73
52
|
addressToVerificationStatus: AddressToVerificationStatus
|
|
74
53
|
// Mapping of address to the entity that verified it (e.g. "valora", "minipay")
|
|
@@ -87,7 +66,6 @@ const initialState: State = {
|
|
|
87
66
|
current: 0,
|
|
88
67
|
total: 0,
|
|
89
68
|
},
|
|
90
|
-
secureSendPhoneNumberMapping: {},
|
|
91
69
|
addressToVerificationStatus: {},
|
|
92
70
|
addressToVerifiedBy: {},
|
|
93
71
|
lastSavedContactsHash: null,
|
|
@@ -159,66 +137,11 @@ export const reducer = (
|
|
|
159
137
|
status: success ? ImportContactsStatus.Done : ImportContactsStatus.Failed,
|
|
160
138
|
},
|
|
161
139
|
}
|
|
162
|
-
case Actions.VALIDATE_RECIPIENT_ADDRESS_SUCCESS:
|
|
163
|
-
return {
|
|
164
|
-
...state,
|
|
165
|
-
// Overwrite the previous mapping when a new address is validated
|
|
166
|
-
secureSendPhoneNumberMapping: dotProp.set(
|
|
167
|
-
state.secureSendPhoneNumberMapping,
|
|
168
|
-
`${action.e164Number}`,
|
|
169
|
-
{
|
|
170
|
-
address: action.validatedAddress,
|
|
171
|
-
addressValidationType: AddressValidationType.NONE,
|
|
172
|
-
validationSuccessful: true,
|
|
173
|
-
}
|
|
174
|
-
),
|
|
175
|
-
}
|
|
176
|
-
case Actions.VALIDATE_RECIPIENT_ADDRESS_RESET:
|
|
177
|
-
return {
|
|
178
|
-
...state,
|
|
179
|
-
secureSendPhoneNumberMapping: dotProp.set(
|
|
180
|
-
state.secureSendPhoneNumberMapping,
|
|
181
|
-
`${action.e164Number}.validationSuccessful`,
|
|
182
|
-
false
|
|
183
|
-
),
|
|
184
|
-
}
|
|
185
|
-
case Actions.REQUIRE_SECURE_SEND:
|
|
186
|
-
return {
|
|
187
|
-
...state,
|
|
188
|
-
// Erase the previous mapping when new validation is required
|
|
189
|
-
secureSendPhoneNumberMapping: dotProp.set(
|
|
190
|
-
state.secureSendPhoneNumberMapping,
|
|
191
|
-
`${action.e164Number}`,
|
|
192
|
-
{
|
|
193
|
-
address: undefined,
|
|
194
|
-
addressValidationType: action.addressValidationType,
|
|
195
|
-
}
|
|
196
|
-
),
|
|
197
|
-
}
|
|
198
|
-
case Actions.FETCH_ADDRESSES_AND_VALIDATION_STATUS:
|
|
199
|
-
return {
|
|
200
|
-
...state,
|
|
201
|
-
secureSendPhoneNumberMapping: dotProp.set(
|
|
202
|
-
state.secureSendPhoneNumberMapping,
|
|
203
|
-
`${action.e164Number}.isFetchingAddresses`,
|
|
204
|
-
true
|
|
205
|
-
),
|
|
206
|
-
}
|
|
207
|
-
case Actions.END_FETCHING_ADDRESSES:
|
|
208
|
-
return {
|
|
209
|
-
...state,
|
|
210
|
-
secureSendPhoneNumberMapping: dotProp.merge(
|
|
211
|
-
state.secureSendPhoneNumberMapping,
|
|
212
|
-
`${action.e164Number}`,
|
|
213
|
-
{ isFetchingAddresses: false, lastFetchSuccessful: action.lastFetchSuccessful }
|
|
214
|
-
),
|
|
215
|
-
}
|
|
216
140
|
case AccountActions.CLEAR_STORED_ACCOUNT:
|
|
217
141
|
return {
|
|
218
142
|
...initialState,
|
|
219
143
|
addressToE164Number: state.addressToE164Number,
|
|
220
144
|
e164NumberToAddress: state.e164NumberToAddress,
|
|
221
|
-
secureSendPhoneNumberMapping: state.secureSendPhoneNumberMapping,
|
|
222
145
|
}
|
|
223
146
|
case Actions.FETCH_ADDRESS_VERIFICATION_STATUS:
|
|
224
147
|
// If the current status is false or does not exist, we set it to undefined
|