https://github.com/trufflesuite/truffle-hdwallet-provider/blob/master/index.js

实现代码

truffle-hdwallet-provider/index.js

const bip39 = require("bip39");
const ethJSWallet = require('ethereumjs-wallet');
const hdkey = require('ethereumjs-wallet/hdkey');
const debug = require('debug')('truffle-hdwallet-provider')
const ProviderEngine = require("web3-provider-engine");
const FiltersSubprovider = require('web3-provider-engine/subproviders/filters.js');
const NonceSubProvider = require('web3-provider-engine/subproviders/nonce-tracker.js');
const HookedSubprovider = require('web3-provider-engine/subproviders/hooked-wallet.js');
const ProviderSubprovider = require("web3-provider-engine/subproviders/provider.js");
const Web3 = require("web3");
const Transaction = require('ethereumjs-tx');
const ethUtil = require('ethereumjs-util');// This line shares nonce state across multiple provider instances. Necessary
// because within truffle the wallet is repeatedly newed if it's declared in the config within a
// function, resetting nonce from tx to tx. An instance can opt out
// of this behavior by passing `shareNonce=false` to the constructor.
// See issue #65 for more
const singletonNonceSubProvider = new NonceSubProvider();function HDWalletProvider(mnemonic,provider,address_index=0,//从给的mnemonic数组的第几下标开始取num_addresses=1,//取里面的几个mnemonic,即生成几个addressshareNonce=true, //共享nonce状态,这样钱包进行刷新时nonce值还是原来的值wallet_hdpath="m/44'/60'/0'/0/"//指明到第四层,即上面的操作是要在该账户的外链上生成num_addresses个公钥
) {if (mnemonic && mnemonic.indexOf(' ') === -1 || Array.isArray(mnemonic)) {//传入的是privateKey,一个或多个(数组)const privateKeys = Array.isArray(mnemonic) ? mnemonic : [mnemonic];//如果是一个也要将其转成数组形式this.wallets = {};this.addresses = [];for (let i = address_index; i < address_index + num_addresses; i++){const privateKey = Buffer.from(privateKeys[i].replace('0x', ''), 'hex');//将privateKey转成Buffer格式if (ethUtil.isValidPrivate(privateKey)) {//查看privateKey是否正确const wallet = ethJSWallet.fromPrivateKey(privateKey);//正确则能从主私钥得到walletconst address = wallet.getAddressString();//得到wallet的addressthis.addresses.push(address);//并记录到wallets和addresses中this.wallets[address] = wallet;}}} else {//否则传入的就是一个mnemonicthis.mnemonic = mnemonic;this.hdwallet = hdkey.fromMasterSeed(bip39.mnemonicToSeed(mnemonic));//根据mnemonic生成hdwalletthis.wallet_hdpath = wallet_hdpath;this.wallets = {};this.addresses = [];if (!bip39.validateMnemonic(mnemonic)) {//如果mnemonic不对则报错throw new Error("Mnemonic invalid or undefined")}for (let i = address_index; i < address_index + num_addresses; i++){const wallet = this.hdwallet.derivePath(this.wallet_hdpath + i).getWallet();// getWallet()-return a Wallet instance,这样这个m/44'/60'/0'/0/i就能够使用Wallet的API了const addr = '0x' + wallet.getAddress().toString('hex');//得到m/44'/60'/0'/0/i的addressthis.addresses.push(addr);//并记录下来this.wallets[addr] = wallet;}}//得到上面根据privateKey和mnemonic生成的账户address和walletconst tmp_accounts = this.addresses;const tmp_wallets = this.wallets;this.engine = new ProviderEngine();this.engine.addProvider(new HookedSubprovider({ //先将HookedSubprovider添加进engine,并定义能够进行的rpc操作getAccounts: function(cb) { cb(null, tmp_accounts) },getPrivateKey: function(address, cb) {if (!tmp_wallets[address]) { return cb('Account not found'); }else { cb(null, tmp_wallets[address].getPrivateKey().toString('hex')); }},signTransaction: function(txParams, cb) {let pkey;const from = txParams.from.toLowerCase()if (tmp_wallets[from]) { pkey = tmp_wallets[from].getPrivateKey(); }else { cb('Account not found'); }const tx = new Transaction(txParams);tx.sign(pkey);const rawTx = '0x' + tx.serialize().toString('hex');cb(null, rawTx);},signMessage(message, cb) {const dataIfExists = message.data;if (!dataIfExists) {cb('No data to sign');}if (!tmp_wallets[message.from]) {cb('Account not found');}let pkey = tmp_wallets[message.from].getPrivateKey();const dataBuff = ethUtil.toBuffer(dataIfExists);const msgHashBuff = ethUtil.hashPersonalMessage(dataBuff);const sig = ethUtil.ecsign(msgHashBuff, pkey);const rpcSig = ethUtil.toRpcSig(sig.v, sig.r, sig.s);cb(null, rpcSig);}             }));(!shareNonce)//NonceSubProvider在HookedSubprovider和ProviderSubprovider之间被添加,以免多个钱包处理同一类数字资产的情况下同时生成交易时会导致nonce值相同造成冲突? this.engine.addProvider(new NonceSubProvider())//如果shareNonce = false,不共享nonce值,则添加的NonceSubProvider为局部对象: this.engine.addProvider(singletonNonceSubProvider);////如果shareNonce = true,共享nonce值,则添加的singletonNonceSubProvider为全局常量this.engine.addProvider(new FiltersSubprovider());//添加FiltersSubproviderif (typeof provider === 'string') {//添加ProviderSubproviderthis.engine.addProvider(new ProviderSubprovider(new Web3.providers.HttpProvider(provider)));} else {this.engine.addProvider(new ProviderSubprovider(provider));}this.engine.start(); // Required by the provider engine.
};HDWalletProvider.prototype.sendAsync = function() {this.engine.sendAsync.apply(this.engine, arguments);
};HDWalletProvider.prototype.send = function() {return this.engine.send.apply(this.engine, arguments);
};// returns the address of the given address_index, first checking the cache
HDWalletProvider.prototype.getAddress = function(idx) {debug('getting addresses', this.addresses[0], idx)if (!idx) { return this.addresses[0]; }else { return this.addresses[idx]; }
}// returns the addresses cache
HDWalletProvider.prototype.getAddresses = function() {return this.addresses;
}module.exports = HDWalletProvider;

使用:

安装:

npm install truffle-hdwallet-provider
//+ truffle-hdwallet-provider@0.0.6

var HDWalletProvider = require("truffle-hdwallet-provider");
var Web3 = require("web3");
var web3 = new Web3();
const mnemonic = 'candy maple cake sugar pudding cream honey rich smooth crumble sweet treat';
var provider = new HDWalletProvider(mnemonic, "http://localhost:8202", 0, 1);
console.log(provider.getAddresses());
web3.setProvider(provider);
web3.eth.getBlockNumber((err, number) => {console.log(number);
});
// At termination, `provider.engine.stop()' should be called to finish the process elegantly.
provider.engine.stop();//一定要记得添加
//不能运行下面的内容,因为Error: Web3ProviderEngine does not support synchronous requests.
// web3.eth.coinbase((err, coinbase) => {
//     console.log(coinbase);
// });
// web3.eth.mining((err, state) => {
//     console.log(state);
// });

返回:

就成功生成了m/44'/60'/0'/0/0的address

userdeMacBook-Pro:test-hd-wallet user$ node index.js
[ '0x627306090abab3a6e1400e9345bc60c78a8bef57' ]
301

如果改成:

var provider = new HDWalletProvider(mnemonic, "http://localhost:8202", 0, 5);

则为:

userdeMacBook-Pro:test-hd-wallet user$ node index.js
[ '0x627306090abab3a6e1400e9345bc60c78a8bef57','0xf17f52151ebef6c7334fad080c5704d77216b732','0xc5fdf4076b8f3a5357c5e395ab970b5b54098fef','0x821aea9a577a9b44299b9c15c88cf3087f3b5544','0x0d1d4e623d10f9fba5db95830f7d3839406c6af2' ]
301

在geth中运行sendTransaction后:

> web3.eth.sendTransaction({from:eth.accounts[0],to:'0x627306090abab3a6e1400e9345bc60c78a8bef57',value:web3.toWei(4,'ether')})
"0xd45b223fa40b36b214f178bb2c343d8a9cc7c94a7bbfacd8d69efd297f346786"

再查看账户余额:

var addresses = provider.getAddresses();
console.log(addresses);
web3.setProvider(provider);
web3.eth.getBlockNumber((err, number) => {console.log(number);
});
web3.eth.getBalance(addresses[0],(err,balance) => {if(!err){console.log(balance.toString());        }
});

返回:

userdeMacBook-Pro:test-hd-wallet user$ node index.js
[ '0x627306090abab3a6e1400e9345bc60c78a8bef57','0xf17f52151ebef6c7334fad080c5704d77216b732','0xc5fdf4076b8f3a5357c5e395ab970b5b54098fef','0x821aea9a577a9b44299b9c15c88cf3087f3b5544','0x0d1d4e623d10f9fba5db95830f7d3839406c6af2' ]
4000000000000000000
328

接下来部署一个合约看看:

var HDWalletProvider = require("truffle-hdwallet-provider");
var Web3 = require("web3");
const fs = require("fs");
const solc = require("solc");var web3 = new Web3();
const mnemonic = 'candy maple cake sugar pudding cream honey rich smooth crumble sweet treat';
var provider = new HDWalletProvider(mnemonic, "http://localhost:8202", 0, 5);
var addresses = provider.getAddresses();
// console.log(addresses);
web3.setProvider(provider);
web3.eth.getBlockNumber((err, number) => {console.log(number);
});
web3.eth.getBalance(addresses[0],(err,balance) => {if(!err){console.log(balance.toString());        }
});let source = fs.readFileSync("./Adoption.sol",'utf8');//读取sol智能合约文件
//对智能合约进行编译,第二个参数设置为1可以激活优化器optimiser
let compiledContract = solc.compile(source,1);
var bytecode,abi;
for (let contractName in compiledContract.contracts) {bytecode = compiledContract.contracts[contractName].bytecode;//获得编译后合约的bytecode
    console.log(bytecode)abi = JSON.parse(compiledContract.contracts[contractName].interface); //获得编译后合约的abi并写成json形式
    console.log(abi)
}let MyContract = web3.eth.contract(abi);
var instance = MyContract.new({from:addresses[0],data:'0x'+bytecode,gas:30000000},function(e,contract){if(typeof contract.address !== 'undefined'){console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash);}else{console.log(e);}
});setTimeout(()=>{web3.eth.getBalance(addresses[0],(err,balance) => {if(!err){console.log(balance.toString());        }})
},3000);

