DApp创建本地钱包并实现签名转账(BSC,Polygon,ETH)


前端创建本地钱包并实现签名转账(BSC,Polygon,ETH)

1. 项目准备

  1. 安装ether.js
npm install --save ethers

引入ether.js:的三种方法

  • es3:
var ethers = require(‘ethers’);
  • es5/es6
const ethers = require(‘ethers’);
  • javascript/typescript es6
import ethers from ‘ethers’;

2. 钱包相关概念

这里默认为你已经了解 地址、密码、私钥、助记词、Keystore 之间的关系,所以不再过多介绍,只列出他们之间的关联:

地址 = 银行卡号

密码 = 银行卡密码

私钥 = 银行卡号+密码

助记词 = 银行卡号+密码

Keystore = 加密私钥

Keystore + 密码 = 私钥

3.随机创建一个钱包

使用到的ethers的Wallet类:

ethers.Wallet.createRandom()

createRandom 返回一个带有随机私钥的新钱包,由加密安全的熵源生成。如果当前环境没有安全的熵源,则会抛出错误。
使用此方法创建的钱包将具有助记词

  createNewWallet() {

    let walletRandom = ethers.Wallet.createRandom()
    // 钱包助记词对象
    let mnemonic = walletRandom.mnemonic
    
    //钱包助记词单词
    let phrase = mnemonic.phrase
    
    //path: "m/44'/60'/0'/0/0",
    let path = mnemonic.path
    
    //钱包地址
    let address = walletRandom.address
    
    //钱包公钥
    let publicKey = walletRandom.publicKey
    
    //钱包私钥
    let privateKey = walletRandom.privateKey
    
    //通过用户设置的密码生成keystore文件
    let password = "123456"
    walletRandom.encrypt(password).then((keystory_string) => {
      let keystory_json = JSON.parse(keystory_string)
      //钱包的keystore字符串
      this.keystory = keystory_string
      console.log(keystory_json)
    })
	
	//可以通过AES对称加密把钱包的助记词加密存储在本地
	let encryptPassword = "1234qwer"
    let encryptedPhrase = encryption(phrase, encryptPassword)
    console.log('加密后的助记词:', encryptedPhrase)
    
    let decryptedPhrase = decryption(encryptedPhrase, encryptPassword)
    console.log('解密后的助记词:', decryptedPhrase)
  }
import * as CryptoJS from 'crypto-js'

//数据对称加密
function encryption(data, password) {
  let encrypted = CryptoJS.AES.encrypt(data, password);
  return encrypted.toString()
}

//数据解密
function decryption(encrypted, password) {
  let decrypted = CryptoJS.AES.decrypt(encrypted, password);
  return decrypted.toString(CryptoJS.enc.Utf8);
}

4.根据助记词导入钱包

  ethers.Wallet.fromMnemonic( mnemonic [ , path , [ wordlist ] ] ) ⇒ Wallet

从助记短语中创建实例。

如果没有指定path,则使用以太坊的默认path路径(如m/44’/60’/0’/0/0).

如果不指定wordlist,则使用English Wordlist。

  async createWalletByPhrase() {
  	//默认路径
    let path = ethers.utils.defaultPath

	//要导入的钱包助记词
    let phrase =
      'able fee damage express dilemma visit fine claim similar attract awkward market'
    let mnemonic = ethers.Wallet.fromMnemonic(phrase)

	//钱包私钥
    let privateKey = mnemonic.privateKey
	
	//通过钱包私钥创建钱包实例
    let wallet = new ethers.Wallet(privateKey)
    
    //钱包公钥
    let publicKey = wallet.publicKey

	//钱包地址
    let address = wallet.address

	//通过用户设置的密码生成keystore文件
    let password = "123456"
    wallet.encrypt(password).then((keystory_string) => {
      let keystory_json = JSON.parse(keystory_string)
      let keystory = keystory_string
      console.log(keystory_json)
    })
  }

5.根据keystore导入钱包

ethers.Wallet.fromEncryptedJson( json , password [ , progress ] ) ⇒ Promise< Wallet >source

从加密的JSON钱包创建一个实例。

如果提供了进度,它将在解密期间被调用,其值介于0到1之间,表示一个完成进度。

  createWalletByKeystory() {
  	
  	//要导入的钱包keystore
    let keystory =
      '{"address":"df9e902814baba3ddc6b4a1ac9db11bc79eda07f","id":"60db3db5-ef64-400a-b25e-3615a9bdfa24","version":3,"crypto":{"cipher":"aes-128-ctr","cipherparams":{"iv":"f4c7ece791d112dc408537203aa2bb10"},"ciphertext":"acba3333e3d7078e2186ebd561c28bf0e4a8c105e4b1eec40bec20616441cc31","kdf":"scrypt","kdfparams":{"salt":"f1e8acd43868559c1ecda1c9b31489efd12f6c7c9302710b957a3b779dd6ec54","n":131072,"dklen":32,"p":1,"r":8},"mac":"e466473ae761f98b1f26354e27305ce23e41b5d5c8a5674b65675bdfbf848718"},"x-ethers":{"client":"ethers.js","gethFilename":"UTC--2023-03-25T03-36-38.0Z--df9e902814baba3ddc6b4a1ac9db11bc79eda07f","mnemonicCounter":"e4482220566b9a9f9d821c1352d1708f","mnemonicCiphertext":"7357682acae64479641611e17e1c6473","path":"m/44'/60'/0'/0/0","locale":"en","version":"0.1"}}'
      
     //改keystore创建时使用的密码
     let password = "123456"
      
    ethers.Wallet.fromEncryptedJson(keystory, password).then((wallet) => {
      console.log('wallet实例:', wallet)

	  //钱包地址
      let address = wallet.address
      //钱包公钥
      let publicKey = wallet.publicKey
      //钱包私钥
      let privateKey = wallet.privateKey
      //默认的路径
      let path = ethers.utils.defaultPath
    })
  }

6.签名转账

  async sendTransaction() {
  	//ETH
    // let network = 'goerli'
    // let contractAddress = ''

	//Polygon
    // let network = 'maticmum'
    // let contractAddress = ''

	//BSC
    // let network = 'https://bsc-dataseed.binance.org/'
    let network = 'https://data-seed-prebsc-1-s1.binance.org:8545/'
    let contractAddress = ''

	//使用Infura作为RPC使用
	//let projectId = ''
    // let provider = new ethers.providers.InfuraProvider(network, projectId)
    let provider = new ethers.providers.JsonRpcProvider(network);
    let privateKey = '0x0fb9146e20a3bd3497b47de967316c8aa7f83818ddc62429a24774f0df1f8065'
    let wallet = new ethers.Wallet(privateKey, provider)
    // let balance = await wallet.getBalance('latest')
    // console.log('余额:', balance)
    // console.log('余额:', ethers.utils.formatEther(balance))
    // console.log(await wallet.getChainId())
    // return
    /**
    //ETH转账
    let tx = {
      to: '',
      value: ethers.utils.parseEther('0.001'),
      chainId: ethers.BigNumber.from('5').toHexString()
    }
    let res = await wallet.sendTransaction(tx)
    console.log(res)
     */

    /**
     *
    //使用signers进行ERC20转账
    let contract = new ethers.Contract(contractAddress, GBK.abi, wallet)
    console.log(contract)
    let balance = await contract.balanceOf(wallet.address)
    balance = ethers.utils.formatEther(balance)
    console.log(balance)
    let res = await contract.transfer('', ethers.utils.parseUnits('1'))
    console.log(res)
     */
  }