4
3

More than 3 years have passed since last update.

solidity で書かれたスマートコントラクト用の golang バインディングコードを生成する

Last updated at Posted at 2020-10-08

はじめに

golangを使用してEthreumに接続する場合、Ethereumのスマートコントラクトをgolangから直接実行するバインディングコードを生成すると簡単です。
一昨年から昨年にかけて、Ethereumのスマートコントラクトを利用したエスクローサービスを制作した際にもこの方式で実装しました。

やってみよう

必用ソフト

ソフト 説明 インストール方法
solcjs Solidity用のJavaScriptバインディング npm install solc
abigen ABIベースのgolangバインディング
※ gethに付属
go get github.com/ethereum/go-ethereum
cd $GOPATH/src/github.com/ethereum/go-ethereum
go install ./cmd/abigen

バインディングコードを生成するスマートコントラクト

標準的なERC20のスマートコントラクトのsolidityソースコードです。

Erc20.sol
pragma solidity ^0.4.24;

contract ERC20 {
    string public constant name = "";
    string public constant symbol = "";
    uint8 public constant decimals = 0;

    function totalSupply() public constant returns (uint);
    function balanceOf(address tokenOwner) public constant returns (uint balance);
    function allowance(address tokenOwner, address spender) public constant returns (uint remaining);
    function transfer(address to, uint tokens) public returns (bool success);
    function approve(address spender, uint tokens) public returns (bool success);
    function transferFrom(address from, address to, uint tokens) public returns (bool success);

    event Transfer(address indexed from, address indexed to, uint tokens);
    event Approval(address indexed tokenOwner, address indexed spender, uint tokens);
}

バインディングコード生成

一度 solidity から abi を生成し、abi から golang バインディングを生成します。

solidity -> abi (Erc20_sol_ERC20.abiを生成)
$ solcjs --abi Erc20.sol

abi -> golangバインディング (Erc20.goを生成)
$ abigen --abi Erc20_sol_ERC20.abi -pkg contract -out Erc20.go

生成されたメソッド

Erc20.goにsolidityのインターフェイスに倣ってメソッドが生成されます。

func (_Erc20 *Erc20Raw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error {
func (_Erc20 *Erc20Raw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
func (_Erc20 *Erc20Raw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
func (_Erc20 *Erc20CallerRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error {
func (_Erc20 *Erc20TransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
func (_Erc20 *Erc20TransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
func (_Erc20 *Erc20Caller) Allowance(opts *bind.CallOpts, tokenOwner common.Address, spender common.Address) (*big.Int, error) {
func (_Erc20 *Erc20Session) Allowance(tokenOwner common.Address, spender common.Address) (*big.Int, error) {
func (_Erc20 *Erc20CallerSession) Allowance(tokenOwner common.Address, spender common.Address) (*big.Int, error) {
func (_Erc20 *Erc20Caller) BalanceOf(opts *bind.CallOpts, tokenOwner common.Address) (*big.Int, error) {
func (_Erc20 *Erc20Session) BalanceOf(tokenOwner common.Address) (*big.Int, error) {
func (_Erc20 *Erc20CallerSession) BalanceOf(tokenOwner common.Address) (*big.Int, error) {
func (_Erc20 *Erc20Caller) Decimals(opts *bind.CallOpts) (uint8, error) {
func (_Erc20 *Erc20Session) Decimals() (uint8, error) {
func (_Erc20 *Erc20CallerSession) Decimals() (uint8, error) {
func (_Erc20 *Erc20Caller) Name(opts *bind.CallOpts) (string, error) {
func (_Erc20 *Erc20Session) Name() (string, error) {
func (_Erc20 *Erc20CallerSession) Name() (string, error) {
func (_Erc20 *Erc20Caller) Symbol(opts *bind.CallOpts) (string, error) {
func (_Erc20 *Erc20Session) Symbol() (string, error) {
func (_Erc20 *Erc20CallerSession) Symbol() (string, error) {
func (_Erc20 *Erc20Caller) TotalSupply(opts *bind.CallOpts) (*big.Int, error) {
func (_Erc20 *Erc20Session) TotalSupply() (*big.Int, error) {
func (_Erc20 *Erc20CallerSession) TotalSupply() (*big.Int, error) {
func (_Erc20 *Erc20Transactor) Approve(opts *bind.TransactOpts, spender common.Address, tokens *big.Int) (*types.Transaction, error) {
func (_Erc20 *Erc20Session) Approve(spender common.Address, tokens *big.Int) (*types.Transaction, error) {
func (_Erc20 *Erc20TransactorSession) Approve(spender common.Address, tokens *big.Int) (*types.Transaction, error) {
func (_Erc20 *Erc20Transactor) Transfer(opts *bind.TransactOpts, to common.Address, tokens *big.Int) (*types.Transaction, error) {
func (_Erc20 *Erc20Session) Transfer(to common.Address, tokens *big.Int) (*types.Transaction, error) {
func (_Erc20 *Erc20TransactorSession) Transfer(to common.Address, tokens *big.Int) (*types.Transaction, error) {
func (_Erc20 *Erc20Transactor) TransferFrom(opts *bind.TransactOpts, from common.Address, to common.Address, tokens *big.Int) (*types.Transaction, error) {
func (_Erc20 *Erc20Session) TransferFrom(from common.Address, to common.Address, tokens *big.Int) (*types.Transaction, error) {
func (_Erc20 *Erc20TransactorSession) TransferFrom(from common.Address, to common.Address, tokens *big.Int) (*types.Transaction, error) {
func (it *Erc20ApprovalIterator) Next() bool {
func (it *Erc20ApprovalIterator) Error() error {
func (it *Erc20ApprovalIterator) Close() error {
func (_Erc20 *Erc20Filterer) FilterApproval(opts *bind.FilterOpts, tokenOwner []common.Address, spender []common.Address) (*Erc20ApprovalIterator, error) {
func (_Erc20 *Erc20Filterer) WatchApproval(opts *bind.WatchOpts, sink chan<- *Erc20Approval, tokenOwner []common.Address, spender []common.Address) (event.Subscription, error) {
func (it *Erc20TransferIterator) Next() bool {
func (it *Erc20TransferIterator) Error() error {
func (it *Erc20TransferIterator) Close() error {
func (_Erc20 *Erc20Filterer) FilterTransfer(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*Erc20TransferIterator, error) {
func (_Erc20 *Erc20Filterer) WatchTransfer(opts *bind.WatchOpts, sink chan<- *Erc20Transfer, from []common.Address, to []common.Address) (event.Subscription, error) {

golangからのERC20 BalanceOf()実行例

これでgolangから簡単にスマートコントラクトを実行できます。

client, _ := ethclient.Dial("Ethereumの接続URL(infura.ioなど)")
erc20, _ := contract.NewErc20("コントラクトのアドレス(type:common.Address)", client)
balance, _ := erc20.BalanceOf(&bind.CallOpts{}, "残高を確認したいアドレス(type:common.Address)")
4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3