部署完之后就可以直接使用该合约:

var instance = MyContract.at('0xF12b5dd4EAD5F743C6BaA640B0216200e89B60Da');
instance.adopt(1,{from:addresses[0],gas:3000000},(err,result) => {if(!err){console.log(result);        }else{console.log(err);}
});

然后再调用:

instance.getAdopters({gas:3000000},(err,result) =>{if(!err){console.log(result);        }else{console.log(err);}
});

可以得到结果:

[ '0x627306090abab3a6e1400e9345bc60c78a8bef57','0x627306090abab3a6e1400e9345bc60c78a8bef57','0x0000000000000000000000000000000000000000','0x0000000000000000000000000000000000000000','0x0000000000000000000000000000000000000000','0x0000000000000000000000000000000000000000','0x0000000000000000000000000000000000000000','0x0000000000000000000000000000000000000000','0x0000000000000000000000000000000000000000','0x0000000000000000000000000000000000000000','0x0000000000000000000000000000000000000000','0x0000000000000000000000000000000000000000','0x0000000000000000000000000000000000000000','0x0000000000000000000000000000000000000000','0x0000000000000000000000000000000000000000','0x0000000000000000000000000000000000000000' ]

转载于:https://www.cnblogs.com/wanghui-garcia/p/9985192.html

