wallet-stack 1.0.0-alpha.132 → 1.0.0-alpha.134

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 (64) hide show
  1. package/locales/base/translation.json +5 -0
  2. package/package.json +1 -2
  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 +0 -7
  7. package/src/components/ReviewTransaction.test.tsx +49 -8
  8. package/src/components/ReviewTransaction.tsx +58 -12
  9. package/src/icons/VerifiedBadge.tsx +27 -0
  10. package/src/identity/actions.ts +1 -114
  11. package/src/identity/contactMapping.test.ts +80 -46
  12. package/src/identity/contactMapping.ts +46 -102
  13. package/src/identity/reducer.ts +7 -98
  14. package/src/identity/saga.ts +2 -85
  15. package/src/identity/selectors.ts +0 -4
  16. package/src/images/Images.ts +2 -0
  17. package/src/images/assets/minipay.png +0 -0
  18. package/src/images/assets/minipay@1.5x.png +0 -0
  19. package/src/images/assets/minipay@2x.png +0 -0
  20. package/src/images/assets/minipay@3x.png +0 -0
  21. package/src/images/assets/minipay@4x.png +0 -0
  22. package/src/images/assets/valora.png +0 -0
  23. package/src/images/assets/valora@1.5x.png +0 -0
  24. package/src/images/assets/valora@2x.png +0 -0
  25. package/src/images/assets/valora@3x.png +0 -0
  26. package/src/images/assets/valora@4x.png +0 -0
  27. package/src/index.d.ts +0 -1
  28. package/src/navigator/Navigator.tsx +4 -14
  29. package/src/navigator/Screens.tsx +1 -2
  30. package/src/navigator/types.tsx +4 -6
  31. package/src/qrcode/utils.test.tsx +4 -96
  32. package/src/qrcode/utils.ts +5 -114
  33. package/src/recipients/RecipientItemV2.test.tsx +11 -72
  34. package/src/recipients/RecipientItemV2.tsx +1 -34
  35. package/src/recipients/recipient.test.ts +6 -5
  36. package/src/recipients/recipient.ts +7 -12
  37. package/src/recipients/verifier.ts +20 -0
  38. package/src/redux/migrations.test.ts +38 -0
  39. package/src/redux/migrations.ts +25 -0
  40. package/src/redux/store.test.ts +1 -3
  41. package/src/redux/store.ts +1 -1
  42. package/src/send/SelectRecipientAddress.test.tsx +146 -0
  43. package/src/send/SelectRecipientAddress.tsx +164 -0
  44. package/src/send/SendConfirmation.test.tsx +3 -3
  45. package/src/send/SendConfirmation.tsx +3 -3
  46. package/src/send/SendSelectRecipient.test.tsx +53 -138
  47. package/src/send/SendSelectRecipient.tsx +12 -27
  48. package/src/send/actions.ts +0 -26
  49. package/src/send/saga.ts +1 -6
  50. package/src/send/useFetchRecipientVerificationStatus.ts +6 -11
  51. package/src/transactions/UserSection.tsx +37 -11
  52. package/src/transactions/feed/TransactionDetailsScreen.test.tsx +6 -6
  53. package/src/utils/phoneNumbers.ts +0 -11
  54. package/src/components/AccountNumberCard.tsx +0 -23
  55. package/src/components/ErrorMessageInline.tsx +0 -78
  56. package/src/components/SingleDigitInput.tsx +0 -53
  57. package/src/icons/HamburgerCard.tsx +0 -55
  58. package/src/identity/saga.test.ts +0 -103
  59. package/src/identity/secureSend.ts +0 -171
  60. package/src/send/ValidateRecipientAccount.test.tsx +0 -182
  61. package/src/send/ValidateRecipientAccount.tsx +0 -392
  62. package/src/send/ValidateRecipientIntro.test.tsx +0 -61
  63. package/src/send/ValidateRecipientIntro.tsx +0 -136
  64. 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.132",
