|
|
@@ -0,0 +1,141 @@
|
|
|
+import * as bip39 from 'bip39'
|
|
|
+import { BIP32Factory } from 'bip32'
|
|
|
+import * as bitcoin from 'bitcoinjs-lib'
|
|
|
+import { ethers } from 'ethers'
|
|
|
+import { TronWeb } from 'tronweb'
|
|
|
+import * as ecc from 'tiny-secp256k1'
|
|
|
+import Logger from '@ioc:Adonis/Core/Logger'
|
|
|
+
|
|
|
+const bip32 = BIP32Factory(ecc)
|
|
|
+
|
|
|
+class BlockchainWalletService {
|
|
|
+ /**
|
|
|
+ * 验证助记词是否有效
|
|
|
+ * @param mnemonic 助记词字符串
|
|
|
+ */
|
|
|
+ private validateMnemonic(mnemonic: string) {
|
|
|
+ if (!bip39.validateMnemonic(mnemonic)) {
|
|
|
+ throw new Error('Invalid mnemonic')
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据给定的路径派生子节点
|
|
|
+ * @param mnemonic 助记词字符串
|
|
|
+ * @param path 路径
|
|
|
+ */
|
|
|
+ private deriveChildNode(mnemonic: string, path: string) {
|
|
|
+ const seed = bip39.mnemonicToSeedSync(mnemonic)
|
|
|
+ const root = bip32.fromSeed(seed)
|
|
|
+ return root.derivePath(path)
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 生成比特币(BTC)地址
|
|
|
+ * @param mnemonic 助记词字符串
|
|
|
+ * @param accountIndex 账户索引,默认为0
|
|
|
+ * @param network 网络类型,默认为主网
|
|
|
+ * @returns BTC地址
|
|
|
+ */
|
|
|
+ public getBTCAddress(
|
|
|
+ mnemonic: string,
|
|
|
+ accountIndex: number = 0,
|
|
|
+ network = bitcoin.networks.bitcoin
|
|
|
+ ): string {
|
|
|
+ this.validateMnemonic(mnemonic)
|
|
|
+
|
|
|
+ // BIP44 路径: m/44'/0'/accountIndex'/0/0
|
|
|
+ const path = `m/44'/0'/${accountIndex}'/0/0`
|
|
|
+ const child = this.deriveChildNode(mnemonic, path)
|
|
|
+
|
|
|
+ const { address } = bitcoin.payments.p2pkh({
|
|
|
+ pubkey: Buffer.from(child.publicKey!),
|
|
|
+ network
|
|
|
+ })
|
|
|
+
|
|
|
+ return address || ''
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 生成以太坊(ETH)地址
|
|
|
+ * @param mnemonic 助记词字符串
|
|
|
+ * @param accountIndex 账户索引,默认为0
|
|
|
+ * @returns ETH地址
|
|
|
+ */
|
|
|
+ public getETHAddress(mnemonic: string, accountIndex: number = 0): string {
|
|
|
+ this.validateMnemonic(mnemonic)
|
|
|
+
|
|
|
+ // BIP44 路径: m/44'/60'/accountIndex'/0/0
|
|
|
+ const path = `m/44'/60'/${accountIndex}'/0/0`
|
|
|
+ const child = this.deriveChildNode(mnemonic, path)
|
|
|
+
|
|
|
+ if (!child.privateKey) {
|
|
|
+ Logger.error('Unable to derive private key')
|
|
|
+ return ''
|
|
|
+ }
|
|
|
+
|
|
|
+ const privateKeyHex = Buffer.from(child.privateKey).toString('hex')
|
|
|
+ const wallet = new ethers.Wallet(`0x${privateKeyHex}`)
|
|
|
+
|
|
|
+ return wallet.address
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 生成波场(TRON)地址
|
|
|
+ * @param mnemonic 助记词字符串
|
|
|
+ * @param accountIndex 账户索引,默认为0
|
|
|
+ * @returns TRON地址
|
|
|
+ */
|
|
|
+ public getTRONAddress(mnemonic: string, accountIndex: number = 0): string {
|
|
|
+ this.validateMnemonic(mnemonic)
|
|
|
+
|
|
|
+ // TRON 和 ETH 使用相同的 BIP44 路径,但地址格式不同
|
|
|
+ const path = `m/44'/195'/${accountIndex}'/0/0`
|
|
|
+ const child = this.deriveChildNode(mnemonic, path)
|
|
|
+
|
|
|
+ if (!child.privateKey) {
|
|
|
+ Logger.error('Unable to derive private key')
|
|
|
+ return ''
|
|
|
+ }
|
|
|
+
|
|
|
+ const privateKeyHex = Buffer.from(child.privateKey).toString('hex')
|
|
|
+
|
|
|
+ const tronWeb = new TronWeb({ fullHost: 'https://api.trongrid.io' })
|
|
|
+ const account = tronWeb.address.fromPrivateKey(privateKeyHex)
|
|
|
+
|
|
|
+ if (typeof account !== 'string') {
|
|
|
+ return ''
|
|
|
+ }
|
|
|
+
|
|
|
+ return account
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取所有支持的区块链地址
|
|
|
+ * @param mnemonic 助记词字符串
|
|
|
+ * @param accountIndex 账户索引,默认为0
|
|
|
+ * @returns 包含所有地址的对象
|
|
|
+ */
|
|
|
+ public async getAllAddresses(mnemonic: string, accountIndex: number = 0) {
|
|
|
+ const data = {
|
|
|
+ btc: '',
|
|
|
+ eth: '',
|
|
|
+ tron: ''
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ const [btc, eth, tron] = await Promise.all([
|
|
|
+ this.getBTCAddress(mnemonic, accountIndex),
|
|
|
+ this.getETHAddress(mnemonic, accountIndex),
|
|
|
+ this.getTRONAddress(mnemonic, accountIndex)
|
|
|
+ ])
|
|
|
+ data.btc = btc
|
|
|
+ data.eth = eth
|
|
|
+ data.tron = tron
|
|
|
+ } catch (error) {
|
|
|
+ Logger.error(`Failed to get addresses: ${error.message}`)
|
|
|
+ }
|
|
|
+ return data
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+export default new BlockchainWalletService()
|