首页 文章

通过Trezor(硬件钱包)向Ropsten或Truffle发送网络签名交易

提问于
浏览
16

我试图将 web3jsTrezor 集成在 truffle dev网络中或使用 ropsten test network .

我的想法是使用 hardware wallet and then send a raw transaction using web3js 签署交易

我得到了我们没有 balancer 来进行交易, probably because web3js isnt taking one of the 10 truffle accounts and is using the trezor address that isnt in my local network ..

在ropsten我有一些醚,我得到“无效地址”

有没有办法使用web3js将已签名的交易(使用trezor)发送到松露开发网络?我的意思是,有没有办法将trezor地址包含在松露网络中?

松露的情况在这里详细解释,但问题可以概括为“ is there a way to include hardware wallets into truffle development network? ”:https://github.com/trufflesuite/truffle/issues/973

使用ropsten我已经设法发送一个事务并在回调中接收一个事务哈希,但如果我们查询该事务,我们得到该事务不存在..所以..这怎么可能?

我也尝试将 Contract 部署到Ropsten,现在我在调用智能合约函数时得到“无效地址” . 也许签名功能错了?有人可以将Trezor交易登录与web3js集成吗?

Do you guys see anything wrong in the signing and sending process that we have followed? 可能是R,V和S参数处理有问题..

Another important thing 是我使用https://github.com/ethereumjs/ethereumjs-tx来创建原始事务

Issues published in web3js, truffle and trezzor connect with more information:

亲切的问候

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,因为该对象是作为脚本注入的

<script src="https://connect.trezor.io/4/connect.js"></script>


let getTrezorConnect = new Promise(function(resolve, reject) {
    // Wait for loading completion
    window.addEventListener('load', function() {

        var trezorConnect = window.TrezorConnect

            return resolve(trezorConnect)


})});

export default getTrezorConnect

1 回答

  • 2

    好吧,经过大量的尝试,我们设法将与Trezor签名的原始交易发送到 RopstenTruffle (请参阅答案底部的编辑)以及本地私有 Geth 网络,因此,代码是可以的,那里Trezor在这些环境中的集成是没有问题的

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

    这是我为了能够将已签名的事务发送到Ropsten testnet而更改的内容 .

    这假定您已将 Contract 部署到Ropsten并且您拥有 Contract 地址 .

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

    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"可选参数来获取帐户的所有事务,否则您将重写未决事务 .

    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响应的值并将其转换为hexa:

    // 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测试它我们使用Infura,所以我们改变了web3提供者:

    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
    

    EDIT

    This also works on Truffle !查看此问题的最新评论https://github.com/trufflesuite/truffle/issues/973

相关问题