无需安装metamask钱包,如何使用私钥直接发送以太坊交易

2018-09-08  本文已影响489人  JackyGu

By 古千峰

很多DAPP应用,会要求在电脑浏览器中安装以太坊钱包metamask,当应用中需要发送ETH时,自动打开metamask,发送交易。

但是在浏览器中如果没有metamask钱包(安装metamask的门槛并不低,需要学会科学上网),该怎么办呢?能不能像imtoken那样简单的操作呢?

发送交易的本质是用发送方的私钥签名,所以除了metamask外,还可以使用另外两种方法签名:

本教程,就先来介绍使用私钥方式来签名并发送交易,而不需要安装metamask钱包,这类应用可广泛用于手机端Dapp。这类Dapp不需要与运营商的服务器进行交互,前端源码公开,对于运营商来说,比较容易自证清白。

使用以太坊发送交易分为两步:

一、准备工作

1- 在编程之前,需要导入两个库:

1.1 如果你喜欢使用nodejs,用以下命令安装:

npm install web3@0.20.3 --save
npm install ethereumjs-tx --save

在程序中,使用以下命令导入库:

var Web3 = require("web3");
var Tx = require("ethereumjs-tx");

1.2 如果你喜欢使用原生javascript,则需要在html中使用如下方式导入以上两个库:

<script src="https://cdn.jsdelivr.net/gh/ethereum/web3.js/dist/web3.min.js"></script>
<script src="https://cdn.rawgit.com/ethereumjs/browser-builds/2fb69a714afe092b06645286f14b94f41e5c062c/dist/ethereumjs-tx.js"></script>

2- 注册infura,并获取API KEY

开发以太坊Dapp,一般需要在本地安装geth,但这种方法需要花比较多的时间和空间来同步区块,利用infura可以简单很多,infura提供公开以太坊和测试节点,可以利用infura提供的api访问以太坊以及IPFS

官网网址:infura.io。只需要提供email注册得到链接即可,进到infuradashboard中,新建一个DAPP,即可获得API KEY,如下图。

API KEY

二、连接以太坊网络

一般使用以下统一代码:

function init() {
    var network = "mainnet";//或者ropsten等测试网络名称
    var infura_apikey = "infura的API_KEY";
    if (typeof web3 !== 'undefined') {
        //如果浏览器中安装有metamask,则执行这里
        web3 = new Web3(web3.currentProvider);
    } else {
        /*
        //开发环境,如果在本地有以太坊的testrpc或者Ganache测试环境,则使用以下方式链接
        web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
        */
        //通过infura连接以太坊网络
        web3 = new Web3(new Web3.providers.HttpProvider('https://' + network + '.infura.io/v3/' + infura_apikey));
    }
}

三、配置发送交易的数据

function getTx() {
    //发送1个eth
    var wei = web3.toWei("1", "ether");
    //获取当前Gas价格,Gas价格一直变动,发送交易前建议动态获取
    var gasPrice = web3.eth.gasPrice.toNumber();
    //获取当前发送账号的所有交易,包括pending的交易,用来确定nonce值
    //web3.eth.getTransactionCount 有bug,有时候无法正确获取,最好在客户端设置nonce值
    var nonce = web3.eth.getTransactionCount('发送者地址', 'pending');
    //获取估计的Gas值
    var estimategas = web3.eth.estimateGas({
        to: '收款方地址,或者合约地址',
        data: '发送数据'
    });
    //获取gas限额
    var gasLimit = web3.eth.getBlock("latest").gasLimit;

    //配置交易参数
    var rawTransaction = {
        nonce:     web3.toHex(nonce),
        gasPrice:  web3.toHex(gasPrice * 2),
        gasLimit:  web3.toHex(gasLimit),
        gas:       web3.toHex(estimategas),
        value:     web3.toHex(wei),
        chainId:   3, //ropsten测试网络用3,主网用1
        to:        '收款方地址',
        data:      '发送数据'
    }
    return rawTransaction;

四、签名

如果是用nodejs,使用如下代码:

var privateKey = new Buffer('发送账户的私钥', 'hex')
var tx = new Tx(rawTransaction);
tx.sign(privateKey);
var serializedTx = tx.serialize().toString('hex');//签名结果

如果用原生javascript,使用如下代码:

var privateKey = new EthJS.Buffer.Buffer('发送账户的私钥', 'hex');
var tx = new EthJS.Tx(rawTransaction);
tx.sign(privateKey);
var serializedTx = tx.serialize().toString('hex');

五、发送交易

使用如下代码:

web3.eth.sendRawTransaction("0x" + serializedTx, function (err, hash) {
    if (!err) console.log("Tx: " + hash); //交易发送成功后的TX值
    else console.log(err.toString());
});

nodejs版全部代码如下:

var Web3 = require('web3');
var Tx = require('ethereumjs-tx');

const network = "ropsten";//mainnet, ropsten
const chainId = 3;//1- mainnet, 3-ropsten
const sender = "0x615b80388e3d3cac6aa3a904803acfe7939"; //发送者公钥
const privateKey = new Buffer('19608a60b54943cd840c84b8e833ef84732a18eb562cdee09f8dba532ea', 'hex')
const toAddress = "0x3fe7995bf0a505a51196aa11218b181c849"; //接受者公钥
const ethAmount = "0";//发送的ETH
const hexData = "Hello World!";

const infura_apikey = "3446259cb0e74d68b614f9a103";

init();
sendTx();

function sendTx() {
    var wei = web3.toWei(ethAmount, "ether");
    var nonce = web3.eth.getTransactionCount(sender, 'pending');
    var estimategas = web3.eth.estimateGas({
        to: toAddress,
        data: hexData
    });
    var gasPrice = web3.eth.gasPrice.toNumber();
    var gasLimit = web3.eth.getBlock("latest").gasLimit;

    var rawTransaction = {
        nonce: web3.toHex(nonce),
        gasPrice: web3.toHex(gasPrice * 2), //2倍Gas价格
        gasLimit: web3.toHex(gasLimit),
        gas: web3.toHex(estimategas),
        value: web3.toHex(wei),
        chainId: chainId,
        to: toAddress,
        data: hexData
    }

    var tx = new Tx(rawTransaction);
    tx.sign(privateKey);

    var serializedTx = tx.serialize().toString('hex');
    console.log(serializedTx);
    
    web3.eth.sendRawTransaction("0x" + serializedTx, function (err, hash) {
        if (!err) console.log("Tx: " + hash);
        else console.log(err.toString());
    });
    
}

function init() {
    if (typeof web3 !== 'undefined') {
        web3 = new Web3(web3.currentProvider);
    } else {
        //web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:7545"));
        web3 = new Web3(new Web3.providers.HttpProvider('https://' + network + '.infura.io/v3/' + infura_apikey));
    }
}

如果使用原生javascript,可以参考以下链接:
https://codepen.io/jackygu/pen/zJdVyj

上一篇下一篇

猜你喜欢

热点阅读