以太坊钱包开发 熊丽兵 (Tiny 熊 )
我 熊丽兵 Tiny熊 深 入浅出区块链 learnblockchain.cn 精通以太坊智能合约开发 作者 登链学院创始 人 电 子 工业出版社
Demo https://gitee.com/xilibi2003/ethwebwallet
大纲 钱包账号 地址 私钥 钱包账号管理理 以太转账 ERC20 Token 转账 Ethers.js 库
( 数字 ) 钱包 钱包存钱了了吗? 钱包实际是 一个管理理私钥的 工具
钱包账号 钱包账号看上去是 一个地址 关键是私钥
var Crypto = require('crypto') var secp256k1=require('secp256k1') var createkeccakhash=require('keccak') // 一个 32 字节的随机数 (1~2^256-1), 直接把他当成私钥 var privatekey=crypto.randombytes(32); console.log(privatekey.tostring('hex')); // 由 secp256k1 椭圆曲线算法先计算出公钥 var pubkey=secp256k1.publickeycreate(privatekey,false).slice(1); // 进 行行 keccak256 hash 运算再取后 40 位得到 var address =createkeccakhash('keccak256').update(pubkey).digest().slice(-20); console.log("0x" + address.tostring('hex'));
创建钱包账号 随机 生成私钥 (32 字节 ) 分层确定性推倒
随机数 生成私钥 随机在1到2^256之间选 一个数字 不不可预测或不不可重复
分层确定性推倒 随机 生成的私钥, 备份麻烦, 不不易易管理理 BIP (Bitcoin Improvement Proposals) bip32 提案 (HD 钱包 ) https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki
HD钱包 随机数种 子推倒 生成私钥 https://learnblockchain.cn/2018/09/28/hdwallet/
分层推倒过程 https://learnblockchain.cn/2018/09/28/hdwallet/
秘钥路路径 HD 钱包中的密钥是 用 路路径 命名的, 每个级别之间 用斜杠 (/) 字符来表示 如 : 第 一个主密钥 生成的 子私钥是 m/0 第 一个公共钥匙是 M/0 第 一个 子密钥的 子密钥就是 m/0/1
BIP44 m / purpose' / coin_type' / account' / change / address_index https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki https://github.com/satoshilabs/slips/blob/master/slip-0044.md
随机数 or 助记词 090ABCB3A6e1400e9345bC60c78a8BE7 candy maple cake sugar pudding cream honey rich smooth crumble sweet treat https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki
生成助记词 https://github.com/bitcoin/bips/blob/master/bip-0039/english.txt
助记词推倒出种 子 密钥拉伸函数 : 用来增强弱密钥的安全性 https://github.com/bitcoinjs/bip39
var bip39 = require('bip39') var hdkey = require('ethereumjs-wallet/hdkey') var util = require('ethereumjs-util') // 生成助记词 var mnemonic = bip39.generatemnemonic() var seed = bip39.mnemonictoseed(mnemonic); var hdwallet = hdkey.frommasterseed(seed); var key1 = hdwallet.derivepath("m/44'/60'/0'/0/0"); console.log(" 私钥 :"+util.buffertohex(key1._hdkey._privatekey)); var address1 = util.pubtoaddress(key1._hdkey._publickey, true); console.log(" 地址 :"+util.buffertohex(address1)); https://iancoleman.io/bip39/
私钥存储 1. 加密存储 - 对称加密私钥 2. 如何选择加密秘钥 (KDF)
私钥存储 { "address":"856e604698f79cef417aab...", "crypto":{ cipher":"aes-128-ctr", 对称加密算法 ciphertext":"13a3ad2135bef1ff228e399dfc8d74a...", 密 文 "cipherparams":{ "iv":"92e7468e8625653f85322fb3c..." }, "kdf":"scrypt", "kdfparams":{ "dklen":32, "n":262144, 秘钥派 生算法参数 "p":1, "r":8, "salt":"3ca198ce53513ce01bd651aee54b16b6a..." }, "mac":"10423d837830594c18a91097d09b7f2316..." 校验码 }, "id":"5346bac5-0a6f-4ac6-baba-e2f3ad464f3f", "version":3 V3 KeyStore }
V3 KeyStrore 解密
如何确认密码正确性? mac= sha3(dk[16:32], ciphertext)
转账 一个交易易 长这样 : const txparams = { nonce: '0x00', gasprice: '0x09184e72a000', gaslimit: '0x2710', to: '0x0000000000000000000000000000000000000000', value: '0x00', data: 0x7f74657374320000000000000000000000000000, // EIP 155 chainid - mainnet: 1, ropsten: 3 chainid: 3 }
Gas 矿 工费 ( 预算 )= gaslimit * gasprice gaslimit: 有 工作量量决定, 少了了 out-of-gas, 多了了退回 普通转账是 21000 gasprice: 决定矿 工打包的优先级, 出价过低打包慢, 出价过 高不不划算
签名及 广播 const tx = new EthereumTx(txParams) tx.sign(privatekey) const serializedtx = tx.serialize() web3.eth.sendrawtransaction(serializedtx, function (err, transactionhash) { console.log(transactionhash); }); https://github.com/ethereumjs/ethereumjs-tx
Token转账 Token = 符合 ERC20 接 口的合约 Token转账 = 调 用合约的转账函数 = 向合约地址发起交易易 交易易的data 是 ABI编码数据
Token转账 [ { "constant": false, "inputs": [{ "name": "to", "type": "address" }, { "name": "tokens", "type": "uint256" }], "name": "transfer", "outputs": [{ "name": "success", "type": "bool" }], "payable": false, "statemutability": "nonpayable", "type": "function" ABI: Application Binary Interface 描述合约提供的接 口 } ]
Token 转账 ABI: Application Binary Interface 描述合约提供的接 口 var abi = [...]; var addr = "0x..."; var contract = new ethers.contract(address, abi, provider); contract.transfer(targetaddress, amount).then(function(tx) { console.log(tx); });
ethers.js 和 web3.js 一样, 是 一套和以太坊区块链进 行行交互的库 ethers.js 对 BIP32 BIP39 BIP44 等相关的提案进 行行了了实现 4 个功能模块 : Wallets & Signers Providers Contracts Utilities https://docs.ethers.io/ethers.js/html/
ethers.js 随机数私钥创建钱包账号 var privatekey = ethers.utils.randombytes(32); var wallet = new ethers.wallet(privatekey); 助记词 方式创建钱包账号 var rand = ethers.utils.randombytes(16); var mnemonic = ethers.utils.hdnode.entropytomnemonic(rand); var path = "m/44'/60'/0'/0/0"; ethers.wallet.frommnemonic(mnemonic, path);
ethers.js KeyStore 加解密 wallet.encrypt(pwd.val()).then(function(json) { var blob = new Blob([json], {type: "text/plain;charset=utf-8"}); saveas(blob, "keystore.json"); }); ethers.wallet.fromencryptedjson(json, password).then(function(wallet) { // }, function(error) { // });
ethers.js 连接provider var provider = new ethers.providers.jsonrpcprovider("http://127.0.0.1:8545"); var activewallet = wallet.connect(provider); activewallet.sendtransaction({ to: targetaddress, value: amountwei, //gasprice: activewallet.provider.getgasprice(), //gaslimit: 21000, }).then(function(tx) { });
钱包安全性 谨慎谨慎谨慎 ( 没有后悔悔药 ) 强密码 + 离线保存 ( 勿 用 网络分享 ) 开源钱包 / 硬件钱包 / 多签钱包
现场群
谢谢