首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >将Trezor (硬件钱包)与Web3js一起使用在松露或粗纱上

将Trezor (硬件钱包)与Web3js一起使用在松露或粗纱上
EN

Ethereum用户
提问于 2018-06-09 20:44:52
回答 2查看 2K关注 0票数 2

我们正在尝试将web3js与Trezor集成到松露开发网络中,或者使用ropsten测试网络。

其思想是使用硬件钱包对事务进行签名,然后使用web3js发送原始事务。

我们得到的是,我们没有馀额来进行交易,可能是因为web3js没有使用10个松露帐户中的一个,而是使用不在我本地网络中的trezor地址。

我有一些以太,我得到了“无效地址”

是否有方法使用web3js将签名的事务(与trezor一起)发送到松露开发网络?我是说,有没有办法把trezor地址包含到松露网络中?

松露的情况在这里有更详细的解释,但问题可以概括为“有办法将硬件钱包纳入松露开发网络吗?”:https://github.com/trufflesuite/truffle/issues/973

使用ropsten,我们成功地发送了一个事务,并在回调中接收了一个事务散列,但是如果我们查询该事务,就会得到事务不存在。所以..。那件事怎么可能?

我们也尝试过将一个契约部署到Ropsten中,现在我们在调用智能契约函数时得到了“无效地址”。也许签名函数是错的?任何人都可以将Trezor事务与web3js进行集成吗?

你们认为我们所遵循的签约和发送过程中有什么问题吗?也许R,V和S的参数处理有什么问题..。

另一件重要的事情是,我们使用https://github.com/ethereumjs/ethereumjs-tx来创建原始事务。

发布于web3js、块菌和trezzor中,与更多信息连接:

亲切问候

代码语言:javascript
复制
 trezorLogin = async()=> {
        let trezor=  await this.getTrezor();

        // site icon, optional. at least 48x48px
        var hosticon = 'https://doc.satoshilabs.com/trezor-apps/_images/copay_logo.png';
        // server-side generated and randomized challenges
        var challenge_hidden = '';
        var challenge_visual = '';
        //use anonimous functions on callback otherwise returns cross origin errors
        trezor.requestLogin(hosticon, challenge_hidden, challenge_visual, function (result){
            if (result.success) {
                console.log('Public key:', result.public_key); // pubkey in hex
                console.log('Signature:', result.signature); // signature in hex
                console.log('Version 2:', result.version === 2); // version field
                console.log(result);
            }else {
                console.error('Error:', result.error);
            }
        });}


    trezorSignTx= async(transaction)=> {
        let trezor=  await this.getTrezor();
        // spend one change output
        var address_n = "m/44'/60'/0'/0/0"
        // var address_n = [44 | 0x80000000,
        //                  60 | 0x80000000,
        //                  0  | 0x80000000 ,
        //                  0 ]; // same, in raw form
        var nonce = transaction.nonce.substring(2); // note - it is hex, not number!!!
        var gas_price = transaction.gasPrice.substring(2);
        var gas_limit = transaction.gasLimit.substring(2);
        var to = transaction.to.substring(2);
        // var value = '01'; // in hexadecimal, in wei - this is 1 wei
        var value = transaction.value.substring(2); // in hexadecimal, in wei - this is about 18 ETC
        var data = transaction.data.substring(2); // some contract data
        // var data = null  // for no data
        var chain_id = 5777; // 1 for ETH, 61 for ETC
        return new Promise (function (resolve,reject) {
            trezor.ethereumSignTx(
                address_n,
                nonce,
                gas_price,
                gas_limit,
                to,
                value,
                data,
                chain_id,
                function (response) {
                    if (response.success) {

                        console.log('Signature V (recovery parameter):', response.v); // number
                        console.log('Signature R component:', response.r); // bytes
                        console.log('Signature S component:', response.s); // bytes
                        resolve(response);

                    } else {
                        console.error('Error:', response.error); // error message
                        resolve(null);
                    }

                });
        })
    }

    getTrezorAddress = async() => {
        let trezor=  await this.getTrezor();
        // spend one change output
        var address_n = "m/44'/60'/0'/0/0";
        trezor.ethereumGetAddress(address_n, function (result) {
            if (result.success) { // success
                console.log('Address: ', result.address);
            } else {
                console.error('Error:', result.error); // error message
            }
        });
    }


    getTrezor = async() => {
        let trezorC;
        await getTrezorConnect
            .then(trezorConnect => {
                trezorC= trezorConnect;
            })
            .catch((error) => {
                console.log(error)
            })
        return trezorC;

    }

 sendTransaction= async(address, amount, id)=>{
        let tokenInstance = this.props.smartContractInstance;

        var getData = tokenInstance.mint.getData(address, amount);

        var tx = {
            nonce: '0x00',
            gasPrice: '0x09184e72a000',
            gasLimit: '0x2710',
            to: CONTRACT_ADDRESS,
            value: '0x00',
            from:CONTRACT_OWNER_ADDRESS,
            data: getData
        };
        let response = await this.trezorSignTx(tx);

        let web3;
        let _this = this;
        if (response!=null){
            getWeb3
                .then(results => {
                    web3= results.web3;
                    let v = response.v.toString();
                    if (v.length % 2 != 0){
                        v="0"+v;
                    }
                    tx.r=Buffer.from(response.r,'hex');
                    tx.v=Buffer.from(v,'hex');
                    tx.s=Buffer.from(response.s,'hex');
                    let ethtx = new ethereumjs(tx);
                    console.dir(ethtx.getSenderAddress().toString('hex'), );
                    const serializedTx = ethtx.serialize();
                    const rawTx = '0x' + serializedTx.toString('hex');
                    console.log(rawTx);
                    //finally pass this data parameter to send Transaction
                    web3.eth.sendRawTransaction(rawTx, function (error, result) {
                        if(!error){
                            _this.props.addTokens(id)
                                .then(()=>{
                                        _this.setState({modalOpen: true});
                                        _this.props.getAllTransactions();
                                    }
                                );
                        }else{
                            alert(error)
                        }
                    });
                })
                .catch((error) => {
                    console.log(error)
                })
        }else{
            alert("There was an error signing with trezor hardware wallet")
        }


    }

