<template>
<div class="purseinfo_box">
<div class="purse_info_add">
<el-form
ref="formRef"
:model="form"
:rules="rules"
label-width="auto"
style="max-width: 600px"
>
<el-form-item v-if="mnemonicInputShow">
<el-input
style="width: 400px"
v-model="mnemonicInput"
autocomplete="off"
placeholder="请输入12或24个助记词,用空格分隔"
@blur="handleMnemonicInput"
/>
</el-form-item>
<el-form-item label="助记词数量:">
<el-radio-group v-model="form.wordsNumber">
<el-radio value="12">12个</el-radio>
<el-radio value="24">24个</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="助记词:">
<div class="form_container">
<div
class="form_item"
v-for="index in Number(form.wordsNumber)"
:key="index"
>
<span>{{ index }}.</span>
<el-form-item
:prop="`number${index}`"
:rules="[
{
required: true,
message: `请输入第 ${index} 个助记词`,
trigger: 'blur'
},
{ validator: validateWord, trigger: 'blur' }
]"
>
<el-input v-model="form[`number${index}`]" autocomplete="off" />
</el-form-item>
</div>
</div>
</el-form-item>
<el-form-item>
<div class="submit_btn">
<el-button type="default" @click="clearForm">清空</el-button>
<el-button type="primary" @click="onSubmit">录入</el-button>
</div>
</el-form-item>
</el-form>
</div>
<div class="mnemonicWords_btn">
<el-button type="primary" @click="handleShowZhujici">
{{ showZhujiciText }}
</el-button>
</div>
<div class="mnemonicWords_box" v-if="showZhujici">
<div class="text" v-for="(item, index) in mnemonicWords" :key="index">
<span>{{ item }}</span>
</div>
</div>
</div>
</template>
<script setup name="PurseInfoAdd">
import { ref, watch } from 'vue'
import { ElMessage } from 'element-plus'
import { ethers } from 'ethers'
import { TronWeb } from 'tronweb'
import { Buffer } from 'buffer'
import { HDNode } from '@ethersproject/hdnode'
import { addPurseAddress } from '@/api/purse/purseInfo'
import { mnemonicWords } from './mnemonicWords'
import { Keypair } from '@solana/web3.js'
import { HDKey } from 'micro-ed25519-hdkey'
import * as bip39 from 'bip39'
import bs58 from 'bs58'
import CryptoJS from 'crypto-js'
window.Buffer = Buffer
const formRef = ref(null)
const mnemonicInput = ref('')
const mnemonic = ref('')
const rules = ref({})
const showZhujiciText = ref('点击显示助记词')
const showZhujici = ref(false)
const mnemonicInputShow = ref(true)
const form = ref({
wordsNumber: '12',
...Object.fromEntries(
Array.from({ length: 24 }, (_, i) => [`number${i + 1}`, ''])
)
})
watch(
() => form.value?.wordsNumber,
(newValue) => {
const num = Number(newValue)
for (let i = 1; i <= 24; i++) {
if (i > num) {
form.value[`number${i}`] = ''
}
}
}
)
const handleMnemonicInput = () => {
const words = mnemonicInput.value.trim().split(/\s+/)
if (words.length === 12 || words.length === 24) {
form.value.wordsNumber = words.length.toString()
words.forEach((word, index) => {
form.value[`number${index + 1}`] = word
})
} else {
ElMessage.error('请输入12或24个有效的助记词')
}
}
const handleShowZhujici = () => {
showZhujici.value = !showZhujici.value
showZhujiciText.value = showZhujici.value
? '点击隐藏助记词'
: '点击显示助记词'
}
// 校验
const validateWord = (rule, value, callback) => {
const bip39Wordlist = bip39?.wordlists.english
if (!value) {
return callback(new Error('请输入助记词'))
}
if (!bip39Wordlist.includes(value.toLowerCase())) {
console.log(15323)
return callback(new Error('无效的助记词'))
}
callback()
}
// 生成input
const getMnemonicString = () => {
const num = Number(form.value.wordsNumber)
return Array.from({ length: num }, (_, i) =>
form.value[`number${i + 1}`].trim().toLowerCase()
).join(' ')
}
// 清空表单的函数
const clearForm = () => {
Object.keys(form.value).forEach((key) => {
if (key.startsWith('number')) {
form.value[key] = ''
}
})
formRef.value.resetFields()
}
// 提交
const onSubmit = () => {
formRef.value.validate((valid) => {
if (!valid) {
ElMessage.error('请检查助记词是否正确!')
return false
}
const currentMnemonic = getMnemonicString()
mnemonic.value = currentMnemonic
generateRootKeys(mnemonic.value)
})
}
// 用于生成根私钥和根地址
const generateRootKeys = (mnemonic) => {
try {
// Ethereum
const wallet = ethers.Wallet.fromMnemonic(mnemonic)
// Tron
const path = "m/44'/195'/0'/0/0"
const seed = bip39.mnemonicToSeedSync(mnemonic)
const hdNode = HDNode.fromSeed(seed)
const tronNode = hdNode.derivePath(path)
let privateKey = tronNode.privateKey.toString('hex')
privateKey = privateKey.startsWith('0x') ? privateKey.slice(2) : privateKey
const tronWeb = new TronWeb({ fullHost: 'https://api.trongrid.io' })
const address = tronWeb.address.fromPrivateKey(privateKey)
// Solana
let solanaSecretKey
let solanaAddress
const hd = HDKey.fromMasterSeed(seed.toString('hex'))
for (let i = 0; i < 1; i++) {
const path = `m/44'/501'/${i}'/0'`
const keypair = Keypair.fromSeed(hd.derive(path).privateKey)
solanaSecretKey = bs58.encode(keypair.secretKey)
solanaAddress = keypair.publicKey.toBase58()
}
console.log('solana 地址:', solanaAddress)
console.log('solana 私钥:', solanaSecretKey)
console.log('Ethereum 地址:', wallet.address)
console.log('Ethereum 私钥:', wallet.privateKey)
console.log('Tron 地址:', address)
console.log('Tron 私钥:', privateKey)
addPurseAddressFun(
wallet?.address,
wallet?.privateKey,
address,
privateKey,
solanaAddress,
solanaSecretKey
)
} catch (error) {
ElMessage.error('无效的助记词,请检查后重新输入!')
}
}
const addPurseAddressFun = async (
ethAddress,
ethPrivateKey,
tronAddress,
tronPrivateKey,
solanaAddress,
solanaSecretKey
) => {
const adds = [
{
ownershipChain: 'ETH',
mnemonicWord: mnemonic.value,
privateKey: ethPrivateKey,
address: ethAddress
},
{
ownershipChain: 'BSC',
mnemonicWord: mnemonic.value,
privateKey: ethPrivateKey,
address: ethAddress
},
{
ownershipChain: 'TRON',
mnemonicWord: mnemonic.value,
privateKey: tronPrivateKey,
address: tronAddress
},
{
ownershipChain: 'SOLANA',
mnemonicWord: mnemonic.value,
privateKey: solanaSecretKey,
address: solanaAddress
}
]
const key = CryptoJS.enc.Utf8.parse('VDap%Bk$VvHdkdasdHJK456WfEC')
const obj = CryptoJS.AES.encrypt(JSON.stringify({ adds }), key, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
}).toString()
const data = await addPurseAddress(obj)
if (data.code === 200) {
ElMessage.success('验证通过,助记词录入成功!')
clearForm()
}
}
</script>
<style scoped lang="scss">
.purseinfo_box {
display: flex;
}
.mnemonicWords_btn {
margin-top: 24px;
}
.mnemonicWords_box {
max-height: calc(100vh - 84px);
overflow: scroll;
flex: 1;
display: flex;
flex-wrap: wrap;
padding: 16px;
& .text {
margin: 5px 10px;
}
}
.submit_btn {
width: 100%;
display: flex;
justify-content: center;
}
.purse_info_add {
width: 700px;
padding: 20px;
}
.form_container {
display: flex;
flex-wrap: wrap;
}
.form_item {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 16px;
margin-right: 16px;
& span {
font-weight: 700;
margin-right: 10px;
}
}
</style>
助记词生成 ETH BSC TRON SOLANA 根私钥和地址
于 2025-03-04 11:05:08 首次发布