wallet-stack 1.0.0-alpha.131 → 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.
Files changed (59) hide show
  1. package/locales/base/translation.json +11 -0
  2. package/package.json +2 -3
  3. package/src/analytics/Events.tsx +3 -10
  4. package/src/analytics/Properties.tsx +9 -25
  5. package/src/analytics/docs.ts +11 -8
  6. package/src/app/ErrorMessages.ts +1 -7
  7. package/src/identity/actions.ts +1 -97
  8. package/src/identity/contactMapping.test.ts +3 -28
  9. package/src/identity/contactMapping.ts +2 -88
  10. package/src/identity/reducer.ts +0 -77
  11. package/src/identity/saga.ts +2 -85
  12. package/src/identity/selectors.ts +0 -2
  13. package/src/images/Images.ts +3 -0
  14. package/src/images/assets/invite-modal.png +0 -0
  15. package/src/images/assets/invite-modal@1.5x.png +0 -0
  16. package/src/images/assets/invite-modal@2x.png +0 -0
  17. package/src/images/assets/invite-modal@3x.png +0 -0
  18. package/src/images/assets/invite-modal@4x.png +0 -0
  19. package/src/images/assets/minipay.png +0 -0
  20. package/src/images/assets/minipay@1.5x.png +0 -0
  21. package/src/images/assets/minipay@2x.png +0 -0
  22. package/src/images/assets/minipay@3x.png +0 -0
  23. package/src/images/assets/minipay@4x.png +0 -0
  24. package/src/images/assets/valora.png +0 -0
  25. package/src/images/assets/valora@1.5x.png +0 -0
  26. package/src/images/assets/valora@2x.png +0 -0
  27. package/src/images/assets/valora@3x.png +0 -0
  28. package/src/images/assets/valora@4x.png +0 -0
  29. package/src/index.d.ts +0 -1
  30. package/src/navigator/Navigator.tsx +10 -14
  31. package/src/navigator/Screens.tsx +2 -2
  32. package/src/navigator/types.tsx +5 -6
  33. package/src/qrcode/utils.test.tsx +4 -96
  34. package/src/qrcode/utils.ts +5 -114
  35. package/src/redux/migrations.test.ts +13 -0
  36. package/src/redux/migrations.ts +4 -0
  37. package/src/redux/store.test.ts +1 -2
  38. package/src/redux/store.ts +1 -1
  39. package/src/send/SelectRecipientAddress.test.tsx +146 -0
  40. package/src/send/SelectRecipientAddress.tsx +166 -0
  41. package/src/send/SendConfirmation.test.tsx +28 -0
  42. package/src/send/SendConfirmation.tsx +18 -1
  43. package/src/send/SendInvite.test.tsx +107 -0
  44. package/src/send/SendInvite.tsx +99 -0
  45. package/src/send/SendSelectRecipient.test.tsx +44 -223
  46. package/src/send/SendSelectRecipient.tsx +41 -149
  47. package/src/send/actions.ts +0 -26
  48. package/src/send/saga.ts +1 -6
  49. package/src/components/AccountNumberCard.tsx +0 -23
  50. package/src/components/ErrorMessageInline.tsx +0 -78
  51. package/src/components/SingleDigitInput.tsx +0 -53
  52. package/src/icons/HamburgerCard.tsx +0 -55
  53. package/src/identity/saga.test.ts +0 -103
  54. package/src/identity/secureSend.ts +0 -171
  55. package/src/send/ValidateRecipientAccount.test.tsx +0 -182
  56. package/src/send/ValidateRecipientAccount.tsx +0 -392
  57. package/src/send/ValidateRecipientIntro.test.tsx +0 -61
  58. package/src/send/ValidateRecipientIntro.tsx +0 -136
  59. package/src/send/__snapshots__/ValidateRecipientAccount.test.tsx.snap +0 -777
@@ -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
@@ -1,94 +1,16 @@
1
- import { showErrorInline } from 'src/alert/actions'
2
- import { SendEvents } from 'src/analytics/Events'
3
- import AppAnalytics from 'src/analytics/AppAnalytics'
4
- import { ErrorMessages } from 'src/app/ErrorMessages'
5
- import {
6
- Actions,
7
- ValidateRecipientAddressAction,
8
- validateRecipientAddressSuccess,
9
- } from 'src/identity/actions'
10
1
  import {
11
2
  doImportContactsWrapper,
12
3
  fetchAddressVerificationSaga,
13
4
  fetchAddressesAndValidateSaga,
14
5
  saveContacts,
15
6
  } from 'src/identity/contactMapping'
