Golang Learning Note 19 using Golang to implement Ethereum token transfer
- In the Ethereum blockchain, we call tokens tokens, which are digital assets that everyone in the Ethereum blockchain can freely distribute. And it must follow the ERC20 standard, as for the ERC20 standard, you can refer to this article Https://theethereum.wiki/w/index.php/ERC20_Token_Standard
- It's actually a smart contract code that has the following function and event in the smart contract code.
contract ERC20 {function totalsupply () constant Returns (UINTtotalsupply); function balanceof (address _owner) constant Returns (UINTbalance); function transfer (address _to,UINT_value) Returns (BOOLsuccess); function Transferfrom (address _from, address _to,UINT_value) Returns (BOOLsuccess); function approve (address _spender,UINT_value) Returns (BOOLsuccess); function allowance (address _owner, address _spender) constant Returns (UINTremaining); EventTransfer (address indexed _from, address indexed _to,UINT_value); EventApproval (address indexed _owner, address indexed _spender,UINT_value); }
The can contract code is run in the Ethereum Smart contract virtual machine. Document: Https://solidity.readthedocs.io/en/latest/installing-solidity.html#building-from-source
We see the above section similar to Golang in the interface code, which contains the total amount, balance, transfer and other methods. Our focus today is actually to use Golang to achieve transfer, Transferfrom method.
Connecting an Ethereum RPC node
- Currently widely used is Go-ethereum, whose client name is Geth. You can build, install, etc. to set up the node on your computer or server, and turn on the RPC service. This article omits this step, there is a lot of articles on the Internet for you to understand.
- Attached Github:https://github.com/ethereum/go-ethereum
- Geth The default RPC port is
8545
, I use the default port, which we all use http://127.0.0.1:8545
as our RPC connection.
Get the Go-ethereum code first
go get github.com/ethereum/go-ethereum
- Then we go-ethereum the directory, if your Golang environment is not a problem, then it should be this path.
cd $GOPATH/src/github.com/ethereum/go-ethereum
- When you enter the directory and see that the code is fully pulled down, then we can proceed to the next step.
Connecting RPC Nodes
Import ( "Github.com/ethereum/go-ethereum/rpc" " github.com/ethereum/go-ethereum/ethclient") rpcDial, err: = RPC. Dial ("http://127.0.0.1:8545") if err! = Nil {panic (err);} Client: = Ethclient. Newclient (rpcdial)
If there is no panic, then we have successfully connected
Create a Test account
- To perform a transfer test, we need two ethereum accounts. We use Golang to generate, we know that the Ethereum account private key is placed in the KeyStore file, is a JSON, and when created can set the password. The same meaning as Bitcoin's Wallet.dat file is that your assets will remain in the blockchain network forever and will never be recovered.
- Below we create two Ethereum accounts in code.
Import ( "Github.com/ethereum/go-ethereum/accounts/keystore") ks: = KeyStore. Newkeystore ("/", KeyStore. STANDARDSCRYPTN, KeyStore. STANDARDSCRYPTP) Address, _: = ks. NewAccount ("password") account, err: = ks. Export (Address, "password", "password") if err! = Nil { panic (err)}
- From the above code we can see that an Ethereum account has been created, and the password is set to and
password
exported. The final account
variable is the private key of the account, which is a JSON text.
- With
address
the variable, we can get the address of the account. Such asaddress.Address.Hex()
Generate token file
- Open
cd $GOPATH/src/github.com/ethereum/go-ethereum/cmd/abigen
You can see the Main.go file
Executed go build main.go
, a binary file is generated under the directory main
.
Save the following JSON as Token.abi and put it in the current directory.
[{"Constant": true, "inputs": [], "name": "Name", "outputs": [{"Name": "", "type": "Bytes32"}], "payable": false, "type": " function "},{" constant ": false," inputs ": []," name ":" Stop "," outputs ": []," payable ": false," type ":" Function "},{" Constant ": false," inputs ": [{" Name ":" Guy "," type ":" Address "},{" name ":" Wad "," type ":" uint256 "}]," name ":" Approve "," Outputs ": [{" Name ":" "," type ":" BOOL "}]," payable ": false," type ":" function "},{" constant ": false," inputs ": [{" Name ":" Owner_ "," type ":" Address "}]," name ":" SetOwner "," outputs ": []," payable ": false," type ":" function "},{" constant ": true, "Inputs": [], "name": "Totalsupply", "outputs": [{"Name": "", "type": "uint256"}], "payable": false, "type": "Function"},{ "Constant": false, "inputs": [{"name": "src", "type": "Address"},{"name": "DST", "type": "Address"},{"name": "Wad", "type" ":" uint256 "}]," name ":" Transferfrom "," outputs ": [{" Name ":" "," type ":" BOOL "}]," payable ": false," type ":" Function "},{ "Constant": true, "inputs": [], "name": "Decimals", "outputs": [{"Name": "", "type": "uint256"}], "payable": false, "type": "Function"},{"consTant ": false," inputs ": [{" Name ":" DST "," type ":" Address "},{" name ":" Wad "," type ":" uint128 "}]," name ":" Push "," outputs " : [{"Name": "", "type": "BOOL"}], "payable": false, "type": "function"},{"constant": false, "inputs": [{"Name": "Name_", " Type ":" Bytes32 "}]," name ":" SetName "," outputs ": []," payable ": false," type ":" function "},{" constant ": false," inputs ": [{"Name": "Wad", "type": "uint128"}], "name": "Mint", "outputs": [], "payable": false, "type": "function"},{"constant": True, "inputs": [{"name": "src", "type": "Address"}], "name": "Balanceof", "outputs": [{"Name": "", "type": "uint256"}], " Payable ": false," type ":" function "},{" constant ": true," inputs ": []," name ":" Stopped "," outputs ": [{" Name ":" "," type ":" BOOL "}]," payable ": false," type ":" function "},{" constant ": false," inputs ": [{" Name ":" Authority_ "," type ":" Address "}] , "name": "Setauthority", "outputs": [], "payable": false, "type": "function"},{"constant": false, "inputs": [{"Name": " src "," type ":" Address "},{" name ":" Wad "," type ":" uint128 "}]," name ":" Pull "," outputs ": [{" Name ":" "," type ":" BOOL "}]," Payable ": false," tYpe ":" function "},{" constant ": true," inputs ": []," name ":" Owner "," outputs ": [{" Name ":" "," type ":" Address "}]," payable ": false," type ":" function "},{" constant ": false," inputs ": [{" Name ":" Wad "," type ":" uint128 "}]," name ":" Burn "," outputs ": []," payable ": false," type ":" function "},{" constant ": true," inputs ": []," name ":" Symbol "," outputs ": [{" Name ":" "," Type ":" Bytes32 "}]," payable ": false," type ":" function "},{" constant ": false," inputs ": [{" Name ":" DST "," type ":" Address "},{" name ":" Wad "," type ":" uint256 "}]," name ":" Transfer "," outputs ": [{" Name ":" "," type ":" BOOL "}]," payable ": false," Type ":" function "},{" constant ": false," inputs ": []," name ":" Start "," outputs ": []," payable ": false," type ":" Function "} {"Constant": true, "inputs": [], "name": "authority", "outputs": [{"Name": "", "type": "Address"}], "payable": false, " Type ":" function "},{" constant ": true," inputs ": [{" name ":" src "," type ":" Address "},{" name ":" Guy "," type ":" Address "}], "Name": "Allowance", "outputs": [{"Name": "", "type": "uint256"}], "payable": false, "type": "function"},{"inputs": [{" Name ":" Symbol_ "," tYpe ":" Bytes32 "}]," payable ": false," type ":" Constructor "},{" anonymous ": true," inputs ": [{" Indexed ": True," name ":" Sig "," type ":" Bytes4 "},{" indexed ": True," name ":" Guy "," type ":" Address "},{" indexed ": True," name ":" foo "," type ":" Bytes32 "},{" indexed ": True," "Name": "Bar", "type": "Bytes32"},{"indexed": false, "name": "Wad", "type": "uint256"},{"indexed": False, "name": "Fax", "type": "bytes"}], "name": "Lognote", "Type": "Event"},{"anonymous": false, "inputs": [{"Indexed": True, "name": "authority", "type": "Address"}], "name": "Logsetauthority", "Type": "Event"},{"anonymous": false, "inputs ": [{" Indexed ": True," name ":" Owner "," Type ":" Address "}]," name ":" Logsetowner "," Type ":" Event "},{" anonymous ": false," Inputs ": [{" Indexed ": True," name ":" From "," type ":" Address "},{" indexed ": True," name ":" To "," type ":" Address "},{" Indexed ": false," name ":" Value "," type ":" uint256 "}]," name ":" Transfer "," Type ":" Event "},{" anonymous ": false," inputs " : [{"Indexed": True, "name": "Owner", "Type": "Address"},{"indexed": True, "name": "Spender", "type": "Address"},{" Indexed ": false," name ":"Value "," type ":" uint256 "}]," name ":" Approval "," Type ":" Event "}]
Start transfer
- The first step is to drag the previous build
token.go
into the project.
Import ( "Github.com/ethereum/go-ethereum/accounts/abi/bind")//imports the Account key (JSON) and password Auth generated above first, err: = Bind. Newtransactor (Strings. Newreader ("JSON"), "password")//This sentence is generated token.go inside the method//client variable is our first step to connect the Ethereum RPC node when the//contractaddress is created is the token address, For example, the EOS address is 0x86fa049857e0209aa7d9e616f7eb3b3b78ecfdb0//, so we're just transferring the EOS tokens in the account.//specific See here https://etherscan.io/token/ 0x86fa049857e0209aa7d9e616f7eb3b3b78ecfdb0token, err: = Newtoken (Common. Hextoaddress ("0x86fa049857e0209aa7d9e616f7eb3b3b78ecfdb0"), client) if err! = Nil { panic (err)}//Each token will have a corresponding number of digits, For example, Eos is 18-bit, so when we transfer money, we need to add 18 0decimal after the amount, err: = token. Decimals (nil) if err! = Nil { panic (err)}//This is the code snippet that handles the number of bits tendecimal: = big. Newfloat (Math. Pow (float64 (decimal))) Convertamount, _: = new (big. Float). Mul (Tendecimal, amount). Int (&big. int{})//Then you can transfer to the account you need to accept the//toaddress is the account address TXs that accepts EOS, err: = token. Transfer (auth, Common. Hextoaddress (toaddress), Convertamount)
The transfer was successful.
Https://golang.org/src/go/token/token.go
There's a lot of other ways in there.