wallet-stack 1.0.0-alpha.136 → 1.0.0-alpha.137
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 +1 -0
- package/package.json +1 -1
- package/src/components/ReviewTransaction.test.tsx +26 -0
- package/src/components/ReviewTransaction.tsx +28 -7
- package/src/recipients/verifier.ts +5 -3
- package/src/send/SendConfirmation.test.tsx +23 -2
- package/src/send/SendConfirmation.tsx +1 -4
|
@@ -2174,6 +2174,7 @@
|
|
|
2174
2174
|
"recipient": "Recipient",
|
|
2175
2175
|
"explanation": "<0>{{name}}</0> has more than one wallet linked to the phone number. Choose which one to send to."
|
|
2176
2176
|
},
|
|
2177
|
+
"unverifiedAddress": "Unverified",
|
|
2177
2178
|
"sendSelectRecipient": {
|
|
2178
2179
|
"searchText": "Search by name, phone, wallet...",
|
|
2179
2180
|
"searchInputLabel": "To",
|
package/package.json
CHANGED
|
@@ -172,6 +172,32 @@ describe('ReviewSummaryItemContact', () => {
|
|
|
172
172
|
expect(subtitle).toHaveTextContent('MiniPay', { exact: false })
|
|
173
173
|
})
|
|
174
174
|
|
|
175
|
+
it('shows the unverified warning in the subtitle for phone recipients with a known-unverified address', () => {
|
|
176
|
+
const address = '0x0123456789012345678901234567890123456789'
|
|
177
|
+
const recipient = {
|
|
178
|
+
name: 'John Doe',
|
|
179
|
+
e164PhoneNumber: '+222222222',
|
|
180
|
+
address,
|
|
181
|
+
} as Recipient
|
|
182
|
+
const tree = renderContact(recipient, {
|
|
183
|
+
identity: { addressToVerifiedBy: { [address]: null } },
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
const subtitle = tree.getByTestId('ContactItem/SecondaryValue')
|
|
187
|
+
expect(subtitle).toHaveTextContent('0x0123...6789', { exact: false })
|
|
188
|
+
expect(subtitle).toHaveTextContent('unverifiedAddress', { exact: false })
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
it('omits the unverified warning for address-only recipients (the address is already the primary value)', () => {
|
|
192
|
+
const address = '0x0123456789012345678901234567890123456789'
|
|
193
|
+
const recipient = { address } as Recipient
|
|
194
|
+
const tree = renderContact(recipient, {
|
|
195
|
+
identity: { addressToVerifiedBy: { [address]: null } },
|
|
196
|
+
})
|
|
197
|
+
|
|
198
|
+
expect(tree.queryByTestId('ContactItem/SecondaryValue')).toBeNull()
|
|
199
|
+
})
|
|
200
|
+
|
|
175
201
|
it('logs an error if no name/phone/address exist', () => {
|
|
176
202
|
const recipient = {} as Recipient
|
|
177
203
|
const tree = renderContact(recipient)
|
|
@@ -11,6 +11,7 @@ import CustomHeader from 'src/components/header/CustomHeader'
|
|
|
11
11
|
import SkeletonPlaceholder from 'src/components/SkeletonPlaceholder'
|
|
12
12
|
import { formatValueToDisplay } from 'src/components/TokenDisplay'
|
|
13
13
|
import Touchable from 'src/components/Touchable'
|
|
14
|
+
import AttentionIcon from 'src/icons/Attention'
|
|
14
15
|
import InfoIcon from 'src/icons/InfoIcon'
|
|
15
16
|
import WalletIcon from 'src/icons/navigator/Wallet'
|
|
16
17
|
import PhoneIcon from 'src/icons/Phone'
|
|
@@ -126,17 +127,31 @@ export function ReviewSummaryItem(props: {
|
|
|
126
127
|
|
|
127
128
|
function renderAddressAndVerifier(
|
|
128
129
|
shortAddress: string | undefined,
|
|
129
|
-
verifierName: string | undefined
|
|
130
|
+
verifierName: string | null | undefined
|
|
130
131
|
): ReactNode {
|
|
131
|
-
if (!shortAddress &&
|
|
132
|
+
if (!shortAddress && verifierName === undefined) return undefined
|
|
133
|
+
const isUnverified = verifierName === null
|
|
132
134
|
return (
|
|
133
135
|
<>
|
|
134
|
-
{!!shortAddress &&
|
|
135
|
-
|
|
136
|
+
{!!shortAddress && (
|
|
137
|
+
<Text style={[styles.reviewSummaryItemSecondaryValue, isUnverified && styles.warningText]}>
|
|
138
|
+
{shortAddress}
|
|
139
|
+
</Text>
|
|
140
|
+
)}
|
|
141
|
+
{isUnverified ? (
|
|
136
142
|
<>
|
|
137
|
-
<
|
|
138
|
-
<Text style={styles.reviewSummaryItemSecondaryValue}>
|
|
143
|
+
<AttentionIcon size={14} color={colors.warningPrimary} />
|
|
144
|
+
<Text style={[styles.reviewSummaryItemSecondaryValue, styles.warningText]}>
|
|
145
|
+
<Trans i18nKey="unverifiedAddress" />
|
|
146
|
+
</Text>
|
|
139
147
|
</>
|
|
148
|
+
) : (
|
|
149
|
+
!!verifierName && (
|
|
150
|
+
<>
|
|
151
|
+
<VerifiedBadge color={colors.contentSecondary} />
|
|
152
|
+
<Text style={styles.reviewSummaryItemSecondaryValue}>{verifierName}</Text>
|
|
153
|
+
</>
|
|
154
|
+
)
|
|
140
155
|
)}
|
|
141
156
|
</>
|
|
142
157
|
)
|
|
@@ -155,6 +170,7 @@ export function ReviewSummaryItemContact({
|
|
|
155
170
|
const phone = recipient.displayNumber || recipient.e164PhoneNumber
|
|
156
171
|
// For recipients with a phone mapping, surface the resolved on-chain address (and verifier,
|
|
157
172
|
// if known) as a subtitle so the user can verify the actual destination they are signing.
|
|
173
|
+
// When the address is known to be unverified, swap the verified badge for a warning.
|
|
158
174
|
const shortAddress = recipient.address ? formatShortenedAddress(recipient.address) : undefined
|
|
159
175
|
const phoneSubtitle = renderAddressAndVerifier(shortAddress, verifierName)
|
|
160
176
|
|
|
@@ -169,7 +185,9 @@ export function ReviewSummaryItemContact({
|
|
|
169
185
|
if (recipient.address) {
|
|
170
186
|
return {
|
|
171
187
|
title: recipient.address,
|
|
172
|
-
|
|
188
|
+
// For plain wallet recipients, suppress the unverified warning
|
|
189
|
+
// by collapsing `null` to `undefined`.
|
|
190
|
+
subtitle: renderAddressAndVerifier(undefined, verifierName ?? undefined),
|
|
173
191
|
icon: WalletIcon,
|
|
174
192
|
}
|
|
175
193
|
}
|
|
@@ -513,6 +531,9 @@ const styles = StyleSheet.create({
|
|
|
513
531
|
...typeScale.bodySmall,
|
|
514
532
|
color: colors.contentSecondary,
|
|
515
533
|
},
|
|
534
|
+
warningText: {
|
|
535
|
+
color: colors.warningPrimary,
|
|
536
|
+
},
|
|
516
537
|
reviewSummaryItemSecondaryValueWrapper: {
|
|
517
538
|
flexDirection: 'row',
|
|
518
539
|
gap: Spacing.Smallest8,
|
|
@@ -13,8 +13,10 @@ export function isKnownVerifier(verifier: string | null | undefined): verifier i
|
|
|
13
13
|
return !!verifier && Object.hasOwn(VERIFIERS, verifier)
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
export function useVerifierName(address: string | undefined): string | undefined {
|
|
16
|
+
export function useVerifierName(address: string | undefined): string | null | undefined {
|
|
17
17
|
const addressToVerifiedBy = useSelector(addressToVerifiedBySelector)
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
if (!address) return undefined
|
|
19
|
+
const verifier = addressToVerifiedBy[address.toLowerCase()]
|
|
20
|
+
if (isKnownVerifier(verifier)) return VERIFIERS[verifier].name
|
|
21
|
+
return verifier === null ? null : undefined
|
|
20
22
|
}
|
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
mockCusdTokenBalance,
|
|
24
24
|
mockCusdTokenId,
|
|
25
25
|
mockPoofTokenId,
|
|
26
|
+
mockRecipient,
|
|
26
27
|
mockTokenBalances,
|
|
27
28
|
mockTokenTransactionData,
|
|
28
29
|
} from 'test/values'
|
|
@@ -174,7 +175,27 @@ describe('SendConfirmation', () => {
|
|
|
174
175
|
it('shows the unknown address warning when the recipient address is not a known app user', () => {
|
|
175
176
|
const { getByTestId } = renderScreen(mockSendConfirmationProps, {
|
|
176
177
|
identity: {
|
|
177
|
-
addressToVerifiedBy: { [mockAccount]: null },
|
|
178
|
+
addressToVerifiedBy: { [mockAccount.toLowerCase()]: null },
|
|
179
|
+
},
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
expect(getByTestId('UnknownAddressInfo')).toBeTruthy()
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
it('shows the unknown address warning for phone recipients whose resolved address is known-unverified', () => {
|
|
186
|
+
const phoneRecipientProps = getMockStackScreenProps(Screens.SendConfirmation, {
|
|
187
|
+
...mockBaseScreenProps,
|
|
188
|
+
transactionData: {
|
|
189
|
+
...mockTokenTransactionData,
|
|
190
|
+
recipient: { ...mockRecipient, address: mockAccount },
|
|
191
|
+
},
|
|
192
|
+
prepareTransactionsResult: getSerializablePreparedTransactionsPossible(
|
|
193
|
+
mockPrepareTransactionsResultPossible
|
|
194
|
+
),
|
|
195
|
+
})
|
|
196
|
+
const { getByTestId } = renderScreen(phoneRecipientProps, {
|
|
197
|
+
identity: {
|
|
198
|
+
addressToVerifiedBy: { [mockAccount.toLowerCase()]: null },
|
|
178
199
|
},
|
|
179
200
|
})
|
|
180
201
|
|
|
@@ -184,7 +205,7 @@ describe('SendConfirmation', () => {
|
|
|
184
205
|
it('does not show the unknown address warning when the recipient address is verified', () => {
|
|
185
206
|
const { queryByTestId } = renderScreen(mockSendConfirmationProps, {
|
|
186
207
|
identity: {
|
|
187
|
-
addressToVerifiedBy: { [mockAccount]: 'valora' },
|
|
208
|
+
addressToVerifiedBy: { [mockAccount.toLowerCase()]: 'valora' },
|
|
188
209
|
},
|
|
189
210
|
})
|
|
190
211
|
|
|
@@ -30,7 +30,6 @@ import { getLocalCurrencyCode, getLocalCurrencySymbol } from 'src/localCurrency/
|
|
|
30
30
|
import { noHeader } from 'src/navigator/Headers'
|
|
31
31
|
import { Screens } from 'src/navigator/Screens'
|
|
32
32
|
import { StackParamList } from 'src/navigator/types'
|
|
33
|
-
import { RecipientType } from 'src/recipients/recipient'
|
|
34
33
|
import { useDispatch, useSelector } from 'src/redux/hooks'
|
|
35
34
|
import { sendPayment } from 'src/send/actions'
|
|
36
35
|
import { isSendingSelector } from 'src/send/selectors'
|
|
@@ -93,9 +92,7 @@ export default function SendConfirmation({ route: { params } }: Props) {
|
|
|
93
92
|
const walletAddress = useSelector(walletAddressSelector)
|
|
94
93
|
const addressToVerifiedBy = useSelector(addressToVerifiedBySelector)
|
|
95
94
|
const showUnknownAddressInfo =
|
|
96
|
-
recipient.
|
|
97
|
-
!!recipient.address &&
|
|
98
|
-
addressToVerifiedBy[recipient.address] === null
|
|
95
|
+
!!recipient.address && addressToVerifiedBy[recipient.address.toLowerCase()] === null
|
|
99
96
|
|
|
100
97
|
const feeCurrencies = useSelector((state) => feeCurrenciesSelector(state, tokenInfo!.networkId))
|
|
101
98
|
const {
|