16
- import { AddressValidationType } from 'src/identity/reducer'
17
- import { validateAndReturnMatch } from 'src/identity/secureSend'
18
- import { e164NumberToAddressSelector } from 'src/identity/selectors'
19
- import { recipientHasNumber } from 'src/recipients/recipient'
7
+ import { Actions } from 'src/identity/actions'
20
8
  import Logger from 'src/utils/Logger'
21
- import { ensureError } from 'src/utils/ensureError'
22
9
  import { safely } from 'src/utils/safely'
23
- import { currentAccountSelector } from 'src/web3/selectors'
24
- import { cancelled, put, select, spawn, takeEvery, takeLatest, takeLeading } from 'typed-redux-saga'
10
+ import { cancelled, spawn, takeEvery, takeLatest, takeLeading } from 'typed-redux-saga'
25
11
 
26
12
  const TAG = 'identity/saga'
27
13
 
28
- export function* validateRecipientAddressSaga({
29
- userInputOfFullAddressOrLastFourDigits,
30
- addressValidationType,
31
- recipient,
32
- requesterAddress,
33
- }: ValidateRecipientAddressAction) {
34
- Logger.debug(TAG, 'Starting Recipient Address Validation')
35
- try {
36
- if (!recipientHasNumber(recipient)) {
37
- throw Error(`Invalid recipient type for Secure Send, does not have e164Number`)
38
- }
39
-
40
- const userAddress = yield* select(currentAccountSelector)
41
- if (!userAddress) {
42
- // This should never happen
43
- throw Error(`No userAddress set`)
44
- }
45
- const e164NumberToAddress = yield* select(e164NumberToAddressSelector)
46
- const { e164PhoneNumber } = recipient
47
- const possibleRecievingAddresses = e164NumberToAddress[e164PhoneNumber]
48
-
49
- // Should never happen - Secure Send is initiated to deal with
50
- // there being several possible addresses
51
- if (!possibleRecievingAddresses) {
52
- throw Error('There are no possible recipient addresses to validate against')
53
- }
54
-
55
- // E164NumberToAddress in redux store only holds verified addresses
56
- // Need to add the requester address to the option set in the event
57
- // a request is coming from an unverified account
58
- if (requesterAddress && !possibleRecievingAddresses.includes(requesterAddress)) {
59
- possibleRecievingAddresses.push(requesterAddress)
60
- }
61
-
62
- const validatedAddress = validateAndReturnMatch(
63
- userInputOfFullAddressOrLastFourDigits,
64
- possibleRecievingAddresses,
65
- userAddress,
66
- addressValidationType
67
- )
68
-
69
- AppAnalytics.track(SendEvents.send_secure_complete, {
70
- confirmByScan: false,
71
- partialAddressValidation: addressValidationType === AddressValidationType.PARTIAL,
72
- })
73
-
74
- yield* put(validateRecipientAddressSuccess(e164PhoneNumber, validatedAddress))
75
- } catch (err) {
76
- const error = ensureError(err)
77
- AppAnalytics.track(SendEvents.send_secure_incorrect, {
78
- confirmByScan: false,
79
- partialAddressValidation: addressValidationType === AddressValidationType.PARTIAL,
80
- error: error.message,
81
- })
82
-
83
- Logger.error(TAG, 'validateRecipientAddressSaga/Address validation error: ', error)
84
- if (Object.values(ErrorMessages).includes(error.message as ErrorMessages)) {
85
- yield* put(showErrorInline(error.message as ErrorMessages))
86
- } else {
87
- yield* put(showErrorInline(ErrorMessages.ADDRESS_VALIDATION_ERROR))
88
- }
89
- }
90
- }
91
-
92
14
  function* watchContactMapping() {
93
15
  yield* takeLeading(Actions.IMPORT_CONTACTS, safely(doImportContactsWrapper))
94
16
  yield* takeLatest(
@@ -97,10 +19,6 @@ function* watchContactMapping() {
97
19
  )
98
20
  }
99
21
 
100
- export function* watchValidateRecipientAddress() {
101
- yield* takeLatest(Actions.VALIDATE_RECIPIENT_ADDRESS, safely(validateRecipientAddressSaga))
102
- }
103
-
104
22
  function* watchFetchAddressVerification() {
105
23
  yield* takeEvery(Actions.FETCH_ADDRESS_VERIFICATION_STATUS, safely(fetchAddressVerificationSaga))
106
24
  }
@@ -109,7 +27,6 @@ export function* identitySaga() {
109
27
  Logger.debug(TAG, 'Initializing identity sagas')
110
28
  try {
111
29
  yield* spawn(watchContactMapping)
112
- yield* spawn(watchValidateRecipientAddress)
113
30
  yield* spawn(watchFetchAddressVerification)
114
31
  yield* spawn(saveContacts) // save contacts on app start
115
32
  } catch (error) {
@@ -5,8 +5,6 @@ export const addressToVerificationStatusSelector = (state: RootState) =>
5
5
  state.identity.addressToVerificationStatus
6
6
  export const addressToE164NumberSelector = (state: RootState) => state.identity.addressToE164Number
7
7
  export const addressToVerifiedBySelector = (state: RootState) => state.identity.addressToVerifiedBy
8
- export const secureSendPhoneNumberMappingSelector = (state: RootState) =>
9
- state.identity.secureSendPhoneNumberMapping
10
8
  export const importContactsProgressSelector = (state: RootState) =>
11
9
  state.identity.importContactsProgress
12
10
  export const addressToDisplayNameSelector = (state: RootState) =>
@@ -14,8 +14,11 @@ export const celoEducation4 = require('src/images/assets/celo-education-4.png')
14
14
  export const email = require('src/images/assets/email.png')
15
15
  export const fiatExchange = require('src/images/assets/fiat-exchange.png')
16
16
  export const getVerified = require('src/images/assets/get-verified.png')
17
+ export const inviteModal = require('src/images/assets/invite-modal.png')
17
18
  export const learnCelo = require('src/images/assets/learn-celo.png')
19
+ export const miniPay = require('src/images/assets/minipay.png')
18
20
  export const pointsCardBackground = require('src/images/assets/points-card-background.png')
19
21
  export const pointsIllustration = require('src/images/assets/points-illustration.png')
22
+ export const valora = require('src/images/assets/valora.png')
20
23
  export const walletSafe = require('src/images/assets/wallet-safe.png')
21
24
  export const earnCardBackground = require('src/images/assets/earn-card-background.png')
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
package/src/index.d.ts CHANGED
@@ -6,7 +6,6 @@ declare module '*.json' {
6
6
  declare module '*.png'
7
7
  declare module '*.jpg'
8
8
 
9
- declare module 'dot-prop-immutable'
10
9
  declare module 'svgs'
11
10
  declare module 'react-native-languages'
12
11
  declare module 'react-native-version-check'
@@ -102,15 +102,11 @@ import PointsIntro from 'src/points/PointsIntro'
102
102
  import { NavigatorScreen } from 'src/public/navigate'
103
103
  import { RootState } from 'src/redux/reducers'
104
104
  import { store } from 'src/redux/store'
105
+ import SelectRecipientAddress from 'src/send/SelectRecipientAddress'
105
106
  import SendConfirmation, { sendConfirmationScreenNavOptions } from 'src/send/SendConfirmation'
106
107
  import SendEnterAmount from 'src/send/SendEnterAmount'
108
+ import SendInvite from 'src/send/SendInvite'
107
109
  import SendSelectRecipient from 'src/send/SendSelectRecipient'
108
- import ValidateRecipientAccount, {
109
- validateRecipientAccountScreenNavOptions,
110
- } from 'src/send/ValidateRecipientAccount'
111
- import ValidateRecipientIntro, {
112
- validateRecipientIntroScreenNavOptions,
113
- } from 'src/send/ValidateRecipientIntro'
114
110
  import { getFeatureGate } from 'src/statsig'
115
111
  import { StatsigFeatureGates } from 'src/statsig/types'
116
112
  import styles from 'src/styles/styles'
@@ -242,20 +238,20 @@ const sendScreens = (Navigator: typeof Stack) => (
242
238
  options={sendConfirmationScreenNavOptions as NativeStackNavigationOptions}
243
239
  />
244
240
  <Navigator.Screen
245
- name={Screens.ValidateRecipientIntro}
246
- component={ValidateRecipientIntro}
247
- options={validateRecipientIntroScreenNavOptions}
248
- />
249
- <Navigator.Screen
250
- name={Screens.ValidateRecipientAccount}
251
- component={ValidateRecipientAccount}
252
- options={validateRecipientAccountScreenNavOptions}
241
+ name={Screens.SelectRecipientAddress}
242
+ component={SelectRecipientAddress}
243
+ options={SelectRecipientAddress.navigationOptions as NativeStackNavigationOptions}
253
244
  />
254
245
  <Navigator.Screen
255
246
  name={Screens.SendEnterAmount}
256
247
  component={SendEnterAmount}
257
248
  options={noHeader}
258
249
  />
250
+ <Navigator.Screen
251
+ name={Screens.SendInvite}
252
+ component={SendInvite}
253
+ options={SendInvite.navigationOptions}
254
+ />
259
255
  </>
260
256
  )
261
257
 
@@ -75,6 +75,8 @@ export enum Screens {
75
75
  SelectCountry = 'SelectCountry',
76
76
  SelectLocalCurrency = 'SelectLocalCurrency',
77
77
  SelectProvider = 'SelectProvider',
78
+ SendInvite = 'SendInvite',
79
+ SelectRecipientAddress = 'SelectRecipientAddress',
78
80
  SendSelectRecipient = 'SendSelectRecipient',
79
81
  SendConfirmation = 'SendConfirmation',
80
82
  SendEnterAmount = 'SendEnterAmount',
@@ -94,8 +96,6 @@ export enum Screens {
94
96
  TokenImport = 'TokenImport',
95
97
  TransactionDetailsScreen = 'TransactionDetailsScreen',
96
98
  UpgradeScreen = 'UpgradeScreen',
97
- ValidateRecipientAccount = 'ValidateRecipientAccount',
98
- ValidateRecipientIntro = 'ValidateRecipientIntro',
99
99
  VerificationCodeInputScreen = 'VerificationCodeInputScreen',
100
100
  VerificationStartScreen = 'VerificationStartScreen',
101
101
  WalletConnectRequest = 'WalletConnectRequest',
@@ -9,7 +9,7 @@ import { KeylessBackupFlow, KeylessBackupOrigin } from 'src/keylessBackup/types'
9
9
  import { Screens } from 'src/navigator/Screens'
10
10
  import { Nft } from 'src/nfts/types'
11
11
  import { EarnPosition } from 'src/positions/types'
12
- import { Recipient } from 'src/recipients/recipient'
12
+ import { MobileRecipient, Recipient } from 'src/recipients/recipient'
13
13
  import { QrCode, TransactionDataInput } from 'src/send/types'
14
14
  import type { SwapTransaction } from 'src/swap/types'
15
15
  import type { SerializedTokenBalance } from 'src/tokens/slice'
@@ -45,10 +45,9 @@ type SendEnterAmountParams = {
45
45
  isMiniPayRecipient?: boolean
46
46
  }
47
47
 
48
- interface ValidateRecipientParams {
49
- requesterAddress?: string
48
+ interface SelectRecipientAddressParams {
49
+ recipient: MobileRecipient
50
50
  origin: SendOrigin
51
- recipient: Recipient
52
51
  forceTokenId?: boolean
53
52
  defaultTokenIdOverride?: string
54
53
  }
@@ -261,6 +260,8 @@ export type StackParamList = {
261
260
  fiat: number
262
261
  }
263
262
  }
263
+ [Screens.SendInvite]: { recipient: Recipient; shareUrl: string }
264
+ [Screens.SelectRecipientAddress]: SelectRecipientAddressParams
264
265
  [Screens.SendSelectRecipient]:
265
266
  | {
266
267
  forceTokenId?: boolean
@@ -300,8 +301,6 @@ export type StackParamList = {
300
301
  transaction: TokenTransaction
301
302
  }
302
303
  [Screens.UpgradeScreen]: undefined
303
- [Screens.ValidateRecipientIntro]: ValidateRecipientParams
304
- [Screens.ValidateRecipientAccount]: ValidateRecipientParams
305
304
  [Screens.VerificationStartScreen]:
306
305
  | {
307
306
  hasOnboarded?: boolean
@@ -3,45 +3,32 @@ import * as React from 'react'
3
3
  import 'react-native'
4
4
  import { View } from 'react-native'
5
5
  import { expectSaga } from 'redux-saga-test-plan'
6
- import { call, select } from 'redux-saga-test-plan/matchers'
6
+ import { select } from 'redux-saga-test-plan/matchers'
7
7
  import { showError } from 'src/alert/actions'
8
8
  import AppAnalytics from 'src/analytics/AppAnalytics'
9
9
  import { QrScreenEvents } from 'src/analytics/Events'
10
10
  import { HooksEnablePreviewOrigin, SendOrigin } from 'src/analytics/types'
11
11
  import { ErrorMessages } from 'src/app/ErrorMessages'
12
12
  import { DEEP_LINK_URL_SCHEME } from 'src/config'
13
- import {
14
- e164NumberToAddressSelector,
15
- secureSendPhoneNumberMappingSelector,
16
- } from 'src/identity/selectors'
13
+ import { e164NumberToAddressSelector } from 'src/identity/selectors'
17
14
  import { navigate } from 'src/navigator/NavigationService'
18
15
  import { Screens } from 'src/navigator/Screens'
19
16
  import { handleEnableHooksPreviewDeepLink } from 'src/positions/saga'
20
17
  import { allowHooksPreviewSelector } from 'src/positions/selectors'
21
18
  import { urlFromUriData } from 'src/qrcode/schema'
22
- import {
23
- QRCodeTypes,
24
- handleQRCodeDefault,
25
- handleQRCodeSecureSend,
26
- handleSecureSend,
27
- useQRContent,
28
- } from 'src/qrcode/utils'
19
+ import { QRCodeTypes, handleQRCodeDefault, useQRContent } from 'src/qrcode/utils'
29
20
  import { RecipientType } from 'src/recipients/recipient'
30
21
  import { recipientInfoSelector } from 'src/recipients/reducer'
31
- import { handleQRCodeDetected, handleQRCodeDetectedSecureSend } from 'src/send/actions'
22
+ import { handleQRCodeDetected } from 'src/send/actions'
32
23
  import { QrCode } from 'src/send/types'
33
24
  import { createMockStore } from 'test/utils'
34
25
  import {
35
26
  mockAccount,
36
- mockAccount2,
37
27
  mockAccount3,
38
28
  mockE164Number,
39
29
  mockE164Number3,
40
- mockE164NumberToAddress,
41
- mockEthTokenId,
42
30
  mockName,
43
31
  mockQrCodeData,
44
- mockRecipient,
45
32
  mockRecipientInfo,
46
33
  } from 'test/values'
47
34
 
@@ -212,82 +199,3 @@ describe('handleQRCodeDefault', () => {
212
199
  expect(AppAnalytics.track).toHaveBeenCalledWith(QrScreenEvents.qr_scanned, qrCode)
213
200
  })
214
201
  })
215
-
216
- describe('handleQRCodeSecureSend', () => {
217
- it('handles a valid address and navigates to send enter amount when there is no transaction data', async () => {
218
- const data: QrCode = { type: QRCodeTypes.QR_CODE, data: mockAccount }
219
- await expectSaga(
220
- handleQRCodeSecureSend,
221
- handleQRCodeDetectedSecureSend(data, mockRecipient, mockAccount2, false, mockEthTokenId)
222
- )
223
- .provide([
224
- [select(e164NumberToAddressSelector), mockE164NumberToAddress],
225
- [
226
- select(secureSendPhoneNumberMappingSelector),
227
- {
228
- [mockRecipient.e164PhoneNumber]: {
229
- address: mockAccount,
230
- addressValidationType: undefined,
231
- },
232
- },
233
- ],
234
- [
235
- call(
236
- handleSecureSend,
237
- mockAccount.toLowerCase(),
238
- mockE164NumberToAddress,
239
- mockRecipient,
240
- mockAccount2
241
- ),
242
- true,
243
- ],
244
- ])
245
- .run()
246
- expect(navigate).toHaveBeenCalledWith(Screens.SendEnterAmount, {
247
- origin: SendOrigin.AppSendFlow,
248
- recipient: {
249
- ...mockRecipient,
250
- address: mockAccount,
251
- },
252
- isFromScan: true,
253
- forceTokenId: false,
254
- defaultTokenIdOverride: mockEthTokenId,
255
- })
256
- expect(AppAnalytics.track).toHaveBeenCalledWith(QrScreenEvents.qr_scanned, data)
257
- })
258
- it('handles an invalid address', async () => {
259
- const data: QrCode = { type: QRCodeTypes.QR_CODE, data: 'invalid-address' }
260
- await expectSaga(
261
- handleQRCodeSecureSend,
262
- handleQRCodeDetectedSecureSend(data, mockRecipient, mockAccount2)
263
- )
264
- .provide([[select(e164NumberToAddressSelector), mockE164NumberToAddress]])
265
- .put(showError(ErrorMessages.QR_FAILED_INVALID_ADDRESS))
266
- .run()
267
- expect(navigate).not.toHaveBeenCalled()
268
- expect(AppAnalytics.track).toHaveBeenCalledWith(QrScreenEvents.qr_scanned, data)
269
- })
270
- it('handles failed address lookup', async () => {
271
- const data: QrCode = { type: QRCodeTypes.QR_CODE, data: mockAccount }
272
- await expectSaga(
273
- handleQRCodeSecureSend,
274
- handleQRCodeDetectedSecureSend(data, mockRecipient, mockAccount2)
275
- )
276
- .provide([
277
- [select(e164NumberToAddressSelector), mockE164NumberToAddress],
278
- [
279
- call(
280
- handleSecureSend,
281
- mockAccount.toLowerCase(),
282
- mockE164NumberToAddress,
283
- mockRecipient,
284
- mockAccount2
285
- ),
286
- false,
287
- ],
288
- ])
289
- .run()
290
- expect(navigate).not.toHaveBeenCalled()
291
- expect(AppAnalytics.track).toHaveBeenCalledWith(QrScreenEvents.qr_scanned, data)
292
- })
293
- })
@@ -1,40 +1,18 @@
1
1
  import * as RNFS from '@valora/react-native-fs'
2
2
  import { useMemo } from 'react'
3
3
  import Share from 'react-native-share'
4
- import { showError, showMessage } from 'src/alert/actions'
4
+ import { showError } from 'src/alert/actions'
5
5
  import AppAnalytics from 'src/analytics/AppAnalytics'
6
- import { QrScreenEvents, SendEvents } from 'src/analytics/Events'
7
- import {
8
- HooksEnablePreviewOrigin,
9
- SendOrigin,
10
- WalletConnectPairingOrigin,
11
- } from 'src/analytics/types'
6
+ import { QrScreenEvents } from 'src/analytics/Events'
7
+ import { HooksEnablePreviewOrigin, WalletConnectPairingOrigin } from 'src/analytics/types'
12
8
  import { ErrorMessages } from 'src/app/ErrorMessages'
13
9
  import { DEEP_LINK_URL_SCHEME } from 'src/config'
14
- import { validateRecipientAddressSuccess } from 'src/identity/actions'
15
- import { E164NumberToAddressType } from 'src/identity/reducer'
16
- import { getSecureSendAddress } from 'src/identity/secureSend'
17
- import {
18
- e164NumberToAddressSelector,
19
- secureSendPhoneNumberMappingSelector,
20
- } from 'src/identity/selectors'
21
- import { navigate } from 'src/navigator/NavigationService'
22
- import { Screens } from 'src/navigator/Screens'
23
10
  import { handleEnableHooksPreviewDeepLink } from 'src/positions/saga'
24
11
  import { allowHooksPreviewSelector } from 'src/positions/selectors'
25
12
  import { UriData, uriDataFromUrl } from 'src/qrcode/schema'
26
- import {
27
- Recipient,
28
- RecipientInfo,
29
- getRecipientFromAddress,
30
- recipientHasNumber,
31
- } from 'src/recipients/recipient'
13
+ import { RecipientInfo, getRecipientFromAddress } from 'src/recipients/recipient'
32
14
  import { recipientInfoSelector } from 'src/recipients/reducer'
33
- import {
34
- HandleQRCodeDetectedAction,
35
- HandleQRCodeDetectedSecureSendAction,
36
- SVG,
37
- } from 'src/send/actions'
15
+ import { HandleQRCodeDetectedAction, SVG } from 'src/send/actions'
38
16
  import { QrCode } from 'src/send/types'
39
17
  import { handleSendPaymentData } from 'src/send/utils'
40
18
  import Logger from 'src/utils/Logger'
@@ -85,48 +63,6 @@ export async function shareSVGImage(svg: SVG) {
85
63
  })
86
64
  }
87
65
 
88
- export function* handleSecureSend(
89
- address: string,
90
- e164NumberToAddress: E164NumberToAddressType,
91
- recipient: Recipient,
92
- requesterAddress?: string
93
- ) {
94
- if (!recipientHasNumber(recipient)) {
95
- throw Error('Invalid recipient type for Secure Send, has no mobile number')
96
- }
97
-
98
- const userScannedAddress = address.toLowerCase()
99
- const { e164PhoneNumber } = recipient
100
- const possibleReceivingAddresses = e164NumberToAddress[e164PhoneNumber]
101
- // This should never happen. Secure Send is triggered when there are
102
- // multiple addresses for a given phone number
103
- if (!possibleReceivingAddresses) {
104
- throw Error("No addresses associated with recipient's phone number")
105
- }
106
-
107
- // Need to add the requester address to the option set in the event
108
- // a request is coming from an unverified account
109
- if (requesterAddress && !possibleReceivingAddresses.includes(requesterAddress)) {
110
- possibleReceivingAddresses.push(requesterAddress)
111
- }
112
- const possibleReceivingAddressesFormatted = possibleReceivingAddresses.map((addr) =>
113
- addr.toLowerCase()
114
- )
115
- if (!possibleReceivingAddressesFormatted.includes(userScannedAddress)) {
116
- const error = ErrorMessages.QR_FAILED_INVALID_RECIPIENT
117
- AppAnalytics.track(SendEvents.send_secure_incorrect, {
118
- confirmByScan: true,
119
- error,
120
- })
121
- yield* put(showMessage(error))
122
- return false
123
- }
124
-
125
- AppAnalytics.track(SendEvents.send_secure_complete, { confirmByScan: true })
126
- yield* put(validateRecipientAddressSuccess(e164PhoneNumber, userScannedAddress))
127
- return true
128
- }
129
-
130
66
  function* extractQRAddressData(qrCode: QrCode) {
131
67
  // strip network prefix if present
132
68
  const qrAddress = qrCode.data.split(':').at(-1) || qrCode.data
@@ -183,48 +119,3 @@ export function* handleQRCodeDefault({
183
119
  defaultTokenIdOverride,
184
120
  })
185
121
  }
186
-
187
- export function* handleQRCodeSecureSend({
188
- qrCode,
189
- requesterAddress,
190
- recipient,
191
- forceTokenId,
192
- defaultTokenIdOverride,
193
- }: HandleQRCodeDetectedSecureSendAction) {
194
- const e164NumberToAddress = yield* select(e164NumberToAddressSelector)
195
- AppAnalytics.track(QrScreenEvents.qr_scanned, qrCode)
196
-
197
- const qrData = yield* call(extractQRAddressData, qrCode)
198
- if (!qrData) {
199
- return
200
- }
201
-
202
- const success: boolean = yield* call(
203
- handleSecureSend,
204
- qrData.address,
205
- e164NumberToAddress,
206
- recipient,
207
- requesterAddress
208
- )
209
- if (!success) {
210
- return
211
- }
212
-
213
- const secureSendPhoneNumberMapping = yield* select(secureSendPhoneNumberMappingSelector)
214
- const address = getSecureSendAddress(recipient, secureSendPhoneNumberMapping)
215
- if (!address) {
216
- // should never happen b/c if handleSecureSend succeeds then address should be there
217
- Logger.error(TAG, `No secure send address found for recipient ${recipient}`)
218
- return
219
- }
220
- navigate(Screens.SendEnterAmount, {
221
- origin: SendOrigin.AppSendFlow,
222
- recipient: {
223
- ...recipient,
224
- address,
225
- },
226
- isFromScan: true,
227
- forceTokenId,
228
- defaultTokenIdOverride,
229
- })
230
- }