trufflesuite/truffle-hdwallet-provider相关推荐

  1. Truffle 4.0、Geth 1.7.2、TestRPC在私有链上搭建智能合约

    1.什么是 Truffle? Truffle 是最流行的开发框架,能够在本地编译.部署智能合约,使命是让开发更容易. Truffle 需要以太坊客户端支持,需要支持标准的JSON RPC API. 2 ...

  2. Truffle 、Geth、TestRPC 在私有链上搭建智能合约

    Truffle 的简介 Truffle 是最流行的开发框架,能够在本地编译.部署智能合约,使命是让开发更容易. Truffle 需要以太坊客户端支持,需要支持标准的 JSON RPC API. Tru ...

  3. truffle serve 发生异常解决办法

    2019独角兽企业重金招聘Python工程师标准>>> 安装步骤前几步都没有问题 mkdir demo001 # Create a folder for your new dapp ...

  4. day02 智能合约

    上午 1>部署智能合约网络 语法 require 2>利用第三方的节点 同步到以太坊 3>智能合约部署的步骤: 1.查看区块 2.发布合约 deploy后台经历的事情:就是部署合约的 ...

  5. 区块链以太坊以及hyperledger总结

    https://learnblockchain.cn/ 1.什么是智能合约?它有什么特点? 就是具有交互能力而且能够在区块链中传递的合约 一个由计算机代码控制的以太币账户 特点: 公开透明.能即时与区 ...

  6. 被5月GitHub Top20榜单惊呆了 原来区块链大佬都在做这个

    被5月GitHub Top20榜单惊呆了 原来区块链大佬都在做这个 GitHub 上项目的活跃指数,在一定程度上代表了这个项目的开发状态. 频繁更新代码的项目有可能正处于构建和完善中,而停止更新代码的 ...

  7. solidity return data和revert/require的reason string的获得

    前言: 在使用solidity写智能合约的时候,会使用到revert和require来进行断言,比如: require(tokenOwner[tokenId] == 0x0,'this is not ...

  8. Unbox failed! RequestError: Error: connect ETIMEDOUT 151.101.76.133:443

    truffle unbox 或者 init 时出现错误,估计很多可能是墙的原因,解决办法 部分博主说自己可以通过在当前文件夹下新建文件夹后,在新文件夹下可以进行正常操作: 修改hosts文件 http ...

  9. 学习区块链?github上的那些区块链项目

    一番码客 : 挖掘你关心的亮点. http://efonfighting.imwork.net 文章目录 前言 编程语言分布 star前十 中文资源 总结 今日一番 前言 当世界大部分人都还在问&qu ...

  10. 一文了解区块链开发最全技术资料!

    本文收集了所有区块链(BlockChain)技术开发的相关资料,包括 Fabric 和 Ethereum 开发资料,一应俱全,赶快 Mark 起来吧! 介绍 入门 区块链技术指南:区块链领域比较系统的 ...

最新文章

  1. [算法]一次商品交易利益最大化
  2. Markdown编辑器写博客
  3. 停用nfs导致cacti无法抓取snmp数据
  4. PHP LOG使用心得(2)
  5. 命令行里对SAP Spartacus执行命令ng test core
  6. HTML5常用标签及特殊字符表
  7. c语言中二分法100中找30,c语言中的二分法
  8. 【opencv】实时人脸+眼睛+微笑检测
  9. Getting Contexts 获得上下文
  10. 初识TensorFlow
  11. 如何将Blocs v2项目迁移到Blocs v3?
  12. 浅析jQuery源码
  13. 如何用sql语言只获得数据库当前日期,且格式为yyyy-mm-dd?
  14. DSP课设项目(ICETEK-VC5509-EDU)
  15. 考研数据结构程序题常见代码【C语言实现】
  16. 启动dubbo-admin遇到的那些坑
  17. 16进制 颜色透明度
  18. transform模板函数调用tolower函数报错原因、解决办法
  19. Mac一些基本常用快捷键的使用
  20. python将多个列表合并_Python中多个列表与字典的合并方法

热门文章

  1. spring boot 初始化表
  2. 用onSaveInstanceState()方法保存Activity状态
  3. bzoj 3528: [Zjoi2014]星系调查
  4. 解决ASP.NET MVC 下使用SQLite 报no such table的问题
  5. truncate delete 与 drop的区别
  6. jsp:include
  7. 利用Azure backup备份和恢复Azure虚拟机(1)
  8. HDU 4647 Another Graph Game
  9. Python学习笔记之if语句(三)
  10. Guava事件处理组件Eventbus使用入门