getTrezorConnect函数只是异步地获取window.trezorConnect,因为对象被注入为脚本

代码语言:javascript
复制
<script src="https://connect.trezor.io/4/connect.js"></script>
EN

回答 2

Ethereum用户

回答已采纳

发布于 2018-06-14 16:55:31

经过多次尝试,我们成功地将一份与Trezor签署的原始交易发送给Ropsten,基于Tudor Constantin help:

https://ropsten.etherscan.io/address/0x89e2c46b22881f747797cf67310aad1a831d50b7

为了能够将已签名的事务发送到Ropsten testnet,我对这些内容进行了更改。

这假设您已经将您的合同部署到了Ropsten中,并且您有了合同地址。

1)获取你的Trezor帐户的地址

代码语言:javascript
复制
  getTrezorAddress = async() => {
        let trezor=  await this.getTrezor();
        // spend one change output
        var address_n = "m/44'/1'/0'/0/0";
        trezor.ethereumGetAddress(address_n, function (result) {
            if (result.success) { // success
                console.log('Address: ', result.address);
            } else {
                console.error('Error:', result.error); // error message
            }
        });
    }

2)将trezor地址放入原始事务的from字段,通过获取该地址的事务计数来获取事务的nonce。重要:使用getTransactionCount上的" pending“可选参数获取帐户的所有事务,否则您将过度处理挂起的事务。

代码语言:javascript
复制
getNonce = async(address) => {

        let web3 = await this.getWeb3();
        return new Promise (function (resolve,reject) {
            web3.eth.getTransactionCount(address, "pending", function (error,result){
                console.log("Nonce "+result);
                resolve(result);


            });
        });

    }

let count = null;
        await this.getNonce("0xedff546ac229317df81ef9e6cb3b67c0e6425fa7").then(result => {
            if(result.length % 2 !==0){
                result = "0"+result;
            }
            count = "0x"+result;

       });

var tx = {
            nonce: count ,
            gasPrice: web3.toHex(gasPriceGwei*1e9),
            gasLimit: web3.toHex(gasLimit),
            to: CONTRACT_ADDRESS,
            value: '0x00',
            data: getData,
            chainId:chainId,
            from:"yourTrezzorAddress"
        };

3) r、s、v参数不正确,正确的处理方法是取trezor响应的值,并将其转换为十六进制:

代码语言:javascript
复制
// response is the Trezor sign response
tx.v= response.v;
tx.r="0x"+response.r;
tx.s="0x"+response.s;
let ethtx = new ethereumjs(tx);.
const serializedTx = ethtx.serialize();
const rawTx = '0x' + serializedTx.toString('hex');
 //finally pass this data parameter to send Transaction
