From 8e686df8a6539f149b9d0be91e90e7a3023e8b14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9gor=20Sternat?= Date: Mon, 16 Sep 2024 00:59:19 +0200 Subject: [PATCH 01/13] feat: adding the base of the component for the import pop up --- src/components/wallet/importPopUp.vue | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/components/wallet/importPopUp.vue diff --git a/src/components/wallet/importPopUp.vue b/src/components/wallet/importPopUp.vue new file mode 100644 index 0000000..8e0e23d --- /dev/null +++ b/src/components/wallet/importPopUp.vue @@ -0,0 +1,17 @@ + + + \ No newline at end of file From 39d14f8b9a320bbb906119e628a733f2cb7bba88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9gor=20Sternat?= Date: Mon, 16 Sep 2024 01:00:03 +0200 Subject: [PATCH 02/13] feat: adding new mutations and getters to manage password gp --- src/store.ts | 73 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 47 insertions(+), 26 deletions(-) diff --git a/src/store.ts b/src/store.ts index 73f7b78..31a7c0f 100644 --- a/src/store.ts +++ b/src/store.ts @@ -1,50 +1,69 @@ -import { createStore } from 'vuex'; -import type { WalletClient } from 'viem'; +import { createStore } from 'vuex' +import type { WalletClient } from 'viem' interface Account { - name: string; - address: string; - reducedAddress: string; - mnemonic: string; - wallet: WalletClient; + name: string + address: string + reducedAddress: string + wallet: WalletClient + id: number } interface State { - accounts: Account[]; - selectedAccount: string | null; + accounts: Account[] + selectedAccount: string | null + password: string | null + walletCounter: number } const state: State = { accounts: [], selectedAccount: null, -}; + password: null, + walletCounter: 0 +} const mutations = { addAccount(state: State, account: Account) { - account.reducedAddress = `${account.address.slice(0, 7)}...${account.address.slice(-5)}`; - state.accounts.push(account); - state.selectedAccount = account.address; + account.reducedAddress = `${account.address.slice(0, 7)}...${account.address.slice(-5)}` + account.id = state.walletCounter + state.accounts.push(account) + state.selectedAccount = account.address + state.walletCounter++ }, selectAccount(state: State, address: string) { - state.selectedAccount = address; + state.selectedAccount = address }, clearAccounts(state: State) { - state.accounts = []; - state.selectedAccount = null; + state.accounts = [] + state.selectedAccount = null + state.walletCounter = 0 + }, + addPassword(state: State, password: string) { + state.password = password + }, + clearPassword(state: State) { + state.password = null } -}; +} const actions = { addAccount({ commit }: { commit: Function }, account: Account) { - commit('addAccount', account); + commit('addAccount', account) }, selectAccount({ commit }: { commit: Function }, address: string) { - commit('selectAccount', address); + commit('selectAccount', address) }, clearAccounts({ commit }: { commit: Function }) { - commit('clearAccounts'); + commit('clearAccounts') + }, + addPassword({ commit }: { commit: Function }, password: string) { + commit('addPassword', password) + }, + clearPassword({ commit }: { commit: Function }) { + commit('clearPassword') } -}; +} const getters = { accounts: (state: State) => state.accounts, @@ -53,15 +72,17 @@ const getters = { return state.accounts.map(account => ({ ...account, reducedAddress: `${account.address.slice(0, 7)}...${account.address.slice(-5)}` - })); - } -}; + })) + }, + password: (state: State) => state.password, + walletCounter: (state: State) => state.walletCounter +} const store = createStore({ state, mutations, actions, getters -}); +}) -export default store; +export default store From c1ae3ff0e8ad86d71d3f13a1dea6b1f730dab459 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9gor=20Sternat?= Date: Mon, 16 Sep 2024 01:04:06 +0200 Subject: [PATCH 03/13] feat: store the password to the store --- src/components/passwordPage.vue | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/components/passwordPage.vue b/src/components/passwordPage.vue index 71d943a..9debc4a 100644 --- a/src/components/passwordPage.vue +++ b/src/components/passwordPage.vue @@ -14,15 +14,18 @@ From 60d55f7b3e7936257ff9d97386b1a86b7dea743b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9gor=20Sternat?= Date: Mon, 16 Sep 2024 01:32:38 +0200 Subject: [PATCH 05/13] feat: return the private key --- src/utils/wallet.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/utils/wallet.ts b/src/utils/wallet.ts index ea4f27b..3b4ee7e 100644 --- a/src/utils/wallet.ts +++ b/src/utils/wallet.ts @@ -13,11 +13,11 @@ function uint8ToHexString(uint8Array: Uint8Array | null): `0x${string}` { return `0x${hexString}` as `0x${string}`; } -export function generateWallet(): { newWallet:WalletClient, mnemonic:string } { +export function generateWallet(walletNumber: number): { newWallet:WalletClient, mnemonic:string, privateKey:string } { const mnemonic = generateMnemonic(english) const seed = mnemonicToSeedSync(mnemonic) const masterKey = HDKey.fromMasterSeed(seed) - const privateKeyUint8 = masterKey.derive(`m/44'/60'/0'/0/0`).privateKey + const privateKeyUint8 = masterKey.derive(`m/44'/60'/0'/0/${walletNumber}`).privateKey const privateKey = uint8ToHexString(privateKeyUint8) const account = privateKeyToAccount(privateKey) @@ -26,5 +26,5 @@ export function generateWallet(): { newWallet:WalletClient, mnemonic:string } { chain: mainnet, transport: http() }) - return { newWallet, mnemonic } + return { newWallet, mnemonic, privateKey } } From bbbf4ed67b7a5ee774256a9e2806de47d43e7563 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9gor=20Sternat?= Date: Mon, 16 Sep 2024 01:33:10 +0200 Subject: [PATCH 06/13] feat: set the encrypted private key to the local storage --- src/components/wallet/verticalNavbar.vue | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/wallet/verticalNavbar.vue b/src/components/wallet/verticalNavbar.vue index 22ce51b..1e2c1f7 100644 --- a/src/components/wallet/verticalNavbar.vue +++ b/src/components/wallet/verticalNavbar.vue @@ -6,6 +6,7 @@ import mnemonicPopUp from '@/components/wallet/mnemonicPopUp.vue' import { generateWallet } from '@/utils/wallet' import type { WalletClient } from 'viem' import importPopUp from './importPopUp.vue' +import { encryption } from '../../utils/crypto' interface Account { name: string @@ -38,7 +39,7 @@ export default defineComponent({ methods: { ...mapActions(['addAccount', 'selectAccount']), addAccountToStore() { - const { newWallet, mnemonic } = generateWallet() + const { newWallet, mnemonic, privateKey } = generateWallet(this.walletCounter) const newAccount: Account = { name: `Account ${this.walletCounter + 1}`, address: newWallet.account.address, @@ -47,6 +48,7 @@ export default defineComponent({ this.mnemonic = mnemonic this.addAccount(newAccount) this.isMnemonicVisible = true + localStorage.setItem(`privateKeyAccount${this.walletCounter + 1}`, encryption(privateKey, this.password)) }, selectAccountInStore(address: string) { this.selectAccount(address) From 0ecda318e4143c2c8fb488f36f78aee1be2e630f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9gor=20Sternat?= Date: Mon, 16 Sep 2024 21:53:37 +0200 Subject: [PATCH 07/13] feat: adding importation feature --- src/components/wallet/verticalNavbar.vue | 14 ++++++++--- src/store.ts | 30 ++++++++++++++++++++++++ src/utils/wallet.ts | 9 +++++++ 3 files changed, 50 insertions(+), 3 deletions(-) diff --git a/src/components/wallet/verticalNavbar.vue b/src/components/wallet/verticalNavbar.vue index 1e2c1f7..1efaccb 100644 --- a/src/components/wallet/verticalNavbar.vue +++ b/src/components/wallet/verticalNavbar.vue @@ -6,7 +6,7 @@ import mnemonicPopUp from '@/components/wallet/mnemonicPopUp.vue' import { generateWallet } from '@/utils/wallet' import type { WalletClient } from 'viem' import importPopUp from './importPopUp.vue' -import { encryption } from '../../utils/crypto' +import { encryption } from '@/utils/crypto' interface Account { name: string @@ -37,7 +37,7 @@ export default defineComponent({ } }, methods: { - ...mapActions(['addAccount', 'selectAccount']), + ...mapActions(['addAccount', 'selectAccount', 'initializeAccountsFromLocalStorage']), addAccountToStore() { const { newWallet, mnemonic, privateKey } = generateWallet(this.walletCounter) const newAccount: Account = { @@ -48,7 +48,7 @@ export default defineComponent({ this.mnemonic = mnemonic this.addAccount(newAccount) this.isMnemonicVisible = true - localStorage.setItem(`privateKeyAccount${this.walletCounter + 1}`, encryption(privateKey, this.password)) + localStorage.setItem(`privateKeyAccount${this.walletCounter}`, encryption(privateKey, this.password)) }, selectAccountInStore(address: string) { this.selectAccount(address) @@ -64,6 +64,14 @@ export default defineComponent({ this.isImportVisible = false } }, + mounted() { + if (this.password) { + console.log('mounted') + this.initializeAccountsFromLocalStorage() + } else { + console.log('No password set') + } + } }) diff --git a/src/store.ts b/src/store.ts index 31a7c0f..b14cece 100644 --- a/src/store.ts +++ b/src/store.ts @@ -1,5 +1,7 @@ import { createStore } from 'vuex' import type { WalletClient } from 'viem' +import { decryption } from '@/utils/crypto' +import { generateWalletFromPrivateKey } from '@/utils/wallet' interface Account { name: string @@ -44,6 +46,31 @@ const mutations = { }, clearPassword(state: State) { state.password = null + }, + initializeAccountsFromLocalStorage( state: State) { + let walletCounter = 0 + while (localStorage.getItem(`privateKeyAccount${walletCounter + 1}`)) { + walletCounter++ + } + state.walletCounter = walletCounter + + console.log(walletCounter) + for (let i = 1; i <= walletCounter; i++) { + const encryptedPrivateKey = localStorage.getItem(`privateKeyAccount${i}`) + if (encryptedPrivateKey && state.password) { + const privateKey = decryption(encryptedPrivateKey, state.password) + const wallet = generateWalletFromPrivateKey(privateKey) + + const account: Account = { + name: `Account ${i}`, + address: wallet.account.address, + wallet: wallet, + reducedAddress: '', + id: i + } + state.accounts.push(account) + } + } } } @@ -62,6 +89,9 @@ const actions = { }, clearPassword({ commit }: { commit: Function }) { commit('clearPassword') + }, + initializeAccountsFromLocalStorage({ commit }: { commit: Function }) { + commit('initializeAccountsFromLocalStorage') } } diff --git a/src/utils/wallet.ts b/src/utils/wallet.ts index 3b4ee7e..6f0cf0e 100644 --- a/src/utils/wallet.ts +++ b/src/utils/wallet.ts @@ -28,3 +28,12 @@ export function generateWallet(walletNumber: number): { newWallet:WalletClient, }) return { newWallet, mnemonic, privateKey } } + +export function generateWalletFromPrivateKey(privateKey: `0x${string}`): WalletClient { + const account = privateKeyToAccount(privateKey) + return createWalletClient({ + account, + chain: mainnet, + transport: http() + }) +} \ No newline at end of file From 78001465658fd4c8c41a07546a384ff2614ac63d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9gor=20Sternat?= Date: Mon, 16 Sep 2024 21:59:58 +0200 Subject: [PATCH 08/13] fix: bug who multiply acc when they was imported --- src/components/wallet/verticalNavbar.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/wallet/verticalNavbar.vue b/src/components/wallet/verticalNavbar.vue index 1efaccb..9bffcea 100644 --- a/src/components/wallet/verticalNavbar.vue +++ b/src/components/wallet/verticalNavbar.vue @@ -65,7 +65,7 @@ export default defineComponent({ } }, mounted() { - if (this.password) { + if (this.password && this.accounts.length === 0) { console.log('mounted') this.initializeAccountsFromLocalStorage() } else { From 659b46632efc897c5bc7f861c97e2cfe838132d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9gor=20Sternat?= Date: Mon, 16 Sep 2024 22:03:21 +0200 Subject: [PATCH 09/13] style: remove useless console.loog --- src/components/wallet/verticalNavbar.vue | 1 - src/store.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/src/components/wallet/verticalNavbar.vue b/src/components/wallet/verticalNavbar.vue index 9bffcea..85b3c40 100644 --- a/src/components/wallet/verticalNavbar.vue +++ b/src/components/wallet/verticalNavbar.vue @@ -66,7 +66,6 @@ export default defineComponent({ }, mounted() { if (this.password && this.accounts.length === 0) { - console.log('mounted') this.initializeAccountsFromLocalStorage() } else { console.log('No password set') diff --git a/src/store.ts b/src/store.ts index b14cece..6c40106 100644 --- a/src/store.ts +++ b/src/store.ts @@ -54,7 +54,6 @@ const mutations = { } state.walletCounter = walletCounter - console.log(walletCounter) for (let i = 1; i <= walletCounter; i++) { const encryptedPrivateKey = localStorage.getItem(`privateKeyAccount${i}`) if (encryptedPrivateKey && state.password) { From 026706fcddb2cc3f97774df02ddb5c804652d344 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9gor=20Sternat?= Date: Mon, 16 Sep 2024 22:08:44 +0200 Subject: [PATCH 10/13] fix: remove password from store when document is hidden --- src/App.vue | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/App.vue b/src/App.vue index 4c86198..abc16ca 100644 --- a/src/App.vue +++ b/src/App.vue @@ -4,8 +4,10 @@ import ERC from "./components/main/ERC/ERC.vue"; import { onMounted, ref, onUnmounted } from "vue"; import passwordPage from "./components/passwordPage.vue"; + import { useStore } from 'vuex' const open = ref(false) + const store = useStore() onMounted(() => { const isOpen = localStorage.getItem('open-wallet') @@ -19,6 +21,7 @@ if (document.hidden) { open.value = false; localStorage.setItem('open-wallet', 'false'); + store.dispatch('clearPassword') } }; From 83c8395de1828051e77dd9a0bbc6d4d60fae2cb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9gor=20Sternat?= Date: Tue, 17 Sep 2024 01:21:44 +0200 Subject: [PATCH 11/13] feat: adding a new component for the import cards --- src/components/wallet/importCard.vue | 33 ++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 src/components/wallet/importCard.vue diff --git a/src/components/wallet/importCard.vue b/src/components/wallet/importCard.vue new file mode 100644 index 0000000..ca950bc --- /dev/null +++ b/src/components/wallet/importCard.vue @@ -0,0 +1,33 @@ + + + From d947bd04f8484504e837805168db41838ad5d223 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9gor=20Sternat?= Date: Tue, 17 Sep 2024 01:22:12 +0200 Subject: [PATCH 12/13] feat: adding the importation feature --- src/components/wallet/importPopUp.vue | 31 ++++++++++++++++++-- src/components/wallet/mnemonicPopUp.vue | 2 +- src/components/wallet/verticalNavbar.vue | 37 +++++++++++++++++++++--- src/utils/wallet.ts | 21 +++++++++++++- 4 files changed, 83 insertions(+), 8 deletions(-) diff --git a/src/components/wallet/importPopUp.vue b/src/components/wallet/importPopUp.vue index 8e0e23d..734389a 100644 --- a/src/components/wallet/importPopUp.vue +++ b/src/components/wallet/importPopUp.vue @@ -1,17 +1,44 @@ \ No newline at end of file diff --git a/src/components/wallet/mnemonicPopUp.vue b/src/components/wallet/mnemonicPopUp.vue index a6d1be5..29efcfe 100644 --- a/src/components/wallet/mnemonicPopUp.vue +++ b/src/components/wallet/mnemonicPopUp.vue @@ -25,7 +25,7 @@ export default {