[转]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 ...
随机推荐
- 为何存在requests库,pycharm依然报错解决方法 --转载
原文地址:https://www.jianshu.com/p/e28a72ba7809 今天在使用pycharm的时候,用到了第三档库requests,提示有错误,报错显示 No module nam ...
- Git版本库管理
Step 1 查看哪些历史提交过文件占用空间较大 使用以下命令可以查看占用空间最多的五个文件: git rev-list --objects --all | grep "$(git veri ...
- 数据库 ACID
ACID是指一个事务本质上有四个特点: Atomicity:原子性 Consistency:一致性 Isolation:隔离性 Durablilty:耐久性 原子性 原子性是指事务是一个不可分割的工作 ...
- RK3288 GPIO
简介GPIO, 全称 General-Purpose Input/Output(通用输入输出),是一种软件运行期间能够动态配置和控制的通用引脚.RK3288有9组 GPIO bank: GPIO0,G ...
- python模块part1
一.时间模块 1.时间表示形式 在Python中,通常有这三种方式来表示时间:时间戳.元组(struct_time).格式化的时间字符串:(1)时间戳(timestamp) :通常来说,时间戳表示的是 ...
- 用with打开文件
rep_word = 'The piece is gone, left the puzzle undone' # \ 换行,跟shell一样 with open('nothing', 'r', enc ...
- 蒙层嵌套pdf以及连接后台
一.在本地浏览pdf(直接将element-dialog 和 iframe相结合)需要将要浏览的pdf放入static文件夹下面 <el-button type="text" ...
- Java Integer常量池——IntegerCache内部类
个人理解,不喜勿喷,欢迎指正. 首先看下面这段代码,猜一下输出结果是什么 Integer a = 10; Integer b = 10; System.out.println(a == b); a = ...
- mybatis 注解的方式批量插入,更新数据
一,当向数据表中插入一条数据时,一般先检查该数据是否已经存在,如果存在更新,不存在则新增 使用关键字 ON DUPLICATE KEY UPDATE zk_device_id为主键 model ...
- Excel身份证验证,身份证校验公式
=IF(LEN(Q4)=0,"空",IF(LEN(Q4)=15,"老号",IF(LEN(Q4)<>18,"位数不对",IF(CH ...