web3.eth.sendRawTransaction(rawTx, someCallbackFunction);

重要:在ropsten中的挖掘时间将在15到30秒之间,因此如果在someCallbackFunction中使用哈希检查事务收据,结果将获得null,因为事务处于挂起状态。

4)为了在ropsten上测试它,我们使用了呋喃,因此我们更改了web3提供者:

代码语言:javascript
复制
import Web3 from 'web3'
import HDWalletProvider from "truffle-hdwallet-provider";

let getWeb3 = new Promise(function(resolve, reject) {
    // Wait for loading completion to avoid race conditions with web3 injection timing.
    window.addEventListener('load', function() {
        var results
        var web3 = window.web3

        // Checking if Web3 has been injected by the browser (Mist/MetaMask)
        if (typeof web3 !== 'undefined') {
            // Use Mist/MetaMask's provider.
            web3 = new Web3(web3.currentProvider)

            results = {
                web3: web3
            }

            console.log('Injected web3 detected.');

            return resolve(results)
        } else {
            // Fallback to localhost if no web3 injection. We've configured this to
            // use the development console's port by default.
            // var provider = new Web3.providers.HttpProvider("https://ropsten.infura.io/your_infura_api_key")

            var mnemonic = "infura mnemonic"
            var provider = new HDWalletProvider(mnemonic, "https://ropsten.infura.io/your_infura_api_key")
            web3 = new Web3(provider)

            results = {
                web3: web3
            }

            console.log('No web3 instance injected, using Local web3.');

            return resolve(results)
        }
    })
})

export default getWeb3

编辑

这也适用于特弗莱!检查这个问题的最后评论,https://github.com/trufflesuite/truffle/issues/973

票数 0
EN

Ethereum用户

发布于 2018-06-13 16:23:19

你有很多问题要问。最好一次只提一个问题,这样你就有更多的机会得到答案。

让我谈谈最重要的问题。

Q1。是否有办法将硬件钱包纳入松露开发网络?

是的,通过使用truffle console配置它连接到testrpc。使用testrpc,您可以拥有您想要的任何帐户(编辑:这不是真的-这些帐户实际上是私钥,使用HW钱包是不可用的),方法是启动它如下:

代码语言:javascript
复制
testrpc --account="0x8414315fe005b8f294020dfc61cfd13749fbc045b0c6abc31fbd1ee3f4ff3b41, 10000000000000000000"         --account="0x566a9022cd3f0dfcc3dff657a6c578897d4b0300e335fa569a082b637e6bb273, 70000000000000000000"         --account="0x90b4e47ca43b66fab5dbebfee464087b51923f73f649701ca485da313574fd5b, 80000000000000000000"         --account="0x5d47b245c405d706fecbc5eb213819d20a2168ad696b352644ad0ffc87aef18e, 90000000000000000000"

地址是你的trezor地址。

或者,您可以从trezor的种子开始(我不建议这样做,除非您确信trezor在实时网络中使用):

代码语言:javascript
复制
testrpc -m 'candy maple cake sugar pudding cream honey rich smooth crumble sweet treat'

Q2:你们认为我们所遵循的签名和发送过程有什么问题吗?

我设法用Ledger硬件钱包编程地签署了eth交易。我用于签名事务的总帐 js库还返回V、R和S参数。我假设它们的格式与Trezor的库返回的格式相同,但我不能肯定。总之,这就是我如何使用V,R,S来创建有效的事务:

代码语言:javascript
复制
console.log('Please sign transaction on device...');
  //the signature is an object with keys v,r and s
  const signature = await eth_utils.ledger.signTransaction_async(argv['derivation_path'], tx.serialize().toString('hex'));

  //"hexify" the keys
  Object.keys(signature).map( (key, index) => {
    signature[key] = '0x'+signature[key];
  });
  //tx_raw is a js object that contains all the tx params, the one that was signed on the hw device
  //(equivalent of your tx from your sendTransaction() function)
  const tx_obj = { ...tx_raw, ...signature};

  //re-create the Transaction using ethereumjs-tx
  const signed_tx = new Transaction( tx_obj );

  //signed_tx_hex needs to be broadcasted
  const signed_tx_hex = '0x'+signed_tx.serialize().toString('hex');

就是这样。

票数 1
EN
页面原文内容由Ethereum提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://ethereum.stackexchange.com/questions/50866

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档