Skip to content

Commit

Permalink
chore: Merge code
Browse files Browse the repository at this point in the history
  • Loading branch information
AricRedemption committed Feb 18, 2024
2 parents 4b1c633 + 060ee0d commit b07dcca
Show file tree
Hide file tree
Showing 13 changed files with 351 additions and 115 deletions.
12 changes: 4 additions & 8 deletions src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,10 @@ checkMigrate().then(async () => {
</script>

<template>
<div
id="app"
class="ext-app relative flex h-150 w-90 items-center justify-center overflow-y-auto xs:h-screen xs:w-screen xs:bg-gray-200/10 font-sans"
>
<div id="app"
class="ext-app relative flex h-150 w-90 items-center justify-center overflow-y-auto xs:h-screen xs:w-screen xs:bg-gray-200/10 font-sans">
<div
class="ext-app flex h-full w-full flex-col xs:relative xs:aspect-[1/2] xs:h-3/4 xs:w-auto xs:min-w-[25rem] xs:rounded-lg xs:border xs:border-gray-100 xs:bg-white xs:shadow-lg"
>
class="ext-app flex h-full w-full flex-col xs:relative xs:aspect-[1/2] xs:h-3/4 xs:w-auto xs:min-w-[25rem] xs:rounded-lg xs:border xs:border-gray-100 xs:bg-white xs:shadow-lg">
<!-- Header -->
<SecondaryHeader v-if="route.meta.secondaryHeader">
<template #title>
Expand All @@ -81,8 +78,7 @@ checkMigrate().then(async () => {

<!-- bg -->
<div
class="fixed left-0 top-0 isolate z-[-1] hidden h-1/2 w-full select-none bg-cover bg-center bg-no-repeat xs:block"
>
class="fixed left-0 top-0 isolate z-[-1] hidden h-1/2 w-full select-none bg-cover bg-center bg-no-repeat xs:block">
<img class="z-[-1] h-full w-full select-none opacity-100" :src="BgHueImg" alt="bg-hue" />
</div>
<div class="isolate grow px-5 overflow-y-auto nicer-scrollbar" :class="noFooter ? 'pb-8' : 'pb-16'">
Expand Down
109 changes: 109 additions & 0 deletions src/lib/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,115 @@ export async function updateBtcPath(path: string) {
await setAccount(account)
}

<<<<<<< HEAD
=======
export async function needsMigrationV2(): Promise<boolean> {
const v1Records = await getLegacyAccounts()
const v2Records = await getV2Accounts()
const v3Records = await getAccounts()

// find out if there are any old records that exists in v1 but not in v2, judged by mnemonic
const v1Mnemonics = v1Records.map((record) => record.mnemonic)
const v2Mnemonics = Array.from(v2Records.values()).map((record) => record.mnemonic)
const v3Mnemonics = Array.from(v3Records.values()).map((record) => record.mnemonic)

return v1Mnemonics.some((mne) => !v2Mnemonics.includes(mne)) ||
v1Mnemonics.some((mne) => !v3Mnemonics.includes(encrypt(mne))) ||
v2Mnemonics.some((mne) => !v3Mnemonics.includes(encrypt(mne)))
}

export async function getLegacyAccounts(): Promise<V1Account[]> {
const legacyAccounts = await getStorage(ACCOUNT_STORAGE_HISTORY_KEYS[0], { isParse: true })
if (!legacyAccounts) {
return []
}

return Object.values(legacyAccounts)
}

export async function getV2Accounts(): Promise<Map<string, Account>> {
const v2Accounts = await getStorage(ACCOUNT_STORAGE_HISTORY_KEYS[1], { defaultValue: '{}', isParse: false })
if (!v2Accounts) {
return new Map()
}

return deserializeAccountMap(v2Accounts)
}

export async function migrateV2(): Promise<void> {
const v1Accounts = await getLegacyAccounts()
const v2Accounts = await getAccounts()
const v2AccountsArr = Array.from(v2Accounts.values())
if (!v1Accounts) {
return
}
const v1AccountsIds = v1Accounts.map((account) => account.id)

// loop through v1 accounts, see if there are any accounts that are not in v2
for (let i = 0; i < v1AccountsIds.length; i++) {
const v1AccountId = v1AccountsIds[i]
const v1Account = v1Accounts.find((account) => account.id === v1AccountId)

if (!v1Account) {
continue
}

// check if account already exists in v2
const accountHasMigrated = v2AccountsArr.some((account) => account.mnemonic === v1Account.mnemonic)

if (accountHasMigrated) {
continue
}

const deriveChainPath = v1Account.path
const path = `m/44'/${deriveChainPath}'/0'/0/0`
const rndNameId = generateRandomString(4)

const allAddresses = deriveAllAddresses({
mnemonic: v1Account.mnemonic,
btcPath: path,
mvcPath: path,
})

const newAccount = {
id: v1AccountId,
name: v1Account.name || `Account ${rndNameId}`,
mnemonic: v1Account.mnemonic,
assetsDisplay: ['SPACE', 'BTC'],
mvc: {
path,
addressType: 'P2PKH',
mainnetAddress: allAddresses.mvcMainnetAddress,
testnetAddress: allAddresses.mvcTestnetAddress,
} as DerivedAccountDetail,
btc: {
path,
addressType: 'P2PKH',
mainnetAddress: allAddresses.btcMainnetAddress,
testnetAddress: allAddresses.btcTestnetAddress,
} as DerivedAccountDetail,
}
v2Accounts.set(v1AccountId, newAccount)
}

// set new accounts map
await setV2Accounts(v2Accounts)
}

export async function migrateV3(): Promise<void> {
const accounts = await getStorage(ACCOUNT_STORAGE_HISTORY_KEYS[1], { defaultValue: '{}', isParse: false })

const accountsMap = deserializeAccountMap(accounts)
for (let [v3AccountId, v3Account] of accountsMap.entries()) {
// encryte mnemonic
v3Account.mnemonic = encrypt(v3Account.mnemonic)
accountsMap.set(v3AccountId, v3Account)
}
// set new accounts map
await setAccounts(accountsMap)
}

>>>>>>> 060ee0db2d0628873973e7ccfbb8f843e47a6c81
type AccountManager = {
all: () => Promise<Map<string, Account>>
getCurrent: () => Promise<Account | undefined>
Expand Down
15 changes: 8 additions & 7 deletions src/lib/btc-util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { isTaprootInput } from 'bitcoinjs-lib/src/psbt/bip371'

import { raise } from './helpers'
import { Output } from 'bitcoinjs-lib/src/transaction'
import { encrypt } from './crypto'

export const DUST_UTXO_VALUE = 546
const TX_EMPTY_SIZE = 4 + 1 + 1 + 4
Expand Down Expand Up @@ -55,12 +56,12 @@ function outputBytes(output: PsbtTxOutput) {
(output.script
? output.script.length
: output.address?.startsWith('bc1') || output.address?.startsWith('tb1')
? output.address?.length === 42
? TX_OUTPUT_SEGWIT
: TX_OUTPUT_SEGWIT_SCRIPTHASH
: output.address?.startsWith('3') || output.address?.startsWith('2')
? TX_OUTPUT_SCRIPTHASH
: TX_OUTPUT_PUBKEYHASH)
? output.address?.length === 42
? TX_OUTPUT_SEGWIT
: TX_OUTPUT_SEGWIT_SCRIPTHASH
: output.address?.startsWith('3') || output.address?.startsWith('2')
? TX_OUTPUT_SCRIPTHASH
: TX_OUTPUT_PUBKEYHASH)
)
}

Expand Down Expand Up @@ -89,7 +90,7 @@ export async function getTweakedPrivateKey() {
const network = await getNetwork()
const account = (await getCurrentAccount()) ?? raise('No current account')

const privateKey = deriveBtcPrivateKey(account.mnemonic, account.btc.path, network)
const privateKey = deriveBtcPrivateKey(encrypt(account.mnemonic), account.btc.path, network)
const xOnlyPublicKey = await getXOnlyPublicKey()
const tabTweaked = tapTweakHash(xOnlyPublicKey)

Expand Down
6 changes: 6 additions & 0 deletions src/lib/connector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,13 @@ async function getConnections() {
}

connector.connect = async function (accountId, host) {
<<<<<<< HEAD
const connections = await getConnections()
=======
const connections = await storage.get('connections', {
defaultValue: {}, isParse: true
})
>>>>>>> 060ee0db2d0628873973e7ccfbb8f843e47a6c81
const accountConnections = connections[accountId] || {}
accountConnections[host] = {
connectedAt: Date.now(),
Expand Down
4 changes: 2 additions & 2 deletions src/lib/crypto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ export const signTransaction = async (
{ txHex, scriptHex, inputIndex, satoshis, sigtype, path }: ToSignTransaction,
returnsTransaction: boolean = false
) => {
const mneObj = mvc.Mnemonic.fromString(account.mnemonic)
const mneObj = mvc.Mnemonic.fromString(encrypt(account.mnemonic))
const hdpk = mneObj.toHDPrivateKey('', network)
const rootPath = await getMvcRootPath()
// find out priv / pub according to path
Expand Down Expand Up @@ -135,7 +135,7 @@ export const signTransactions = async (
network: 'testnet' | 'mainnet',
toSignTransactions: ToSignTransaction[]
) => {
const mneObj = mvc.Mnemonic.fromString(account.mnemonic)
const mneObj = mvc.Mnemonic.fromString(encrypt(account.mnemonic))
const hdpk = mneObj.toHDPrivateKey('', network)
const rootPath = await getMvcRootPath()

Expand Down
17 changes: 17 additions & 0 deletions src/lib/lock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { getStorage, setStorage } from './storage'

const LAST_LOCK_TIME = 'LAST_LOCK_TIME'

export async function getLastLockTime() {
const time = await getStorage(LAST_LOCK_TIME, { defaultValue: -1 })
try {
return Number(time)
} catch (error) {
console.error("getLastLockTimeError", error);
return -1
}
}

export async function setLastLockTime() {
return await setStorage(LAST_LOCK_TIME, Date.now())
}
2 changes: 2 additions & 0 deletions src/pages/lock/Index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import MetaletLogoImg from '@/assets/images/metalet-logo.png?url'
import { EyeIcon, EyeSlashIcon } from '@heroicons/vue/24/solid'
import passwordManager from '@/lib/password'
import { useRouter } from 'vue-router'
import { setLastLockTime } from '@/lib/lock'
const router = useRouter()
Expand All @@ -18,6 +19,7 @@ const tryUnlock = async () => {
if (isCorrect) {
// 如果正确,解锁
await passwordManager.unlock(password.value)
await setLastLockTime()
// 跳转到钱包页面
router.push('/wallet')
} else {
Expand Down
121 changes: 121 additions & 0 deletions src/pages/migrate/Index.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
<script lang="ts" setup>
import { mvc } from 'meta-contract'
import { ref } from 'vue'
import { useRouter } from 'vue-router'
import { addAccount, getAccounts, getLegacyAccounts } from '@/lib/account'
import { setNetwork } from '@/lib/network'
import { deriveAllAddresses, type AddressType } from '@/lib/bip32-deriver'
import MetaletLogoImg from '@/assets/images/metalet-logo.png?url'
import { encrypt } from '@/lib/crypto'
const router = useRouter()
const error = ref('')
const importWallet = async () => {
// 如果是老用户(sync存储中有助记词),且该账号在localStorage中不存在,则说明需要迁移,跳转至新版本迁移页面
const oldRecord = await chrome.storage.sync.get('currentAccount')
const v1Records = await getLegacyAccounts()
if (oldRecord && oldRecord.currentAccount && oldRecord.currentAccount.mnemonicStr && !v1Records.length) {
const mneStr = oldRecord.currentAccount.mnemonicStr
// 比照查看有无该助记词的账号
const accounts = await getAccounts()
const accountsArr = Array.from(accounts.values())
const hasAccount = accountsArr.some((account) => account.mnemonic === encrypt(mneStr))
if (!hasAccount) {
// 迁移过程
// 在localStorage中存储老账号
try {
const mnemonicStr = oldRecord.currentAccount.mnemonicStr
const address = oldRecord.currentAccount.address
const mneObj = mvc.Mnemonic.fromString(mnemonicStr)
// 从其地址推断他的path
let usingPath: string = ''
let network: 'mainnet' | 'testnet' = 'mainnet'
const commonPaths = ['236', '10001']
for (const path of commonPaths) {
network = address.startsWith('1') ? 'mainnet' : 'testnet'
const hdpk = mneObj.toHDPrivateKey('', network)
const privateKey = hdpk.deriveChild(`m/44'/${path}'/0'/0/0`).privateKey
const derivedAddress = privateKey.toAddress(network).toString()
if (address === derivedAddress) {
usingPath = path
break
}
}
if (!usingPath) {
throw new Error('Cannot find the path of the original account')
}
const fullPath = `m/44'/${usingPath}'/0'/0/0`
const btcPath = fullPath
const allAddresses = deriveAllAddresses({
mnemonic: mnemonicStr,
btcPath,
mvcPath: fullPath,
})
// construct new account object
const account = {
mnemonic: mnemonicStr,
assetsDisplay: ['SPACE', 'BTC'],
mvc: {
path: fullPath,
addressType: 'P2PKH' as AddressType,
mainnetAddress: allAddresses.mvcMainnetAddress,
testnetAddress: allAddresses.mvcTestnetAddress,
},
btc: {
path: btcPath,
addressType: 'P2PKH' as AddressType,
mainnetAddress: allAddresses.btcMainnetAddress,
testnetAddress: allAddresses.btcTestnetAddress,
},
}
await addAccount(account)
// 根据用户使用的网络,设置当前网络环境
await setNetwork(network)
// // 跳转到首页
router.push('/wallet')
} catch (e: any) {
error.value = e.message
}
}
}
}
</script>

<template>
<div class="flex h-full flex-col justify-between text-center">
<div class="">
<div class="mt-12">
<img class="mx-auto h-24 w-24" :src="MetaletLogoImg" alt="metalet-logo" />
</div>

<div class="mt-4">
<div class="flex items-end justify-center gap-x-2">
<h1 class="text-3xl font-extrabold leading-none">Metalet</h1>
<span class="text-base font-bold leading-none text-amber-500">v2.0</span>
</div>

<p class="mt-2 text-gray-500">Welcome Back!</p>
</div>
</div>

<div class="flex flex-col items-stretch pb-4">
<p class="mb-2 text-sm text-red-500" v-if="error">{{ error }}</p>
<button class="gradient-bg rounded-md py-4 text-base font-bold leading-none tracking-wide text-blue-50"
@click="importWallet">
OK
</button>
</div>
</div>
</template>
Loading

0 comments on commit b07dcca

Please sign in to comment.