Skip to content

Commit 89c9e0d

Browse files
feat: add new hex address equivalence for mainnet profiles (#8717)
* add new hex address equivalence for mainnet profiles * update styles and add HexAddressBox component * fix test * add to address history * add copy button --------- Co-authored-by: Begoña Álvarez de la Cruz <[email protected]>
1 parent 7ab27c3 commit 89c9e0d

File tree

11 files changed

+195
-17
lines changed

11 files changed

+195
-17
lines changed

packages/desktop/components/popups/AddressHistoryPopup.svelte

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,18 @@
66
import { fetchWithTimeout } from '@core/nfts'
77
import { checkActiveProfileAuth, getActiveProfile, updateAccountPersistedDataOnActiveProfile } from '@core/profile'
88
import { getProfileManager } from '@core/profile-manager/stores'
9-
import { setClipboard, truncateString } from '@core/utils'
9+
import {
10+
setClipboard,
11+
truncateString,
12+
isValidBech32AddressAndPrefix,
13+
BECH32_DEFAULT_HRP,
14+
convertBech32ToHex,
15+
} from '@core/utils'
1016
import { AccountAddress } from '@iota/sdk/out/types'
1117
import VirtualList from '@sveltejs/svelte-virtual-list'
12-
import { Button, FontWeight, KeyValueBox, Spinner, Text, TextType } from 'shared/components'
18+
import { Button, ButtonSize, FontWeight, KeyValueBox, Spinner, Text, TextType } from 'shared/components'
1319
import { onMount } from 'svelte'
20+
import { HexAddressBox } from '@ui'
1421
1522
interface AddressHistory {
1623
address: string
@@ -42,6 +49,13 @@
4249
setClipboard(addresses)
4350
}
4451
52+
function onCopyAllHexAdressesClick(): void {
53+
const hexList = knownAddresses
54+
.map((address) => convertBech32ToHex(address.address, BECH32_DEFAULT_HRP))
55+
.join(',')
56+
setClipboard(hexList)
57+
}
58+
4559
onMount(() => {
4660
knownAddresses = $selectedAccount?.knownAddresses
4761
if (!knownAddresses?.length) {
@@ -146,7 +160,7 @@
146160
{#if knownAddresses.length > 0}
147161
<div class="w-full flex-col space-y-2 virtual-list-wrapper">
148162
<VirtualList items={knownAddresses} let:item>
149-
<div class="mb-1">
163+
<div class="flex flex-col space-y-1">
150164
<KeyValueBox
151165
isCopyable
152166
classes="flex items-center w-full py-4"
@@ -161,6 +175,11 @@
161175
backgroundColor="gray-50"
162176
darkBackgroundColor="gray-900"
163177
/>
178+
179+
{#if isValidBech32AddressAndPrefix(item.address, BECH32_DEFAULT_HRP)}
180+
<HexAddressBox address={item.address} isCopyable clearBackground clearBorder />
181+
<hr class="border-gray-300 dark:border-gray-700 py-2" />
182+
{/if}
164183
</div>
165184
</VirtualList>
166185
</div>
@@ -174,13 +193,18 @@
174193
{/if}
175194
</div>
176195
<div class="flex flex-row flex-nowrap w-full space-x-4 mt-6">
177-
<div class="flex w-full justify-center pt-8 space-x-4">
178-
<Button outline classes="w-1/2" onClick={onCopyClick}>{localize('actions.copy')}</Button>
196+
<div class="flex flex-col w-full justify-center pt-3 space-y-2">
197+
<div class="flex w-full justify-center space-x-4">
198+
<Button outline classes="w-1/2" onClick={onCopyClick} size={ButtonSize.Small}>Copy Addresses</Button>
199+
<Button outline classes="w-1/2" onClick={onCopyAllHexAdressesClick} size={ButtonSize.Small}
200+
>Copy Hex Addresses</Button
201+
>
202+
</div>
179203
<Button
180-
classes="w-1/2"
181204
onClick={handleSearchClick}
182205
disabled={isBusy}
183206
{isBusy}
207+
size={ButtonSize.Medium}
184208
busyMessage={localize('actions.searching')}>{localize('actions.search')}</Button
185209
>
186210
</div>
@@ -199,4 +223,7 @@
199223
.virtual-list-wrapper :global(svelte-virtual-list-contents) {
200224
margin-right: -1rem !important;
201225
}
226+
.virtual-list-wrapper :global(svelte-virtual-list-row:last-of-type hr) {
227+
display: none !important;
228+
}
202229
</style>
Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,28 @@
11
<script lang="ts">
2-
import { QR, Text, FontWeight, AddressBox } from '@ui'
2+
import { QR, Text, FontWeight, AddressBox, HexAddressBox } from '@ui'
33
import { localize } from '@core/i18n'
44
import { selectedAccount } from '@core/account'
5+
import { isValidBech32AddressAndPrefix, BECH32_DEFAULT_HRP } from '@core/utils'
56
67
export let title: string = localize('general.receiveFunds')
78
9+
let hasHexAddressToShow = false
10+
811
$: receiveAddress = $selectedAccount.depositAddress
12+
$: if (isValidBech32AddressAndPrefix(receiveAddress, BECH32_DEFAULT_HRP)) {
13+
hasHexAddressToShow = true
14+
}
915
</script>
1016

1117
<receive-details class="w-full h-full space-y-6 flex flex-auto flex-col shrink-0">
1218
<Text type="h3" fontWeight={FontWeight.semibold} classes="text-left">{title}</Text>
1319
<div class="flex w-full flex-col items-center space-y-6">
1420
<QR data={receiveAddress} />
1521
<AddressBox address={receiveAddress} clearBackground isCopyable />
22+
{#if hasHexAddressToShow}
23+
<div class="w-3/4">
24+
<HexAddressBox address={receiveAddress} isCopyable />
25+
</div>
26+
{/if}
1627
</div>
1728
</receive-details>

packages/desktop/views/dashboard/wallet/Wallet.svelte

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
<script lang="ts">
22
import { AssetList, Overflow, Pane, ReceiveAddressButton } from '@ui'
33
import { AccountSummary, AccountActivity, SendButton } from '@components'
4+
import { isValidBech32AddressAndPrefix, BECH32_DEFAULT_HRP } from '@core/utils'
45
import { selectedAccountAssets } from '@core/wallet'
56
import { selectedAccount } from '@core/account/stores'
67
import features from '@features/features'
8+
import { HexAddressBox } from 'shared/components'
9+
10+
let hasHexAddressToShow = false
11+
$: if (isValidBech32AddressAndPrefix($selectedAccount?.depositAddress, BECH32_DEFAULT_HRP)) {
12+
hasHexAddressToShow = true
13+
}
714
</script>
815

916
{#if $selectedAccount}
@@ -20,10 +27,15 @@
2027
{/if}
2128
</Pane>
2229
<Pane>
23-
<div class="flex flex-col space-y-6">
30+
<div class={`flex flex-col ${hasHexAddressToShow ? 'space-y-2' : 'space-y-6'}`}>
2431
{#if features?.wallet?.sendAndReceive?.enabled}
25-
<SendButton />
32+
{#if !hasHexAddressToShow}
33+
<SendButton />
34+
{/if}
2635
<ReceiveAddressButton />
36+
{#if hasHexAddressToShow}
37+
<HexAddressBox address={$selectedAccount?.depositAddress} isCopyable />
38+
{/if}
2739
{/if}
2840
</div>
2941
</Pane>
@@ -42,3 +54,36 @@
4254
{/key}
4355
</wallet-container>
4456
{/if}
57+
58+
<style lang="scss">
59+
hex-address-box {
60+
@apply border;
61+
@apply border-solid;
62+
@apply border-gray-300;
63+
&:hover {
64+
@apply bg-blue-50;
65+
@apply border-gray-500;
66+
}
67+
&:active,
68+
&:focus {
69+
@apply bg-blue-100;
70+
@apply border-blue-400;
71+
}
72+
&.darkmode {
73+
@apply border-gray-700;
74+
&:hover,
75+
&:focus,
76+
&:active {
77+
@apply bg-gray-700;
78+
@apply bg-opacity-20;
79+
@apply border-opacity-50;
80+
}
81+
&:disabled {
82+
@apply bg-gray-700;
83+
@apply bg-opacity-10;
84+
@apply border-gray-700;
85+
@apply border-opacity-10;
86+
}
87+
}
88+
}
89+
</style>

packages/shared/components/SubjectBox.svelte

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
<script lang="ts">
22
import { localize } from '@core/i18n'
33
import { Subject, SubjectType } from '@core/wallet'
4-
import { Box, AddressBox, Text, AccountLabel, TextType, FontWeight } from 'shared/components'
4+
import { Box, AddressBox, Text, AccountLabel, TextType, FontWeight, HexAddressBox } from 'shared/components'
5+
import { isValidBech32AddressAndPrefix, BECH32_DEFAULT_HRP } from '@core/utils'
56
67
export let subject: Subject | null = null
8+
9+
let hasHexAddressToShow = false
10+
11+
$: if (isValidBech32AddressAndPrefix(subject?.address, BECH32_DEFAULT_HRP)) {
12+
hasHexAddressToShow = true
13+
}
714
</script>
815

916
{#if subject?.type === SubjectType.Account}
@@ -12,6 +19,11 @@
1219
</Box>
1320
{:else if subject?.type === SubjectType.Address}
1421
<AddressBox clearBackground clearPadding isCopyable address={subject?.address} />
22+
{#if hasHexAddressToShow}
23+
<div class="w-3/4">
24+
<HexAddressBox address={subject?.address} isCopyable />
25+
</div>
26+
{/if}
1527
{:else}
1628
<Box row clearBackground clearPadding classes="justify-center">
1729
<Text type={TextType.pre} fontSize="base" fontWeight={FontWeight.medium}>

packages/shared/components/boxes/AddressBox.svelte

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
11
<script lang="ts">
22
import { Text, CopyableBox, FontWeight, TextType } from 'shared/components'
3-
43
export let address: string = ''
54
export let isCopyable: boolean = false
65
export let fontSize: string = 'base'
7-
86
let copyableBoxElement: CopyableBox
9-
107
export function copyAddress(): void {
118
copyableBoxElement.onClick()
129
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
<script lang="ts">
2+
import { Icon, Text, CopyableBox, FontWeight, TextType, Tooltip, Position, Box } from 'shared/components'
3+
import { convertBech32ToHex, BECH32_DEFAULT_HRP } from '@core/utils'
4+
import { Icon as IconEnum } from '@auxiliary/icon'
5+
6+
export let isCopyable = false
7+
export let address: string = ''
8+
export let hexAddress = ''
9+
export let clearBorder = false
10+
11+
let hexCopyableBoxElement: CopyableBox
12+
let infoAnchor: HTMLElement
13+
let tooltipRef: Tooltip
14+
let showInfoTooltip = false
15+
16+
export function copyHexAddress(): void {
17+
hexCopyableBoxElement?.onClick()
18+
}
19+
20+
function showTooltip(): Promise<void> {
21+
showInfoTooltip = true
22+
tooltipRef?.refreshPosition()
23+
}
24+
function hideTooltip(): void {
25+
showInfoTooltip = false
26+
}
27+
28+
$: hexAddress = convertBech32ToHex(address, BECH32_DEFAULT_HRP)
29+
</script>
30+
31+
{#if hexAddress.length > 0}
32+
<Box
33+
clearBackground
34+
classes={`${
35+
clearBorder
36+
? ''
37+
: 'border border-solid border-gray-300 hover:border-gray-500 focus:border-blue-400 active:border-blue-400 dark:border-gray-700 dark:hover:border-opacity-50 dark:active:border-opacity-50 dark:focus:border-opacity-50'
38+
} hover:bg-blue-50 focus:bg-blue-100 active:bg-blue-100 dark:hover:bg-gray-700 dark:hover:bg-opacity-20 dark:focus:bg-gray-700 dark:focus:bg-opacity-20 dark:active:bg-gray-700 dark:active:bg-opacity-20`}
39+
>
40+
<CopyableBox
41+
bind:this={hexCopyableBoxElement}
42+
col
43+
{isCopyable}
44+
value={hexAddress}
45+
clearBoxPadding
46+
clearBackground
47+
{...$$restProps}
48+
>
49+
<div class="flex flex-row gap-4 items-center w-full justify-between">
50+
<div class="flex flex-col w-full break-all text-center">
51+
<Text type={TextType.p} fontSize="12" fontWeight={FontWeight.light} secondary>
52+
{hexAddress}
53+
</Text>
54+
</div>
55+
56+
{#if hexAddress.length > 0}
57+
<span bind:this={infoAnchor} on:mouseenter={showTooltip} on:mouseleave={hideTooltip}>
58+
<Icon icon={IconEnum.Info} classes="text-gray-500 w-4 h-4" />
59+
</span>
60+
{/if}
61+
62+
{#if showInfoTooltip}
63+
<Tooltip
64+
bind:this={tooltipRef}
65+
anchor={infoAnchor}
66+
position={Position.Right}
67+
offset={6}
68+
size="small"
69+
>
70+
<Text color="gray-600" darkColor="gray-400" classes="text-left" smaller>
71+
Equivalent hex address in the new IOTA Wallet extension
72+
</Text>
73+
</Tooltip>
74+
{/if}
75+
</div>
76+
</CopyableBox>
77+
</Box>
78+
{/if}

packages/shared/components/boxes/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ export { default as Box } from './Box.svelte'
22
export { default as KeyValueBox } from './KeyValueBox.svelte'
33
export { default as AddressBox } from './AddressBox.svelte'
44
export { default as CopyableBox } from './CopyableBox.svelte'
5+
export { default as HexAddressBox } from './HexAddressBox.svelte'

packages/shared/components/buttons/ReceiveAddressButton.svelte

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,9 @@
33
import { appSettings } from '@core/app'
44
import { localize } from '@core/i18n'
55
import { QR, Text, FontWeight, AddressBox } from 'shared/components'
6-
76
let addressBoxElement: AddressBox
8-
97
$: receiveAddress = $selectedAccount.depositAddress
108
$: darkModeEnabled = $appSettings.darkMode
11-
129
function onReceiveClick(): void {
1310
addressBoxElement.copyAddress()
1411
}
@@ -39,7 +36,6 @@
3936
@apply border;
4037
@apply border-solid;
4138
@apply border-gray-300;
42-
4339
&:hover {
4440
@apply bg-blue-50;
4541
@apply border-gray-500;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const BECH32_DEFAULT_HRP = 'iota'

packages/shared/lib/core/utils/constants/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ export * from './max-bytes.constant'
77
export * from './max-number-of-iotas.constant'
88
export * from './pin-length.constant'
99
export * from './time.constants'
10+
export * from './bech32-hrp.constant'

packages/shared/lib/core/utils/convert.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,15 @@ import { HEXADECIMAL_PREFIX, MILLISECONDS_PER_SECOND } from './constants'
44
import { isValidDate } from './date'
55
import { Base64 } from './encode'
66
import { clamp } from './math'
7+
import { Bech32Helper } from './crypto'
8+
9+
/**
10+
* Converts a Bech32 address to a hexadecimal string.
11+
*/
12+
export function convertBech32ToHex(bech32Address: string, hrp: string): string {
13+
const { addressBytes } = Bech32Helper.fromBech32(bech32Address, hrp)
14+
return convertBytesToHexString(Array.from(addressBytes), true)
15+
}
716

817
/**
918
* Returns a UNIX timestamp from a given Date object.

0 commit comments

Comments
 (0)