nodejs使用web3js开发以太坊
安装web3 tx
npm install web3 --save
npm install ethereumjs-tx --save
注册节点
eth余额查询、转账
service/ethService.js
const Web3 = require('web3')
const Tx = require('ethereumjs-tx').Transaction
var web3
if (typeof web3 !== 'undefined') {
web3 = new Web3(web3.currentProvider);
} else {
// set the provider you want from Web3.providers
web3 = new Web3(new Web3.providers.HttpProvider("https://ropsten.infura.io/v3/...."));
}
//创建账户
function create(){
let acc = web3.eth.accounts.create()
return acc
}
//获取gas价格
async function getGasPrice(){
let price
await web3.eth.getGasPrice().then((res) => {
price = res
})
return price
}
//查询账户余额
async function balance(account){
let balance
await web3.eth.getBalance(account).then((res) => {
balance = web3.utils.fromWei(res, 'ether')
})
return balance
}
//交易eth
async function tran(fromAdd, to, num, limit, privatekey){
let gasPrice = await getGasPrice();
console.log(gasPrice)
let hash;
await web3.eth.getTransactionCount(fromAdd, (err,txcount)=>{
if(err){
console.log(err)
} else{
const txObject = {
nonce: web3.utils.toHex(txcount),
to: to,
value: web3.utils.toHex(web3.utils.toWei(num, 'ether')),
gasLimit: web3.utils.toHex(limit),
gasPrice: web3.utils.toHex(gasPrice)
}
console.log(txObject)
// 签署交易
const tx = new Tx(txObject, {
chain: 'ropsten',
hardfork: 'petersburg'
})
tx.sign(Buffer.from(privatekey.substring(2),'hex'))
const serializedTx = tx.serialize()
const raw = '0x' + serializedTx.toString('hex')
// 广播交易
web3.eth.sendSignedTransaction(raw , (err, txHash) => {
if (!err){
hash = txHash
}else{
console.log(err);
}
})
}
})
return hash
}
module.exports = {
create,
getGasPrice,
balance,
tran
}
合约代币余额查询、交易
安装 solc fs(直接拷贝合约abi可省略此步骤)
//版本和合约版本一致
npm install --save solc@0.4.17
npm install --save fs
service/conService.js
const ethService = require('./ethService.js')
const Tx = require('ethereumjs-tx').Transaction
const fs = require('fs')
const solc = require('solc')
var web3 = ethService.web3
//编译合约
var source = fs.readFileSync("./contract/contract.sol", "utf8");
var compile = solc.compile(source, 1);
// var bytecode = compile.contracts[':TetherToken'].bytecode;
//获取abi 不在本地编译合约的,可直接拷贝合约abi在此赋值
var abi = compile.contracts[':TetherToken'].interface;
abi = JSON.parse(abi)
//合约实例
var conAdd = '0x785859EdD69cFE827c216233eAb714834E40E7ea'
var contract = new web3.eth.Contract(abi, conAdd)
//代币余额
async function balance(account) {
let balance
await contract.methods.balanceOf(account).call().then((res) =>{
balance = web3.utils.fromWei(res, 'MWEI')
})
return balance
}
async function tran(from,to, num,limit, priKey) {
let gasPrice = await ethService.getGasPrice();
let hash;
await web3.eth.getTransactionCount(from, (err,txcount)=>{
if(err){
console.log(err)
} else{
const txObject = {
nonce: web3.utils.toHex(txcount),
to: conAdd,
gasLimit: web3.utils.toHex(limit),
gasPrice: web3.utils.toHex(gasPrice*2),
data: contract.methods.transfer(to, web3.utils.toWei(num, 'MWEI')).encodeABI()
}// console.log(txObject)
// 签署交易
const tx = new Tx(txObject, {
chain: 'ropsten',
hardfork: 'petersburg'
})
tx.sign(Buffer.from(priKey.substring(2),'hex'))
const serializedTx = tx.serialize()
const raw = '0x' + serializedTx.toString('hex')
// 广播交易
web3.eth.sendSignedTransaction(raw , (err, txHash) => {
if (!err){
hash = txHash
console.log("success:" + txHash)
return hash
}else{
console.log(err);
}
})
}
})
}
module.exports = {
balance,
tran
}
合约源码 contract/contract.sol (直接拷贝合约abi可省略此步骤)
pragma solidity ^0.4.17;
/**
* @title SafeMath
* @dev Math operations with safety checks that throw on error
*/
library SafeMath {
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 c = a * b;
assert(c / a == b);
return c;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
// assert(b > 0); // Solidity automatically throws when dividing by 0
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
assert(b <= a);
return a - b;
}
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
assert(c >= a);
return c;
}
}
contract Ownable {
address public owner;
function Ownable() public {
owner = msg.sender;
}
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
function transferOwnership(address newOwner) public onlyOwner {
if (newOwner != address(0)) {
owner = newOwner;
}
}
}
contract ERC20 {
uint public _totalSupply;
function totalSupply() public constant returns (uint);
function balanceOf(address who) public constant returns (uint);
function transfer(address to, uint value) public;
function approve(address spender, uint value) public;
function transferFrom(address from, address to, uint value) public;
function allowance(address owner, address spender) public constant returns (uint);
event Transfer(address indexed from, address indexed to, uint value);
event Approval(address indexed owner, address indexed spender, uint value);
}
contract TetherToken is Ownable, ERC20 {
using SafeMath for uint;
string public name;
string public symbol;
uint public decimals;
uint public basisPointsRate = 0;
uint public maximumFee = 0;
uint public constant MAX_UINT = 2**256 - 1;
mapping (address => uint) public balances;
mapping (address => mapping (address => uint)) public allowed;
event Issue(uint amount);
event Redeem(uint amount);
function TetherToken (uint _initialSupply, string _name) public {
_totalSupply = _initialSupply * 10**6;
name = _name;
symbol = _name;
decimals = 6;
balances[owner] = _totalSupply;
}
/**
* @dev Fix for the ERC20 short address attack.
*/
modifier onlyPayloadSize(uint size) {
require(!(msg.data.length < size + 4));
_;
}
function totalSupply() public constant returns (uint) {
return _totalSupply;
}
function balanceOf(address _owner) public constant returns (uint balance) {
return balances[_owner];
}
function transfer(address _to, uint _value) public onlyPayloadSize(2 * 32) {
uint fee = (_value.mul(basisPointsRate)).div(10000);
if (fee > maximumFee) {
fee = maximumFee;
}
uint sendAmount = _value.sub(fee);
balances[msg.sender] = balances[msg.sender].sub(_value);
balances[_to] = balances[_to].add(sendAmount);
if (fee > 0) {
balances[owner] = balances[owner].add(fee);
Transfer(msg.sender, owner, fee);
}
Transfer(msg.sender, _to, sendAmount);
}
function approve(address _spender, uint _value) public onlyPayloadSize(2 * 32) {
require(!((_value != 0) && (allowed[msg.sender][_spender] != 0)));
allowed[msg.sender][_spender] = _value;
Approval(msg.sender, _spender, _value);
}
function transferFrom(address _from, address _to, uint _value) public onlyPayloadSize(3 * 32) {
var _allowance = allowed[_from][msg.sender];
uint fee = (_value.mul(basisPointsRate)).div(10000);
if (fee > maximumFee) {
fee = maximumFee;
}
if (_allowance < MAX_UINT) {
allowed[_from][msg.sender] = _allowance.sub(_value);
}
uint sendAmount = _value.sub(fee);
balances[_from] = balances[_from].sub(_value);
balances[_to] = balances[_to].add(sendAmount);
if (fee > 0) {
balances[owner] = balances[owner].add(fee);
Transfer(_from, owner, fee);
}
Transfer(_from, _to, sendAmount);
}
function allowance(address _owner, address _spender) public constant returns (uint remaining) {
return allowed[_owner][_spender];
}
function issue(uint amount) public onlyOwner {
require(_totalSupply + amount > _totalSupply);
require(balances[owner] + amount > balances[owner]);
balances[owner] += amount;
_totalSupply += amount;
Issue(amount);
}
function redeem(uint amount) public onlyOwner {
require(_totalSupply >= amount);
require(balances[owner] >= amount);
_totalSupply -= amount;
balances[owner] -= amount;
Redeem(amount);
}
}
测试 controller/eth.js
const router = require('koa-router')()
const ethService = require('../service/ethService.js')
const conService = require('../service/conService.js')
router.prefix('/eth')
//创建账户
router.get('/create', async (ctx, next) => {
let acc = ethService.create()
ctx.body = acc
})
//获取gas价格
router.get('/gasPrice', async (ctx, next) => {
let price = await ethService.getGasPrice()
console.log(ethService.web3.utils.fromWei(price, 'gwei'))
ctx.body = price
})
//查询账户余额
router.get('/balance', async (ctx, next) => {
let balance = await ethService.balance('0x118234e32f67ad526B31Ad696f6533179a8cB42b')
console.log(balance)
ctx.body = balance
})
//交易
router.get('/tran', async (ctx, next) => {
let hash = await ethService.tran('fromAdd', 'toAdd'
,"1" ,"21000" ,'from账户私钥privatekey')
console.log(hash)
ctx.body = hash
})
//合约余额
router.get('/conBalance', async (ctx, next) => {
let valance = await conService.balance('账户add')
console.log(valance)
ctx.body = valance
})
//合约代币交易
router.get('/conTran', async (ctx, next) => {
let hash = await conService.tran('fromAdd','toAdd', '100','200000', 'from账户私钥privatekey')
console.log(hash)
ctx.body = hash
})
module.exports = router