If you use golang to connect to Ethereum, it's easy to generate binding code that runs Ethereum smart contracts directly from golang. From two years ago to last year, I implemented this method when I created an escrow service using Ethereum's smart contract.
soft | Explanation | Installation method |
---|---|---|
solcjs | JavaScript binding for Solidity | npm install solc |
abigen | ABI based golang binding * Included with geth |
go get github.com/ethereum/go-ethereum cd $GOPATH/src/github.com/ethereum/go-ethereum go install ./cmd/abigen |
Solidity source code for standard ERC20 smart contracts.
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);
}
Once you generate an abi from solidity and a golang binding from abi.
solidity -> abi (Erc20_sol_ERC20.Generate abi)
$ solcjs --abi Erc20.sol
abi ->golang binding(Erc20.Generate go)
$ abigen --abi Erc20_sol_ERC20.abi -pkg contract -out Erc20.go
A method is generated in Erc20.go following the interface of 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) {
Now you can easily execute smart contracts from golang.
client, _ := ethclient.Dial("Ethereum connection URL(infura.io etc.)")
erc20, _ := contract.NewErc20("Contract address(type:common.Address)", client)
balance, _ := erc20.BalanceOf(&bind.CallOpts{}, "Address where you want to check your balance(type:common.Address)")