概述: 用Go来查询ERC20代币智能合约的教程。

查询ERC20代币智能合约

首先创建一个ERC20智能合约interface。 这只是与您可以调用的函数的函数定义的契约。

  1. pragma solidity ^0.4.24;
  2. contract ERC20 {
  3. string public constant name = "";
  4. string public constant symbol = "";
  5. uint8 public constant decimals = 0;
  6. function totalSupply() public constant returns (uint);
  7. function balanceOf(address tokenOwner) public constant returns (uint balance);
  8. function allowance(address tokenOwner, address spender) public constant returns (uint remaining);
  9. function transfer(address to, uint tokens) public returns (bool success);
  10. function approve(address spender, uint tokens) public returns (bool success);
  11. function transferFrom(address from, address to, uint tokens) public returns (bool success);
  12. event Transfer(address indexed from, address indexed to, uint tokens);
  13. event Approval(address indexed tokenOwner, address indexed spender, uint tokens);
  14. }

然后将interface智能合约编译为JSON ABI,并使用abigen从ABI创建Go包。

  1. solc --abi erc20.sol
  2. abigen --abi=erc20_sol_ERC20.abi --pkg=token --out=erc20.go

假设我们已经像往常一样设置了以太坊客户端,我们现在可以将新的token包导入我们的应用程序并实例化它。这个例子里我们用Golem 代币的地址.

  1. tokenAddress := common.HexToAddress("0xa74476443119A942dE498590Fe1f2454d7D4aC0d")
  2. instance, err := token.NewToken(tokenAddress, client)
  3. if err != nil {
  4. log.Fatal(err)
  5. }

我们现在可以调用任何ERC20的方法。 例如,我们可以查询用户的代币余额。

  1. address := common.HexToAddress("0x0536806df512d6cdde913cf95c9886f65b1d3462")
  2. bal, err := instance.BalanceOf(&bind.CallOpts{}, address)
  3. if err != nil {
  4. log.Fatal(err)
  5. }
  6. fmt.Printf("wei: %s\n", bal) // "wei: 74605500647408739782407023"

我们还可以读ERC20智能合约的公共变量。

  1. name, err := instance.Name(&bind.CallOpts{})
  2. if err != nil {
  3. log.Fatal(err)
  4. }
  5. symbol, err := instance.Symbol(&bind.CallOpts{})
  6. if err != nil {
  7. log.Fatal(err)
  8. }
  9. decimals, err := instance.Decimals(&bind.CallOpts{})
  10. if err != nil {
  11. log.Fatal(err)
  12. }
  13. fmt.Printf("name: %s\n", name) // "name: Golem Network"
  14. fmt.Printf("symbol: %s\n", symbol) // "symbol: GNT"
  15. fmt.Printf("decimals: %v\n", decimals) // "decimals: 18"

我们可以做一些简单的数学运算将余额转换为可读的十进制格式。

  1. fbal := new(big.Float)
  2. fbal.SetString(bal.String())
  3. value := new(big.Float).Quo(fbal, big.NewFloat(math.Pow10(int(decimals))))
  4. fmt.Printf("balance: %f", value) // "balance: 74605500.647409"

同样的信息也可以在etherscan上查询: https://etherscan.io/token/0xa74476443119a942de498590fe1f2454d7d4ac0d?a=0x0536806df512d6cdde913cf95c9886f65b1d3462

完整代码

Commands

  1. solc --abi erc20.sol
  2. abigen --abi=erc20_sol_ERC20.abi --pkg=token --out=erc20.go

erc20.sol

  1. pragma solidity ^0.4.24;
  2. contract ERC20 {
  3. string public constant name = "";
  4. string public constant symbol = "";
  5. uint8 public constant decimals = 0;
  6. function totalSupply() public constant returns (uint);
  7. function balanceOf(address tokenOwner) public constant returns (uint balance);
  8. function allowance(address tokenOwner, address spender) public constant returns (uint remaining);
  9. function transfer(address to, uint tokens) public returns (bool success);
  10. function approve(address spender, uint tokens) public returns (bool success);
  11. function transferFrom(address from, address to, uint tokens) public returns (bool success);
  12. event Transfer(address indexed from, address indexed to, uint tokens);
  13. event Approval(address indexed tokenOwner, address indexed spender, uint tokens);
  14. }

contract_read_erc20.go

  1. package main
  2. import (
  3. "fmt"
  4. "log"
  5. "math"
  6. "math/big"
  7. "github.com/ethereum/go-ethereum/accounts/abi/bind"
  8. "github.com/ethereum/go-ethereum/common"
  9. "github.com/ethereum/go-ethereum/ethclient"
  10. token "./contracts_erc20" // for demo
  11. )
  12. func main() {
  13. client, err := ethclient.Dial("https://mainnet.infura.io")
  14. if err != nil {
  15. log.Fatal(err)
  16. }
  17. // Golem (GNT) Address
  18. tokenAddress := common.HexToAddress("0xa74476443119A942dE498590Fe1f2454d7D4aC0d")
  19. instance, err := token.NewToken(tokenAddress, client)
  20. if err != nil {
  21. log.Fatal(err)
  22. }
  23. address := common.HexToAddress("0x0536806df512d6cdde913cf95c9886f65b1d3462")
  24. bal, err := instance.BalanceOf(&bind.CallOpts{}, address)
  25. if err != nil {
  26. log.Fatal(err)
  27. }
  28. name, err := instance.Name(&bind.CallOpts{})
  29. if err != nil {
  30. log.Fatal(err)
  31. }
  32. symbol, err := instance.Symbol(&bind.CallOpts{})
  33. if err != nil {
  34. log.Fatal(err)
  35. }
  36. decimals, err := instance.Decimals(&bind.CallOpts{})
  37. if err != nil {
  38. log.Fatal(err)
  39. }
  40. fmt.Printf("name: %s\n", name) // "name: Golem Network"
  41. fmt.Printf("symbol: %s\n", symbol) // "symbol: GNT"
  42. fmt.Printf("decimals: %v\n", decimals) // "decimals: 18"
  43. fmt.Printf("wei: %s\n", bal) // "wei: 74605500647408739782407023"
  44. fbal := new(big.Float)
  45. fbal.SetString(bal.String())
  46. value := new(big.Float).Quo(fbal, big.NewFloat(math.Pow10(int(decimals))))
  47. fmt.Printf("balance: %f", value) // "balance: 74605500.647409"
  48. }

solc version used for these examples

  1. $ solc --version
  2. 0.4.24+commit.e67f0147.Emscripten.clang