ethereum - 使用 Trezor(硬件钱包)将签名交易发送到 Ropsten 或 Truffle 开发网络

标签 ethereum web3js truffle trezor

我正在尝试整合 web3js 特雷佐 松露 开发网络或使用 ropsten测试网 .

想法是使用 签署交易。硬件钱包,然后使用 web3js 发送原始交易

我知道我们没有余额来进行交易,可能是因为 web3js 没有使用 10 个 truffle 帐户之一,而是使用了我本地网络中不存在的 trezor 地址 ..

在 ropsten 我有一些以太币,我得到“无效地址”

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

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

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

我也尝试将合约部署到 Ropsten 中,现在在调用智能合约功能时我得到“无效地址”。也许签名功能是错误的?任何人都可以将 Trezor 交易签名与 web3js 集成在一起吗?

你们在我们遵循的签名和发送过程中发现任何问题吗? 可能 R、V 和 S 参数处理有问题
..

另一个重要的事情是我在使用https://github.com/ethereumjs/ethereumjs-tx用于创建原始交易

在 web3js、truffle 和 trezzor 中发布的问题与更多信息有关:

  • https://github.com/trufflesuite/truffle/issues/973
  • https://github.com/ethereum/web3.js/issues/1669
  • https://github.com/trezor/connect/issues/130

  • 亲切的问候
     trezorLogin = async()=> {
            let trezor=  await this.getTrezor();
    
            // site icon, optional. at least 48x48px
            let hosticon = 'https://doc.satoshilabs.com/trezor-apps/_images/copay_logo.png';
            // server-side generated and randomized challenges
            let challenge_hidden = '';
            let 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
            let address_n = "m/44'/60'/0'/0/0"
            // let address_n = [44 | 0x80000000,
            //                  60 | 0x80000000,
            //                  0  | 0x80000000 ,
            //                  0 ]; // same, in raw form
            let nonce = transaction.nonce.substring(2); // note - it is hex, not number!!!
            let gas_price = transaction.gasPrice.substring(2);
            let gas_limit = transaction.gasLimit.substring(2);
            let to = transaction.to.substring(2);
            // let value = '01'; // in hexadecimal, in wei - this is 1 wei
            let value = transaction.value.substring(2); // in hexadecimal, in wei - this is about 18 ETC
            let data = transaction.data.substring(2); // some contract data
            // let data = null  // for no data
            let 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
            let 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;
    
            let getData = tokenInstance.mint.getData(address, amount);
    
            let 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 因为对象是作为脚本注入(inject)的
    <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() {
    
            let trezorConnect = window.TrezorConnect
    
                return resolve(trezorConnect)
    
    
    })});
    
    export default getTrezorConnect
    

    最佳答案

    好吧,经过多次尝试,我们已经成功地将与 Trezor 签署的原始交易发送到 。罗普斯滕 , 松露 (请参阅答案底部的编辑)以及本地私有(private) 格特 网络,所以,代码没问题,在这些环境中集成 Trezor 没有问题

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

    这是我为了能够将签名交易发送到 Ropsten 测试网而更改的内容。

    这假设您已将合约部署到 Ropsten 并且您拥有合约地址。

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

      getTrezorAddress = async() => {
            let trezor=  await this.getTrezor();
            // spend one change output
            let 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;
    
           });
    
    let 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() {
            let results
            let 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.
                // let provider = new Web3.providers.HttpProvider("https://ropsten.infura.io/your_infura_api_key")
    
                let mnemonic = "infura mnemonic"
                let 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
    

    编辑 :

    这也适用于 Truffle !查看此问题的最后评论https://github.com/trufflesuite/truffle/issues/973

    关于ethereum - 使用 Trezor(硬件钱包)将签名交易发送到 Ropsten 或 Truffle 开发网络,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50596256/

    相关文章:

    ethereum - 尝试从节点脚本部署以太坊智能合约时,为什么会出现 "invalid sender"(-32000)?

    javascript - 调用 web3.eth.personal.unlockAccount 会抛出错误

    blockchain - 如何使用 Solidity 和 Web.js 在以太坊区 block 链上保存和检索数据

    solidity - Solidity 中的输入验证

    ethereum - 在部署时将智能合约链接在一起

    松露未捕获引用错误 : global is not defined after using migrate

    cryptography - 带有 ed25519 曲线签名的 BIP44

    ethereum - web3.eth.abi.decodeLog 返回错误的日志参数值

    Windows 上的 Docker : Error starting protocol stack: listen unix/root/. ethereum/geth.ipc:绑定(bind):不允许操作

    token - @solana/web3.js ERC721 元数据有 API 吗?