Skip to content

Commit d947bd0

Browse files
author
Grégor Sternat
committed
feat: adding the importation feature
1 parent 83c8395 commit d947bd0

File tree

4 files changed

+83
-8
lines changed

4 files changed

+83
-8
lines changed

src/components/wallet/importPopUp.vue

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,44 @@
11
<script lang="ts">
2+
import importCard from './importCard.vue'
3+
24
export default {
35
name: "importPopUp",
6+
components: {
7+
importCard
8+
},
9+
data() {
10+
return {
11+
mnemonicWords: Array(12).fill('')
12+
}
13+
},
414
mounted() {
515
this.$el.focus()
16+
},
17+
methods: {
18+
closeWithoutMnemonic() {
19+
this.$emit('close')
20+
},
21+
closeWithMnemonic() {
22+
this.$emit('close', this.mnemonicWords)
23+
}
624
}
725
}
826
</script>
927

1028
<template>
1129
<div
12-
class="w-2/3 h-2/3 relative bg-background-gray rounded-lg flex flex-col z-10"
13-
@keydown.esc="$emit('close')"
30+
class="relative bg-background-gray rounded-lg w-2/3 h-2/3 p-6 md:p-8 lg:p-10 flex flex-col z-5000"
31+
@keydown.esc="closeWithoutMnemonic"
1432
tabindex="0"
1533
>
34+
<div class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4 flex-1">
35+
<importCard
36+
v-for="index in 12"
37+
:key="index"
38+
:mnemonic-number="index"
39+
v-model="mnemonicWords[index - 1]"
40+
/>
41+
</div>
42+
<button @click="closeWithMnemonic" class="btn btn-xs sm:btn-sm md:btn-md lg:btn-lg w-auto self-end bg-blue-500 hover:bg-blue-700">Import</button>
1643
</div>
1744
</template>

src/components/wallet/mnemonicPopUp.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export default {
2525

2626
<template>
2727
<div
28-
class="relative bg-background-gray rounded-lg w-2/3 h-2/3 p-6 md:p-8 lg:p-10 flex flex-col z-10"
28+
class="relative bg-background-gray rounded-lg w-2/3 h-2/3 p-6 md:p-8 lg:p-10 flex flex-col z-5000"
2929
@keydown.esc="$emit('close')"
3030
tabindex="0"
3131
>

src/components/wallet/verticalNavbar.vue

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { defineComponent } from 'vue'
33
import { mapGetters, mapActions } from 'vuex'
44
import walletCard from '@/components/wallet/walletCard.vue'
55
import mnemonicPopUp from '@/components/wallet/mnemonicPopUp.vue'
6-
import { generateWallet } from '@/utils/wallet'
6+
import { generateWallet, generateWalletFromMnemonic } from '@/utils/wallet'
77
import type { WalletClient } from 'viem'
88
import importPopUp from './importPopUp.vue'
99
import { encryption } from '@/utils/crypto'
@@ -45,6 +45,14 @@ export default defineComponent({
4545
address: newWallet.account.address,
4646
wallet: newWallet
4747
}
48+
const accountExist = this.accounts.some(
49+
(account: Account) => account.address === newWallet.account.address
50+
)
51+
if (accountExist) {
52+
console.warn("Account already exists")
53+
this.isMnemonicVisible = false
54+
return
55+
}
4856
this.mnemonic = mnemonic
4957
this.addAccount(newAccount)
5058
this.isMnemonicVisible = true
@@ -60,15 +68,36 @@ export default defineComponent({
6068
showImportPopUp() {
6169
this.isImportVisible = true
6270
},
63-
closeImportPopUp() {
71+
closeImportPopUp(mnemonicWords: string[]) {
72+
if (mnemonicWords && mnemonicWords.every((word) => word !== '')) {
73+
console.log("Importing wallet...")
74+
const { newWallet, privateKey }= generateWalletFromMnemonic(mnemonicWords)
75+
if (newWallet === null) {
76+
this.isImportVisible = false
77+
return
78+
}
79+
const accountExist = this.accounts.some(
80+
(account: Account) => account.address === newWallet.account.address
81+
)
82+
if (accountExist) {
83+
console.warn("Account already exists")
84+
this.isImportVisible = false
85+
return
86+
}
87+
const newAccount: Account = {
88+
name: `Account ${this.walletCounter + 1}`,
89+
address: newWallet.account.address,
90+
wallet: newWallet
91+
}
92+
this.addAccount(newAccount)
93+
localStorage.setItem(`privateKeyAccount${this.walletCounter}`, encryption(privateKey, this.password))
94+
}
6495
this.isImportVisible = false
6596
}
6697
},
6798
mounted() {
6899
if (this.password && this.accounts.length === 0) {
69100
this.initializeAccountsFromLocalStorage()
70-
} else {
71-
console.log('No password set')
72101
}
73102
}
74103
})

src/utils/wallet.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { HDKey } from '@scure/bip32'
22
import { mnemonicToSeedSync } from '@scure/bip39'
33
import { createWalletClient, http, type WalletClient } from 'viem'
4-
import { privateKeyToAccount, generateMnemonic, english } from 'viem/accounts'
4+
import { privateKeyToAccount, generateMnemonic, english, mnemonicToAccount } from 'viem/accounts'
55
import { mainnet } from 'viem/chains'
66

77
function uint8ToHexString(uint8Array: Uint8Array | null): `0x${string}` {
@@ -36,4 +36,23 @@ export function generateWalletFromPrivateKey(privateKey: `0x${string}`): WalletC
3636
chain: mainnet,
3737
transport: http()
3838
})
39+
}
40+
41+
export function generateWalletFromMnemonic(mnemonic: string[]): { newWallet: WalletClient | null, privateKey: string | null} {
42+
try {
43+
const seed = mnemonicToSeedSync(mnemonic.join(' '))
44+
const masterKey = HDKey.fromMasterSeed(seed)
45+
const privateKeyUint8 = masterKey.derive(`m/44'/60'/0'/0/0`).privateKey
46+
const privateKey = uint8ToHexString(privateKeyUint8)
47+
const account = privateKeyToAccount(privateKey)
48+
const newWallet = createWalletClient({
49+
account,
50+
chain: mainnet,
51+
transport: http()
52+
})
53+
return { newWallet, privateKey }
54+
} catch (error) {
55+
console.error("The mnemonic format is invalid")
56+
return { newWallet: null, privateKey: null }
57+
}
3958
}

0 commit comments

Comments
 (0)