3
+ "version": "1.0.0-alpha.134",
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",
@@ -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/recipients/verifier'
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 {
@@ -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`,
@@ -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',
@@ -76,18 +76,27 @@ describe('ReviewSummaryItem', () => {
76
76
  })
77
77
 
78
78
  describe('ReviewSummaryItemContact', () => {
79
- it('displays name + phone if recipient has a name and phone number', () => {
79
+ const renderContact = (recipient: Recipient, storeOverrides: Record<string, unknown> = {}) =>
80
+ render(
81
+ <Provider store={createMockStore(storeOverrides)}>
82
+ <ReviewSummaryItemContact recipient={recipient} testID="ContactItem" />
83
+ </Provider>
84
+ )
85
+
86
+ it('shows name as primary value and resolved short address as subtitle for phone recipients', () => {
80
87
  const recipient = {
81
88
  name: 'John Doe',
82
89
  displayNumber: '+111111111',
83
90
  e164PhoneNumber: '+222222222',
91
+ address: '0x0123456789012345678901234567890123456789',
84
92
  } as Recipient
85
- const tree = render(<ReviewSummaryItemContact recipient={recipient} testID="ContactItem" />)
93
+ const tree = renderContact(recipient)
86
94
 
87
95
  expect(tree.getByTestId('ContactItem/PrimaryValue')).toHaveTextContent('John Doe', {
88
96
  exact: false,
89
97
  })
90
- expect(tree.getByTestId('ContactItem/SecondaryValue')).toHaveTextContent('+111111111', {
98
+ // Phone recipients always surface the on-chain destination on the review screen.
99
+ expect(tree.getByTestId('ContactItem/SecondaryValue')).toHaveTextContent('0x0123...6789', {
91
100
  exact: false,
92
101
  })
93
102
  })
@@ -109,14 +118,17 @@ describe('ReviewSummaryItemContact', () => {
109
118
  ])(
110
119
  'displays only $phoneNumberType phone if name is not available',
111
120
  ({ displayNumber, e164PhoneNumber, expectedDisplayedValue }) => {
112
- const recipient = { displayNumber, e164PhoneNumber } as Recipient
113
- const tree = render(<ReviewSummaryItemContact recipient={recipient} testID="ContactItem" />)
121
+ const address = '0x0123456789012345678901234567890123456789'
122
+ const recipient = { displayNumber, e164PhoneNumber, address } as Recipient
123
+ const tree = renderContact(recipient)
114
124
 
115
125
  expect(tree.getByTestId('ContactItem/PrimaryValue')).toHaveTextContent(
116
126
  expectedDisplayedValue,
117
127
  { exact: false }
118
128
  )
119
- expect(tree.queryByTestId('ContactItem/SecondaryValue')).toBeNull()
129
+ expect(tree.getByTestId('ContactItem/SecondaryValue')).toHaveTextContent('0x0123...6789', {
130
+ exact: false,
131
+ })
120
132
  }
121
133
  )
122
134
 
@@ -124,16 +136,45 @@ describe('ReviewSummaryItemContact', () => {
124
136
  const recipient = {
125
137
  address: '0x123456789',
126
138
  } as Recipient
127
- const tree = render(<ReviewSummaryItemContact recipient={recipient} testID="ContactItem" />)
139
+ const tree = renderContact(recipient)
128
140
 
129
141
  expect(tree.getByTestId('ContactItem/PrimaryValue')).toHaveTextContent('0x123456789', {
130
142
  exact: false,
131
143
  })
132
144
  })
133
145
 
146
+ it('inlines the verifier with the short address for phone recipients', () => {
147
+ const address = '0x0123456789012345678901234567890123456789'
148
+ const recipient = {
149
+ name: 'John Doe',
150
+ displayNumber: '+111111111',
151
+ e164PhoneNumber: '+222222222',
152
+ address,
153
+ } as Recipient
154
+ const tree = renderContact(recipient, {
155
+ identity: { addressToVerifiedBy: { [address]: 'valora' } },
156
+ })
157
+
158
+ const subtitle = tree.getByTestId('ContactItem/SecondaryValue')
159
+ expect(subtitle).toHaveTextContent('0x0123...6789', { exact: false })
160
+ expect(subtitle).toHaveTextContent('Valora', { exact: false })
161
+ })
162
+
163
+ it('inlines just the verifier for address-only recipients with a known verifier', () => {
164
+ const address = '0x0123456789012345678901234567890123456789'
165
+ const recipient = { address } as Recipient
166
+ const tree = renderContact(recipient, {
167
+ identity: { addressToVerifiedBy: { [address]: 'minipay' } },
168
+ })
169
+
170
+ const subtitle = tree.getByTestId('ContactItem/SecondaryValue')
171
+ // No address in the subtitle — it's already in the primary slot for address-only recipients
172
+ expect(subtitle).toHaveTextContent('MiniPay', { exact: false })
173
+ })
174
+
134
175
  it('logs an error if no name/phone/address exist', () => {
135
176
  const recipient = {} as Recipient
136
- const tree = render(<ReviewSummaryItemContact recipient={recipient} testID="ContactItem" />)
177
+ const tree = renderContact(recipient)
137
178
  expect(Logger.error).toHaveBeenCalledTimes(1)
138
179
  expect(tree.toJSON()).toBeNull()
139
180
  })
@@ -4,6 +4,7 @@ import React, { useMemo, type ReactNode } from 'react'
4
4
  import { Trans, useTranslation } from 'react-i18next'
5
5
  import { ScrollView, StyleSheet, Text, View, type StyleProp, type TextStyle } from 'react-native'
6
6
  import { SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context'
7
+ import { formatShortenedAddress } from 'src/account/utils'
7
8
  import BackButton from 'src/components/BackButton'
8
9
  import ContactCircle from 'src/components/ContactCircle'
9
10
  import CustomHeader from 'src/components/header/CustomHeader'
@@ -14,8 +15,10 @@ import InfoIcon from 'src/icons/InfoIcon'
14
15
  import WalletIcon from 'src/icons/navigator/Wallet'
15
16
  import PhoneIcon from 'src/icons/Phone'
16
17
  import UserIcon from 'src/icons/User'
18
+ import VerifiedBadge from 'src/icons/VerifiedBadge'
17
19
  import { LocalCurrencySymbol } from 'src/localCurrency/consts'
18
- import { getDisplayDetail, type Recipient } from 'src/recipients/recipient'
20
+ import { type Recipient } from 'src/recipients/recipient'
21
+ import { useVerifierName } from 'src/recipients/verifier'
19
22
  import colors, { type ColorValue } from 'src/styles/colors'
20
23
  import { typeScale } from 'src/styles/fonts'
21
24
  import { Spacing } from 'src/styles/styles'
@@ -70,7 +73,7 @@ export function ReviewSummaryItem(props: {
70
73
  label: string
71
74
  icon: ReactNode
72
75
  primaryValue: string
73
- secondaryValue?: string
76
+ secondaryValue?: ReactNode
74
77
  testID?: string
75
78
  onPress?: () => void
76
79
  }) {
@@ -96,12 +99,21 @@ export function ReviewSummaryItem(props: {
96
99
 
97
100
  {!!props.secondaryValue && (
98
101
  <View style={styles.reviewSummaryItemSecondaryValueWrapper}>
99
- <Text
100
- style={styles.reviewSummaryItemSecondaryValue}
101
- testID={`${props.testID}/SecondaryValue`}
102
- >
103
- {props.secondaryValue}
104
- </Text>
102
+ {typeof props.secondaryValue === 'string' ? (
103
+ <Text
104
+ style={styles.reviewSummaryItemSecondaryValue}
105
+ testID={`${props.testID}/SecondaryValue`}
106
+ >
107
+ {props.secondaryValue}
108
+ </Text>
109
+ ) : (
110
+ <View
111
+ style={styles.reviewSummaryItemSecondaryValueContent}
112
+ testID={`${props.testID}/SecondaryValue`}
113
+ >
114
+ {props.secondaryValue}
115
+ </View>
116
+ )}
105
117
  {!!props.onPress && <InfoIcon size={14} color={colors.contentSecondary} />}
106
118
  </View>
107
119
  )}
@@ -112,6 +124,24 @@ export function ReviewSummaryItem(props: {
112
124
  )
113
125
  }
114
126
 
127
+ function renderAddressAndVerifier(
128
+ shortAddress: string | undefined,
129
+ verifierName: string | undefined
130
+ ): ReactNode {
131
+ if (!shortAddress && !verifierName) return undefined
132
+ return (
133
+ <>
134
+ {!!shortAddress && <Text style={styles.reviewSummaryItemSecondaryValue}>{shortAddress}</Text>}
135
+ {!!verifierName && (
136
+ <>
137
+ <VerifiedBadge color={colors.contentSecondary} />
138
+ <Text style={styles.reviewSummaryItemSecondaryValue}>{verifierName}</Text>
139
+ </>
140
+ )}
141
+ </>
142
+ )
143
+ }
144
+
115
145
  export function ReviewSummaryItemContact({
116
146
  testID,
117
147
  recipient,
@@ -120,20 +150,30 @@ export function ReviewSummaryItemContact({
120
150
  recipient: Recipient
121
151
  }) {
122
152
  const { t } = useTranslation()
153
+ const verifierName = useVerifierName(recipient.address)
123
154
  const contact = useMemo(() => {
124
155
  const phone = recipient.displayNumber || recipient.e164PhoneNumber
156
+ // For recipients with a phone mapping, surface the resolved on-chain address (and verifier,
157
+ // if known) as a subtitle so the user can verify the actual destination they are signing.
158
+ const shortAddress = recipient.address ? formatShortenedAddress(recipient.address) : undefined
159
+ const phoneSubtitle = renderAddressAndVerifier(shortAddress, verifierName)
160
+
125
161
  if (recipient.name) {
126
- return { title: recipient.name, subtitle: getDisplayDetail(recipient), icon: UserIcon }
162
+ return { title: recipient.name, subtitle: phoneSubtitle, icon: UserIcon }
127
163
  }
128
164
 
129
165
  if (phone) {
130
- return { title: phone, icon: PhoneIcon }
166
+ return { title: phone, subtitle: phoneSubtitle, icon: PhoneIcon }
131
167
  }
132
168
 
133
169
  if (recipient.address) {
134
- return { title: recipient.address, icon: WalletIcon }
170
+ return {
171
+ title: recipient.address,
172
+ subtitle: renderAddressAndVerifier(undefined, verifierName),
173
+ icon: WalletIcon,
174
+ }
135
175
  }
136
- }, [recipient])
176
+ }, [recipient, verifierName])
137
177
 
138
178
  // This should never happen
139
179
  if (!contact) {
@@ -478,6 +518,12 @@ const styles = StyleSheet.create({
478
518
  gap: Spacing.Smallest8,
479
519
  alignItems: 'center',
480
520
  },
521
+ reviewSummaryItemSecondaryValueContent: {
522
+ flexDirection: 'row',
523
+ gap: Spacing.Tiny4,
524
+ alignItems: 'center',
525
+ flexShrink: 1,
526
+ },
481
527
  reviewDetails: {
482
528
  gap: Spacing.Regular16,
483
529
  width: '100%',
@@ -0,0 +1,27 @@
1
+ import * as React from 'react'
2
+ import Svg, { Path } from 'react-native-svg'
3
+ import colors, { ColorValue } from 'src/styles/colors'
4
+
5
+ interface Props {
6
+ size?: number
7
+ color?: ColorValue
8
+ testID?: string
9
+ }
10
+
11
+ function VerifiedBadge({ size = 14, color = colors.contentSecondary, testID }: Props) {
12
+ return (
13
+ <Svg width={size} height={size} viewBox="0 0 22 22" fill="none" testID={testID}>
14
+ <Path
15
+ d="M20.396 11c-.018-.646-.215-1.275-.57-1.816-.354-.54-.852-.972-1.438-1.246.223-.607.27-1.264.14-1.897-.131-.634-.437-1.218-.882-1.687-.47-.445-1.053-.75-1.687-.882-.633-.13-1.29-.083-1.897.14-.273-.587-.704-1.086-1.245-1.44S11.647 1.62 11 1.604c-.646.017-1.273.213-1.813.568s-.969.854-1.24 1.44c-.608-.223-1.267-.272-1.902-.14-.635.13-1.22.436-1.69.882-.445.47-.749 1.055-.878 1.688-.13.633-.08 1.29.144 1.896-.587.274-1.087.705-1.443 1.245-.356.54-.555 1.17-.574 1.817.02.647.218 1.276.574 1.817.356.54.856.972 1.443 1.245-.224.606-.274 1.263-.144 1.896.13.634.433 1.218.877 1.688.47.443 1.054.747 1.687.878.633.132 1.29.084 1.897-.138.274.586.705 1.084 1.246 1.439.54.354 1.17.551 1.816.569.647-.016 1.276-.213 1.817-.567s.972-.854 1.245-1.44c.604.239 1.266.296 1.903.164.636-.132 1.22-.447 1.68-.907.46-.46.776-1.044.908-1.681s.075-1.299-.165-1.903c.586-.274 1.084-.705 1.439-1.246.354-.54.551-1.17.569-1.816Z"
16
+ stroke={color}
17
+ strokeWidth="1.2"
18
+ />
19
+ <Path
20
+ d="M9.662 14.85 6.233 11.42l1.293-1.302 2.072 2.072 4.4-4.794 1.347 1.246-5.683 6.208Z"
21
+ fill={color}
22
+ />
23
+ </Svg>
24
+ )
25
+ }
26
+
27
+ export default React.memo(VerifiedBadge)
@@ -2,28 +2,19 @@ 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
- ADDRESS_VERIFICATION_STATUS_RECEIVED = 'IDENTITY/ADDRESS_VERIFICATION_STATUS_RECEIVED',
27
18
  CONTACTS_SAVED = 'IDENTITY/CONTACTS_SAVED',
28
19
  STORED_PASSWORD_REFRESHED = 'IDENTITY/STORED_PASSWORD_REFRESHED',
29
20
  }
@@ -43,13 +34,6 @@ export interface UpdateKnownAddressesAction {
43
34
  export interface FetchAddressesAndValidateAction {
44
35
  type: Actions.FETCH_ADDRESSES_AND_VALIDATION_STATUS
45
36
  e164Number: string
46
- requesterAddress?: string
47
- }
48
-
49
- export interface EndFetchingAddressesAction {
50
- type: Actions.END_FETCHING_ADDRESSES
51
- e164Number: string
52
- lastFetchSuccessful: boolean
53
37
  }
54
38
 
55
39
  export interface ImportContactsAction {
@@ -68,42 +52,11 @@ export interface EndImportContactsAction {
68
52
  success: boolean
69
53
  }
70
54
 
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
55
  export interface FetchAddressVerificationAction {
97
56
  type: Actions.FETCH_ADDRESS_VERIFICATION_STATUS
98
57
  address: string
99
58
  }
100
59
 
101
- export interface AddressVerificationStatusReceivedAction {
102
- type: Actions.ADDRESS_VERIFICATION_STATUS_RECEIVED
103
- address: string
104
- addressVerified: boolean
105
- }
106
-
107
60
  interface ContactsSavedAction {
108
61
  type: Actions.CONTACTS_SAVED
109
62
  hash: string
@@ -119,33 +72,14 @@ export type ActionTypes =
119
72
  | ImportContactsAction
120
73
  | UpdateImportContactProgress
121
74
  | EndImportContactsAction
122
- | ValidateRecipientAddressAction
123
- | ValidateRecipientAddressSuccessAction
124
- | ValidateRecipientAddressResetAction
125
- | RequireSecureSendAction
126
75
  | FetchAddressesAndValidateAction
127
- | EndFetchingAddressesAction
128
76
  | FetchAddressVerificationAction
129
- | AddressVerificationStatusReceivedAction
130
77
  | ContactsSavedAction
131
78
  | StoredPasswordRefreshedAction
132
79
 
133
- export const fetchAddressesAndValidate = (
134
- e164Number: string,
135
- requesterAddress?: string
136
- ): FetchAddressesAndValidateAction => ({
80
+ export const fetchAddressesAndValidate = (e164Number: string): FetchAddressesAndValidateAction => ({
137
81
  type: Actions.FETCH_ADDRESSES_AND_VALIDATION_STATUS,
138
82
  e164Number,
139
- requesterAddress,
140
- })
141
-
142
- export const addressVerificationStatusReceived = (
143
- address: string,
144
- addressVerified: boolean
145
- ): AddressVerificationStatusReceivedAction => ({
146
- type: Actions.ADDRESS_VERIFICATION_STATUS_RECEIVED,
147
- address,
148
- addressVerified,
149
83
  })
150
84
 
151
85
  export const fetchAddressVerification = (address: string): FetchAddressVerificationAction => ({
@@ -153,15 +87,6 @@ export const fetchAddressVerification = (address: string): FetchAddressVerificat
153
87
  address,
154
88
  })
155
89
 
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
90
  export const updateE164PhoneNumberAddresses = (
166
91
  e164NumberToAddress: E164NumberToAddressType,
167
92
  addressToE164Number: AddressToE164NumberType,
@@ -200,44 +125,6 @@ export const endImportContacts = (success: boolean): EndImportContactsAction =>
200
125
  success,
201
126
  })
202
127
 
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
128
  export const contactsSaved = (hash: string): ContactsSavedAction => ({
242
129
  type: Actions.CONTACTS_SAVED,
243
130
  hash,