[转]How to Send Ethereum with Web3.js and Node
原文:https://davekiss.com/ethereum-web3-node-tutorial/
Ethereum took the web and cryptocurrency world by storm in 2017. In the span of one year, the price of 1 Ether skyrocketed from $8.24 USD to $750.00 USD – and for good reason. If you need convincing on the nature of decentralization, just watch this video featuring Ethereum founder Vitalik Buterin and AngelList CEO Naval Ravikant and come back in 30 minutes.
However, if you’ve found this article, I’m guessing you’re already a believer and want to learn more about interacting with the Ethereum main network. In my case, I wanted to find a way to programmatically send amounts of Ether between different addresses based on external factors (think IFTTT for sending cryptocurrency.)
Whatever your reasoning, in this article, we’re going to go over how to use Node.js and the quickly-evolving Web3.js library to submit ETH transactions to the Ethereum network. We’ll start off with test transactions first to learn the basics and make sure everything is working as expected. Then, once you’re comfortable, we can flip the switch and move real ETH around the Ethereum mainnet.
There’s a lot to learn here, especially if you’re new to this space like I am, so I’ll try to break down the terms to the best of my understanding. Let’s get started!
Creating a Test Ethereum Wallet
We’re going to get started using some test Ether rather than actual money while we’re learning about this whole process, so the first thing we’ll need to do is create a new Ethereum wallet address that will be able to hold our test funds.
To do this, first visit https://www.myetherwallet.com
Next, open up the dropdown at the top right corner and change the Network selection to Rinkeby – infura.io. This change will make sure that the new wallet address that we are creating is going to exist on the Ethereum test network rather than the live network.
Note: Even though we’re only working with test funds, I’m going to recommend that you take the proper precautions to secure your wallet information so as to practice the best habits for when you do work with real funds. You do not need to be entirely secure with the test network, as there is no consequence to someone accessing your wallet information, but it’s a good idea to get used to the methods of storing your wallet data securely.
Now, select the New Wallet tab. You should see a screen that says Create New Wallet.
You’ll be prompted to enter a password to associate with your new test wallet. Enter it in the text box on the screen and be sure to store it somewhere secure where you’ll remember it.
After entering your password, you’ll be presented with a screen which allows you to download the wallet keystore. This is essentially a file that will allow you to restore your new test wallet if you do end up losing your password. Download it and store it somewhere safe. Then, acknowledge the warning on the screen and click the red “I understand. Continue.” button.
On the next screen, you’ll be presented with your new wallet’s private key. Copy this key to your clipboard and store it somewhere safe.
You may also wish to print out a paper wallet, which is literally a piece of paper that contains this information so it doesn’t exist on your computer anywhere. If you have any serious funds involved, you can store this paper wallet in a safe, make several copies of it, hide it in your walls etc. I’m going to skip this step for the test wallet, but this is a good idea for actual funds.
When you’re ready, click Save your Address.
The next screen will allow you to unlock your wallet to see your public wallet address. For the test network, we can use our private key from the previous step to unlock the wallet and view the public address.
To do this, under the section which reads “How would you like to access your wallet?” choose Private Key, paste your Private Key into the text box on the screen and click Unlock.
Your new wallet’s address will be displayed on the screen. It will start with “0x” and should look something like this: 0x15ECf4401CF9Dd4e74C1B7b44D105bb66e097BBA
Copy this address to your clipboard and store it somewhere safe. You’ve successfully generated a new test wallet!
To summarize, you should now have 4 or 5 pieces of data stored somewhere safely:
- Your wallet password
- Your wallet keystore
- Your wallet private key
- Your wallet public address
- (optional) Your printed paper-wallet
Sweet! Now let’s go get some test money to play with.
Funding your Test Wallet with Test Ether
Since we’re using the test network, there are specific websites, called faucets, that will happily issue you some test tokens to play around with. We’re going to use the Rinkeby Faucet to request that 3 ETH be sent to our new test wallet. I wish it were real ETH (it’d be worth more than $3,000 at the time of writing,) but alas, funny money will have to do for now.
Visit the Rinkeby Faucet site here: https://www.rinkeby.io/#faucet
The Rinkeby Faucet has a protection in place to help prevent abuse of the system: they will only issue test Ether to public wallet addresses that have been associated with a post on a social network.
The easiest way to obtain your test Ether is by using Twitter to send out a tweet containing your public wallet address. I’ve created a mini-tool below to allow you to generate a tweet that works as expected.
After you’ve sent out your tweet, you should copy the link to the tweet and paste your link in the Rinkeby Authenticated Faucet input box. The link should look something like this:
1
|
https://twitter.com/davekiss/status/956982653680484358
|
Then, from the “Give me Ether” dropdown, select the option that reads “3 Ethers / 8 Hours”
If all goes well, in a moment you will see a message that says “Funding request accepted for username@twitter to wallet address“. The test network may take a few minutes to confirm your transaction, but you should be able to verify that everything worked as expected pretty quickly.
To verify that the test Ethers made it to your wallet, go back to https://www.myetherwallet.com and click on the “View Wallet Info” tab. Since MyEtherWallet does not store any of your sensitive data, you’ll need to unlock your wallet again by entering your Wallet Private Key just as you did before.
It works! Your wallet should now have an account balance of 3 RINKEBY ETH
Due to the decentralized nature of Ethereum, you can also view your account balance on EtherScan by visiting the following link, swapping out the placeholder address with your own Public Wallet Address:
1
|
https://rinkeby.etherscan.io/address/0x_your_public_wallet_address
|
Sending Your Test Ether to Another Ethereum Wallet
Now that you’ve created your test wallet and added some test Ethers to it, it’s time to get into the nitty gritty of it all. How can we write some code that will allow us to programmatically send our test Ether to another public Ethereum wallet address?
For the purposes of this tutorial, your objective is to send some test Ether to my own Ethereum test wallet. My public Ethereum test wallet address on the Rinkeby testnet is 0xeF19E7Ec9eE90a0426c60E74aFCc504C02513E11
First things first: you’ll need to create a new free account over at Infura, which is a service that acts as a remote Ethereum node, making it simple to interact with the Ethereum testnet and mainnet. You can sign up here: https://infura.io/signup
Next, open up your terminal and clone the starter repository to a directory that you can get to easily. Make sure you don’t do this in a Dropbox folder, since we’ll be storing some sensitive information and also pulling a bunch of dependencies with Node.
1
|
git clone git@github.com:davekiss/web3-node-tutorial.git
|
Now, make your way into the new directory with cd web3-node-tutorial and install the app dependencies by running npm install or yarn
After a minute or so, your app dependencies will be ready to go, so now we can create a configuration file which will hold all of your sensitive information so it can be used in your app, but without placing it directly in your code. This is called an environment variable file.
Create it by running touch .env and then open it up for editing in your favorite code editor.
There are four different variables that we’ll want to define in this file: the access token provided by Infura which provides access to the Ethereum node, your public wallet address, your wallet private key, and the destination wallet address.
1
2
3
4
5
6
7
8
|
INFURA_ACCESS_TOKEN=xxxxxx
# Rinkeby Testnet
WALLET_ADDRESS=xxxxxx
WALLET_PRIVATE_KEY=xxxxxx
# Destination
DESTINATION_WALLET_ADDRESS=xxxxxx
|
You’ll want to fill this file in with your own unique tokens and keys. You don’t need to place the values in quotes or anything, you can just paste them right after the = sign
Now, we are ready to switch over to the index.js file and start coding. Let’s start by requiring the .env file that we just created:
1
|
require('dotenv').config()
|
We’ll also need to require a few other dependencies that we’ll be using along the way, including the Etherereum Web3.js library.
1
2
3
4
5
|
const Web3 = require('web3')
const axios = require('axios')
const EthereumTx = require('ethereumjs-tx')
const log = require('ololog').configure({ time: true })
const ansi = require('ansicolor').nice
|
Cool! We’re ready to define the network that we’d like to connect to. We’re going to use Infura to connect to the test net, so let’s save the testnet url to a variable and append your testnet access token. You can do that like so:
1
|
const testnet = `https://rinkeby.infura.io/${process.env.INFURA_ACCESS_TOKEN}`
|
Note that all of your environment variables that were defined in the .env file are now accessible in the process.env object.
Web3 will need to know the link to the network that we’re trying to connect to, so let’s set that up now:
1
|
const web3 = new Web3( new Web3.providers.HttpProvider(testnet) )
|
We can also tell Web3 what our public wallet address is so that Web3 knows to always reference that wallet address during future interactions:
1
|
web3.eth.defaultAccount = process.env.WALLET_ADDRESS
|
Great, now let’s also define the amount of ETH that we’d like to send in this transaction. I’m going to use a small amount to start:
1
|
const amountToSend = 0.001
|
That’s about it for the configuration! Let’s write the main function that will execute whenever we run the Node.js program.
1
2
3
4
5
|
const main = async () => {
// our code goes here
}
main()
|
At this point, your code should look something like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
require('dotenv').config()
const Web3 = require('web3')
const axios = require('axios')
const EthereumTx = require('ethereumjs-tx')
const log = require('ololog').configure({ time: true })
const ansi = require('ansicolor').nice
const testnet = `https://rinkeby.infura.io/${process.env.INFURA_ACCESS_TOKEN}`
const web3 = new Web3( new Web3.providers.HttpProvider(networkToUse) )
web3.eth.defaultAccount = process.env.WALLET_ADDRESS
const amountToSend = 0.00100000
const main = async () => {
// our code goes here
}
main()
|
Let’s define what it is we’re looking to do here.
- Find out what the balance of our wallet is to make sure we can afford to send the defined amount.
- Get the nonce to use for each individual transaction.
- Find the current gas prices required to power our transaction through the network.
- Build the transaction and sign it using our wallet private key
- Submit the transaction and view the details on Etherscan.
That sounds like a good summary to me. Let’s start by using Web3 to fetch the current balance of your wallet.
1
2
3
4
|
let myBalanceWei = web3.eth.getBalance(web3.eth.defaultAccount).toNumber()
let myBalance = web3.fromWei(myBalanceWei, 'ether')
log(`Your wallet balance is currently ${myBalance} ETH`.green)
|
Now, let’s figure out the nonce to use in association with this transaction. A nonce (Number used Once) is used to help make sure this transaction cannot be replicated again.
1
2
|
let nonce = web3.eth.getTransactionCount(web3.eth.defaultAccount)
log(`The outgoing transaction count for your wallet address is: ${nonce}`.magenta)
|
We’ll have to write a quick async function in order to fetch the latest gas prices for the Ethereum network. I’m going to use the API provided by https://ethgasstation.info
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
/**
* Fetch the current transaction gas prices from https://ethgasstation.info/
*
* @return {object} Gas prices at different priorities
*/
const getCurrentGasPrices = async () => {
let response = await axios.get('https://ethgasstation.info/json/ethgasAPI.json')
let prices = {
low: response.data.safeLow / 10,
medium: response.data.average / 10,
high: response.data.fast / 10
}
console.log("\r\n")
log (`Current ETH Gas Prices (in GWEI):`.cyan)
console.log("\r\n")
log(`Low: ${prices.low} (transaction completes in < 30 minutes)`.green)
log(`Standard: ${prices.medium} (transaction completes in < 5 minutes)`.yellow)
log(`Fast: ${prices.high} (transaction completes in < 2 minutes)`.red)
console.log("\r\n")
return prices
}
|
We can call this newly written method like so:
1
|
let gasPrices = await getCurrentGasPrices()
|
Time to build the transaction.
1
2
3
4
5
6
7
8
9
10
|
let details = {
"to": process.env.DESTINATION_WALLET_ADDRESS,
"value": web3.toHex( web3.toWei(amountToSend, 'ether') ),
"gas": 21000,
"gasPrice": gasPrices.low * 1000000000, // converts the gwei price to wei
"nonce": nonce,
"chainId": 4 // EIP 155 chainId - mainnet: 1, rinkeby: 4
}
const transaction = new EthereumTx(details)
|
Sign it:
1
|
transaction.sign( Buffer.from(process.env.WALLET_PRIVATE_KEY, 'hex') )
|
Serialize it so that we can send it to the Infura node.
1
|
const serializedTransaction = transaction.serialize()
|
We’re ready! Time to send the transaction to the network for confirmation.
1
|
const transactionId = web3.eth.sendRawTransaction('0x' + serializedTransaction.toString('hex') )
|
Now we’ll add just a few lines to inspect the results of the transaction submission and exit the program.
1
2
3
4
5
6
|
const url = `https://rinkeby.etherscan.io/tx/${transactionId}`
log(url.cyan)
log(`Note: please allow for 30 seconds before transaction appears on Etherscan`.magenta)
process.exit()
|
Here’s the whole file:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
|
/**
* Require the credentials that you entered in the .env file
*/
require('dotenv').config()
const Web3 = require('web3')
const axios = require('axios')
const EthereumTx = require('ethereumjs-tx')
const log = require('ololog').configure({ time: true })
const ansi = require('ansicolor').nice
/**
* Network configuration
*/
const testnet = `https://rinkeby.infura.io/${process.env.INFURA_ACCESS_TOKEN}`
/**
* Change the provider that is passed to HttpProvider to `mainnet` for live transactions.
*/
const web3 = new Web3( new Web3.providers.HttpProvider(testnet) )
/**
* Set the web3 default account to use as your public wallet address
*/
web3.eth.defaultAccount = process.env.WALLET_ADDRESS
/**
* The amount of ETH you want to send in this transaction
* @type {Number}
*/
const amountToSend = 0.00100000
/**
* Fetch the current transaction gas prices from https://ethgasstation.info/
*
* @return {object} Gas prices at different priorities
*/
const getCurrentGasPrices = async () => {
let response = await axios.get('https://ethgasstation.info/json/ethgasAPI.json')
let prices = {
low: response.data.safeLow / 10,
medium: response.data.average / 10,
high: response.data.fast / 10
}
console.log("\r\n")
log (`Current ETH Gas Prices (in GWEI):`.cyan)
console.log("\r\n")
log(`Low: ${prices.low} (transaction completes in < 30 minutes)`.green)
log(`Standard: ${prices.medium} (transaction completes in < 5 minutes)`.yellow)
log(`Fast: ${prices.high} (transaction completes in < 2 minutes)`.red)
console.log("\r\n")
return prices
}
/**
* This is the process that will run when you execute the program.
*/
const main = async () => {
/**
* Fetch your personal wallet's balance
*/
let myBalanceWei = web3.eth.getBalance(web3.eth.defaultAccount).toNumber()
let myBalance = web3.fromWei(myBalanceWei, 'ether')
log(`Your wallet balance is currently ${myBalance} ETH`.green)
/**
* With every new transaction you send using a specific wallet address,
* you need to increase a nonce which is tied to the sender wallet.
*/
let nonce = web3.eth.getTransactionCount(web3.eth.defaultAccount)
log(`The outgoing transaction count for your wallet address is: ${nonce}`.magenta)
/**
* Fetch the current transaction gas prices from https://ethgasstation.info/
*/
let gasPrices = await getCurrentGasPrices()
/**
* Build a new transaction object and sign it locally.
*/
let details = {
"to": process.env.DESTINATION_WALLET_ADDRESS,
"value": web3.toHex( web3.toWei(amountToSend, 'ether') ),
"gas": 21000,
"gasPrice": gasPrices.low * 1000000000, // converts the gwei price to wei
"nonce": nonce,
"chainId": 4 // EIP 155 chainId - mainnet: 1, rinkeby: 4
}
const transaction = new EthereumTx(details)
/**
* This is where the transaction is authorized on your behalf.
* The private key is what unlocks your wallet.
*/
transaction.sign( Buffer.from(process.env.WALLET_PRIVATE_KEY, 'hex') )
/**
* Now, we'll compress the transaction info down into a transportable object.
*/
const serializedTransaction = transaction.serialize()
/**
* Note that the Web3 library is able to automatically determine the "from" address based on your private key.
*/
// const addr = transaction.from.toString('hex')
// log(`Based on your private key, your wallet address is ${addr}`)
/**
* We're ready! Submit the raw transaction details to the provider configured above.
*/
const transactionId = web3.eth.sendRawTransaction('0x' + serializedTransaction.toString('hex') )
/**
* We now know the transaction ID, so let's build the public Etherscan url where
* the transaction details can be viewed.
*/
const url = `https://rinkeby.etherscan.io/tx/${transactionId}`
log(url.cyan)
log(`Note: please allow for 30 seconds before transaction appears on Etherscan`.magenta)
process.exit()
}
main()
|
We’re ready to run the transaction! You can do that by entering the following command into your Terminal:
1
|
babel-node ./index.js
|
You should see some output in the Terminal that will provide some information about the program as it executes. Nice!
To go live, simply switch out your wallet information with a wallet that was generated on the Ethereum mainnet and use the mainnet url provided by Infura.
If this tutorial helps you make boatloads of magic internet money, remember your roots and don’t forget to give back: 0xDcd2E5A0641C1A50d4b2a79288C83896E9912b08
[转]How to Send Ethereum with Web3.js and Node的更多相关文章
- 以太坊智能合约开发,Web3.js API 中文文档 ethereum web3.js入门说明
以太坊智能合约开发,Web3.js API 中文文档 ethereum web3.js入门说明 为了让你的Ðapp运行上以太坊,一种选择是使用web3.js library提供的web3.对象.底层实 ...
- Web3.js API 中文文档
Web3.js API 中文文档 http://web3.tryblockchain.org/Web3.js-api-refrence.html web3对象提供了所有方法. 示例: //初始化过程 ...
- 再深刻理解下web3.js中estimateGas如何计算智能合约消耗的gas量
我们可使用web3.js框架的estimateGas函数获得一个以太坊智能合约的Gas估计值 ,通过执行一个消息调用或交易,该消息调用或交易直接在节点的VM中执行,并未在区块链中确认,函数会返回估算使 ...
- web3.js
安装 别按照官网上面 npm install web3 下载,我已经吃过一次亏了 npm initnpm install ethereum/web3.js --save web3.isConn ...
- web3.js编译Solidity,发布,调用全部流程(手把手教程)
web3.js编译Solidity,发布,调用全部流程(手把手教程) 下面教程是打算在尽量牵涉可能少的以太坊的相关工具,主要使用web3.js这个以太坊提供的工具包,来完成合约的编译,发布,合约方法调 ...
- Web3.js 0.20.x API 中文版翻译
文档原始链接为:https://web3.learnblockchain.cn/0.2x.x/,欢迎大家前往查阅,本文只是节选开头部分的介绍及API列表索引,以下为翻译正文: 为了开发一个基于以太坊的 ...
- 【阿菜用工具】利用 Web3.js 在 ganache 上部署以及调用智能合约
合约部署 要部署的合约 pragma solidity ^0.4.23; contract test { uint256 value; function setValue(uint256 _value ...
- Geth控制台使用及Web3.js使用实战
在开发以太坊去中心化应用,免不了和以太坊进行交互,那就离不开Web3. Geth 控制台(REPL)实现了所有的web3 API及Admin API, 使用好 Geth 就是必修课.结合Geth命令用 ...
- 使用web3.js监听以太坊智能合约event
传送门: 柏链项目学院 使用web3.js监听以太坊智能合约event 当我们在前端页面调用合约时发现有些数据不会立即返回,这时还需要再调用更新数据的函数.那么这样的方法使用起来非常不便,监听ev ...
随机推荐
- java中之内存溢出说明
java语句是编译型和解释型语言,选通过编译命令javac 把java文件编译为.class字节码文件,然后通过java虚拟机(JVM)加载class文件到内存运行. 而java虚拟机在运行程序时有自 ...
- 如何不使用loop循环创建连续的数组
ES5 Array.apply(null,{length:100}) Object.keys(Array.apply(null,{length:100})); ES6 [...Array(100)]
- 小程序中通过判断id来删除数据,当数据长度为0时,显示隐藏部分(交流QQ群:604788754)
欢迎加入小程序交流群:本群定期更新在工作种遇到的小知识(交流QQ群:604788754) WXML: <!--遍历循环的数据部分--> <block wx:for="{{d ...
- Android中的Context(一)
Android中的Context(一) 在Android开发中,Context可以说是我们接触地非常多的一个概念了,也译作"上下文",但是这个上下文到底是什么却并不好理解. 通俗的 ...
- springboot based 主从数据源中间件方案
先定几个原则/目标: 原则: 1.必须保证数据逻辑的一致性: 反例:刚写了数据,(因为主从延迟)查询不到: 2.对开发人员透明,对业务代码无侵入性:与单数据源的业务代码调用一致: 反例:对已有业务代码 ...
- Linux c codeblock的使用(三):使用函数库
(一)概念 什么是函数库呢?一下子说概念大家可能不太熟悉,但是这实际上是大家在windows系统上经常见到的东西.没错,就是那些后缀为DLL的文件. linux上实际也有自己的函数库文件,文件类型为. ...
- Nginx实现404页面的几种方法
一个网站项目,肯定是避免不了404页面的,通常使用Nginx作为Web服务器时,有以下集中配置方式,一起来看看. 第一种:Nginx自己的错误页面 Nginx访问一个静态的html 页面,当这个页面没 ...
- 详解Python的作用域和命名空间
最近在学习Python,不得不说,Python真的是一门很好用的语言.但是学习的过程中关于变量作用域(scope)的命名空间(namespace)的问题真的把我给搞懵了.在查阅了相关资料之后,觉得自己 ...
- Django基础-01
Django 是基于 Python,所有的 Django 代码都是用Python写成的. Django 特点 强大的数据库功能 拥有强大的数据库操作接口(QuerySet API),如需要也能执行原生 ...
- oralce定时任务
oracle定时任务(dbms_job) author:skate time:2007-09-12 http://publish.it168.com/2006/0311/20060311017002. ...