助记词生成 ETH BSC TRON SOLANA 根私钥和地址

<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>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值