Skip to content

Commit 4251bd0

Browse files
Merge pull request #678 from syscoin/feat/import-utxo-accounts
feat: add support for importing utxo accounts using a zprv private key
2 parents b22e6f2 + 385bbc7 commit 4251bd0

File tree

9 files changed

+261
-159
lines changed

9 files changed

+261
-159
lines changed

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,9 @@
5252
"@headlessui/react": "^1.6.0",
5353
"@heroicons/react": "^1.0.5",
5454
"@pollum-io/sysweb3-core": "^1.0.27",
55-
"@pollum-io/sysweb3-keyring": "^1.0.487",
55+
"@pollum-io/sysweb3-keyring": "^1.0.488",
5656
"@pollum-io/sysweb3-network": "^1.0.95",
57-
"@pollum-io/sysweb3-utils": "^1.1.235",
57+
"@pollum-io/sysweb3-utils": "^1.1.236",
5858
"@reduxjs/toolkit": "^1.4.0",
5959
"@tippyjs/react": "^4.2.6",
6060
"@types/chrome": "^0.0.268",

source/components/Header/AccountHeader.tsx

Lines changed: 69 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@ const RenderAccountsListByBitcoinBased = (
5858
className={`py-1.5 px-5 w-max backface-visibility-hidden flex items-center text-white text-sm
5959
font-medium active:bg-opacity-40 focus:outline-none cursor-pointer transform
6060
transition duration-300`}
61-
onClick={() => {
62-
setActiveAccount(
61+
onClick={async () => {
62+
await setActiveAccount(
6363
account.id,
6464
KeyringAccountType.HDAccount
6565
);
@@ -72,7 +72,7 @@ const RenderAccountsListByBitcoinBased = (
7272
style={{ maxWidth: '16.25rem', textOverflow: 'ellipsis' }}
7373
className="w-max gap-[2px] flex items-center justify-start whitespace-nowrap overflow-hidden"
7474
>
75-
<img src={logo} className="mr-1 w-7"></img>
75+
<img src={logo} className="mr-1 w-7" alt="" />
7676
{account.label} ({ellipsis(account.address, 4, 4)})
7777
</span>
7878
<span className="text-xs ml-2 px-2 py-0.5 text-white bg-brand-blue500 rounded-full">
@@ -89,6 +89,44 @@ const RenderAccountsListByBitcoinBased = (
8989
</li>
9090
))}
9191

92+
{Object.values(accounts.Imported)
93+
.filter((acc) => !acc.address.startsWith('0x'))
94+
.map((account, index) => (
95+
<li
96+
className={`py-1.5 px-5 w-max backface-visibility-hidden flex items-center text-white text-sm
97+
font-medium active:bg-opacity-40 focus:outline-none cursor-pointer transform
98+
transition duration-300`}
99+
onClick={async () => {
100+
await setActiveAccount(
101+
account.id,
102+
KeyringAccountType.Imported
103+
);
104+
close();
105+
}}
106+
id={`account-${index}`}
107+
key={account.id}
108+
>
109+
<span
110+
style={{ maxWidth: '16.25rem', textOverflow: 'ellipsis' }}
111+
className="w-max gap-[2px] flex items-center justify-start whitespace-nowrap overflow-hidden"
112+
>
113+
<img src={logo} className="mr-1 w-7" alt="" />
114+
{account.label} ({ellipsis(account.address, 4, 4)})
115+
</span>
116+
<span className="text-xs ml-2 px-2 py-0.5 text-white bg-brand-blue500 rounded-full">
117+
Imported
118+
</span>
119+
{activeAccount.id === account.id &&
120+
activeAccount.type === KeyringAccountType.Imported && (
121+
<Icon
122+
name="check"
123+
className="mb-1 ml-2 w-4"
124+
color="#8EC100"
125+
/>
126+
)}
127+
</li>
128+
))}
129+
92130
{Object.values(accounts.Trezor)
93131
.filter((acc) => acc.isImported === false) //todo we don't have account.isImported anymore
94132
.map((account, index) => (
@@ -100,11 +138,14 @@ const RenderAccountsListByBitcoinBased = (
100138
: 'cursor-pointer'
101139
} transform
102140
transition duration-300`}
103-
onClick={() => {
141+
onClick={async () => {
104142
if (account?.originNetwork.url !== activeNetwork.url) {
105143
return;
106144
}
107-
setActiveAccount(account.id, KeyringAccountType.Trezor);
145+
await setActiveAccount(
146+
account.id,
147+
KeyringAccountType.Trezor
148+
);
108149
close();
109150
}}
110151
id={`account-${index}`}
@@ -119,12 +160,13 @@ const RenderAccountsListByBitcoinBased = (
119160
>
120161
<img
121162
src={trezorLogo}
163+
alt=""
122164
style={{
123165
filter:
124166
'invert(100%) sepia(0%) saturate(0%) hue-rotate(44deg) brightness(108%) contrast(102%)',
125167
}}
126168
className="mr-1 w-7"
127-
></img>
169+
/>
128170
{account.label}{' '}
129171
{!(account?.originNetwork.url !== activeNetwork.url) &&
130172
`(${ellipsis(account.address, 4, 4)})`}
@@ -156,11 +198,14 @@ const RenderAccountsListByBitcoinBased = (
156198
: 'cursor-pointer'
157199
} transform
158200
transition duration-300`}
159-
onClick={() => {
201+
onClick={async () => {
160202
if (account?.originNetwork.url !== activeNetwork.url) {
161203
return;
162204
}
163-
setActiveAccount(account.id, KeyringAccountType.Ledger);
205+
await setActiveAccount(
206+
account.id,
207+
KeyringAccountType.Ledger
208+
);
164209
close();
165210
}}
166211
id={`account-${index}`}
@@ -175,12 +220,13 @@ const RenderAccountsListByBitcoinBased = (
175220
>
176221
<img
177222
src={ledgerLogo}
223+
alt=""
178224
style={{
179225
filter:
180226
'invert(100%) sepia(0%) saturate(0%) hue-rotate(44deg) brightness(108%) contrast(102%)',
181227
}}
182228
className="mr-2 w-7"
183-
></img>
229+
/>
184230
{account.label}{' '}
185231
{!(account?.originNetwork.url !== activeNetwork.url) &&
186232
`(${ellipsis(account.address, 4, 4)})`}
@@ -206,7 +252,7 @@ const RenderAccountsListByBitcoinBased = (
206252
([keyringAccountType, accountTypeAccounts]) => (
207253
<div key={keyringAccountType}>
208254
{Object.values(accountTypeAccounts)
209-
.filter((account) => account.xpub !== '')
255+
.filter((account) => account.address.startsWith('0x'))
210256
.map((account, index) => (
211257
<li
212258
className={`py-1.5 px-5 w-max backface-visibility-hidden flex items-center justify-start text-white text-sm
@@ -219,7 +265,7 @@ const RenderAccountsListByBitcoinBased = (
219265
: 'cursor-pointer'
220266
} transform
221267
transition duration-300`}
222-
onClick={() => {
268+
onClick={async () => {
223269
if (
224270
(account.isTrezorWallet &&
225271
account?.originNetwork?.isBitcoinBased) ||
@@ -228,7 +274,7 @@ const RenderAccountsListByBitcoinBased = (
228274
) {
229275
return;
230276
}
231-
setActiveAccount(
277+
await setActiveAccount(
232278
account.id,
233279
keyringAccountType as KeyringAccountType
234280
);
@@ -245,27 +291,29 @@ const RenderAccountsListByBitcoinBased = (
245291
className="w-full flex items-center justify-start whitespace-nowrap overflow-hidden"
246292
>
247293
{account.isImported ? (
248-
<img src={importIcon} className="mr-1 w-7"></img>
294+
<img src={importIcon} className="mr-1 w-7" alt="" />
249295
) : account.isTrezorWallet ? (
250296
<img
251297
src={trezorLogo}
298+
alt=""
252299
style={{
253300
filter:
254301
'invert(100%) sepia(0%) saturate(0%) hue-rotate(44deg) brightness(108%) contrast(102%)',
255302
}}
256303
className="mr-1 w-7"
257-
></img>
304+
/>
258305
) : account.isLedgerWallet ? (
259306
<img
260307
src={ledgerLogo}
308+
alt=""
261309
style={{
262310
filter:
263311
'invert(100%) sepia(0%) saturate(0%) hue-rotate(44deg) brightness(108%) contrast(102%)',
264312
}}
265313
className="mr-1 w-7"
266-
></img>
314+
/>
267315
) : (
268-
<img src={logo} className="mr-1 w-7"></img>
316+
<img src={logo} className="mr-1 w-7" alt="" />
269317
)}{' '}
270318
{account.label}{' '}
271319
{!(
@@ -328,8 +376,6 @@ export const AccountMenu: React.FC = () => {
328376
await controllerEmitter(['wallet', 'setAccount'], [Number(id), type]);
329377
};
330378

331-
const cursorType = isBitcoinBased ? 'cursor-not-allowed' : 'cursor-pointer';
332-
333379
return (
334380
<div className="flex flex-col justify-start items-start">
335381
<span className="disabled text-xs flex justify-start px-5 mt-5 mb-1">
@@ -394,27 +440,13 @@ export const AccountMenu: React.FC = () => {
394440
<Menu.Item>
395441
<div className="flex flex-col gap-2">
396442
<li
397-
onClick={() => {
398-
isBitcoinBased ? null : navigate('/settings/account/import');
399-
}}
400-
className={`py-1.5 ${cursorType} px-6 w-full backface-visibility-hidden flex items-center justify-start gap-3 text-white text-sm font-medium active:bg-opacity-40 focus:outline-none`}
443+
onClick={() => navigate('/settings/account/import')}
444+
className={`py-1.5 cursor-pointer px-6 w-full backface-visibility-hidden flex items-center justify-start gap-3 text-white text-sm font-medium active:bg-opacity-40 focus:outline-none`}
401445
>
402-
<Icon
403-
name="ImportUser"
404-
isSvg
405-
className="mb-1 text-brand-white"
406-
opacity={isBitcoinBased ? 0.6 : 1}
407-
/>
408-
409-
<span className={isBitcoinBased ? 'disabled' : ''}>
410-
{t('accountMenu.importAccount')}
411-
</span>
446+
<Icon name="ImportUser" isSvg className="mb-1 text-brand-white" />
447+
448+
<span>{t('accountMenu.importAccount')}</span>
412449
</li>
413-
{isBitcoinBased && (
414-
<span className="disabled text-xs px-5 text-left">
415-
{t('accountMenu.importAccMessage')}
416-
</span>
417-
)}
418450
</div>
419451
</Menu.Item>
420452
</div>

source/components/Header/Menus/NetworkMenu.tsx

Lines changed: 72 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ export const NetworkMenu: React.FC<INetworkComponent> = (
193193
</li>
194194
</Menu.Item>
195195
<div className="scrollbar-styled overflow-scroll">
196-
{!activeAccount.isImported ? (
196+
{isBitcoinBased || !activeAccount.isImported ? (
197197
<Menu.Item>
198198
<>
199199
<span className="disabled text-xs flex justify-start px-5 py-4">
@@ -272,71 +272,77 @@ export const NetworkMenu: React.FC<INetworkComponent> = (
272272
</Menu.Item>
273273
) : null}
274274

275-
<Menu.Item>
276-
<Disclosure>
277-
{({ open }) => (
278-
<>
279-
<Disclosure.Button className="flex items-center justify-start px-5 pt-3 w-full text-base hover:bg-bkg-3 cursor-pointer transition-all duration-200">
280-
<img
281-
src={ethIcon}
282-
width="16px"
283-
className="ml-1 flex items-center text-brand-white"
284-
/>
285-
286-
<span className="px-3 text-sm">
287-
{t('networkMenu.evmNetworks')}
288-
</span>
289-
290-
<img
291-
src={arrow}
292-
className={`relative left-[12.4rem] flex items-center ${
293-
open ? 'transform rotate-180' : ''
294-
} text-brand-white`}
295-
id="network-settings-btn"
296-
/>
297-
</Disclosure.Button>
298-
299-
<Disclosure.Panel className="h-max pb-2 pt-4 text-sm">
300-
{Object.values(networks.ethereum)
301-
.sort(customSort)
302-
303-
.map((currentNetwork: any, index: number, arr) => (
304-
<li
305-
key={uniqueId()}
306-
className={`backface-visibility-hidden ${
307-
index === 0
308-
? 'rounded-tl-lg rounded-tr-lg border-b border-dashed border-gray-600 '
309-
: index === arr.length - 1
310-
? 'rounded-bl-lg rounded-br-lg'
311-
: 'border-b border-dashed border-gray-600'
312-
} flex flex-row items-center justify-start mx-auto p-2 max-w-95 text-white text-sm font-medium active:bg-opacity-40 bg-brand-blue500 focus:outline-none cursor-pointer transform transition duration-300`}
313-
onClick={() =>
314-
handleChangeNetwork(
315-
currentNetwork,
316-
'ethereum'
317-
)
318-
}
319-
>
320-
<span className="ml-8 text-left">
321-
{currentNetwork.label}
322-
</span>
323-
<div className="absolute items-center flex gap-2 right-[1rem] ">
324-
{!isBitcoinBased &&
325-
activeNetworkValidator(currentNetwork) && (
326-
<Icon
327-
name="check"
328-
className="w-4 relative bottom-0.5"
329-
wrapperClassname="w-6"
330-
/>
331-
)}
332-
</div>
333-
</li>
334-
))}
335-
</Disclosure.Panel>
336-
</>
337-
)}
338-
</Disclosure>
339-
</Menu.Item>
275+
{activeAccount.isImported && isBitcoinBased ? null : (
276+
<Menu.Item>
277+
<Disclosure>
278+
{({ open }) => (
279+
<>
280+
<Disclosure.Button className="flex items-center justify-start px-5 pt-3 w-full text-base hover:bg-bkg-3 cursor-pointer transition-all duration-200">
281+
<img
282+
src={ethIcon}
283+
width="16px"
284+
className="ml-1 flex items-center text-brand-white"
285+
/>
286+
287+
<span className="px-3 text-sm">
288+
{t('networkMenu.evmNetworks')}
289+
</span>
290+
291+
<img
292+
src={arrow}
293+
className={`relative left-[12.4rem] flex items-center ${
294+
open ? 'transform rotate-180' : ''
295+
} text-brand-white`}
296+
id="network-settings-btn"
297+
/>
298+
</Disclosure.Button>
299+
300+
<Disclosure.Panel className="h-max pb-2 pt-4 text-sm">
301+
{Object.values(networks.ethereum)
302+
.sort(customSort)
303+
304+
.map(
305+
(currentNetwork: any, index: number, arr) => (
306+
<li
307+
key={uniqueId()}
308+
className={`backface-visibility-hidden ${
309+
index === 0
310+
? 'rounded-tl-lg rounded-tr-lg border-b border-dashed border-gray-600 '
311+
: index === arr.length - 1
312+
? 'rounded-bl-lg rounded-br-lg'
313+
: 'border-b border-dashed border-gray-600'
314+
} flex flex-row items-center justify-start mx-auto p-2 max-w-95 text-white text-sm font-medium active:bg-opacity-40 bg-brand-blue500 focus:outline-none cursor-pointer transform transition duration-300`}
315+
onClick={() =>
316+
handleChangeNetwork(
317+
currentNetwork,
318+
'ethereum'
319+
)
320+
}
321+
>
322+
<span className="ml-8 text-left">
323+
{currentNetwork.label}
324+
</span>
325+
<div className="absolute items-center flex gap-2 right-[1rem] ">
326+
{!isBitcoinBased &&
327+
activeNetworkValidator(
328+
currentNetwork
329+
) && (
330+
<Icon
331+
name="check"
332+
className="w-4 relative bottom-0.5"
333+
wrapperClassname="w-6"
334+
/>
335+
)}
336+
</div>
337+
</li>
338+
)
339+
)}
340+
</Disclosure.Panel>
341+
</>
342+
)}
343+
</Disclosure>
344+
</Menu.Item>
345+
)}
340346

341347
<span className="disabled text-xs flex justify-start px-5 py-3 mt-6">
342348
{t('networkMenu.networkSettings')}

0 commit comments

Comments
 (0)