0

I have been following https://geth.ethereum.org/docs/dapp/native-bindings to make a call to a smart contract.

Given an Ethereum transaction can take anywhere between 15 seconds to minutes, I don't want to keep my process stuck for minutes. I would like to create a cron job to check on the state of the transactions. For this I need access to the transaction hash. The document does not show how to get it using Go packages.

Can someone point me to the right direction? Thanks heaps.

1 Answer 1

1

here is a sample script to send an ERC20 Transfer and get tx hash:

package main

import (
    "os"
    "fmt"
    "math/big"
    "context"
    "crypto/ecdsa"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/accounts/abi/bind"
    "github.com/ethereum/go-ethereum/ethclient"
    "github.com/ethereum/go-ethereum/crypto"
   
)
const (
    CHAIN_ID        int64 = 1234
)
var (
    RPC_URL string
    token_addr      common.Address
)
func main() {

    RPC_URL = os.Getenv("RPC_URL")
    eclient, err := ethclient.Dial(RPC_URL)
    if err!=nil {
        fmt.Printf("Can't connect to ETH RPC: %v\n",err)
        os.Exit(1)
    }

    if len(os.Args) != 5 {
        fmt.Printf("Usage: \n\t\t%v [priv_key] [token_addr] [dest_addr] [amount]\n\n\t\tSends erc20 tokens to another address using transfer() function\n",os.Args[0])
        os.Exit(1)
    }
    var copts = new(bind.CallOpts)

    from_pkey_str := os.Args[1]
    if len(from_pkey_str) != 64 {
        fmt.Printf("Sender's private key is not 66 characters long\n")
        os.Exit(1)
    }

    contract_addr := common.HexToAddress(os.Args[2])
    dst_addr := common.HexToAddress(os.Args[3])
    amount_str := os.Args[4]

    tok_amount := big.NewInt(0)
    _,success := tok_amount.SetString(amount_str,10)
    if !success {
        fmt.Printf("Incorrect amount provided on the command line")
        os.Exit(1)
    }

    erc20_token,err := NewERC20(contract_addr,eclient)
    if err!=nil {
        fmt.Printf("Failed to instantiate ERC20 contract: %v\n",err)
        os.Exit(1)
    }

    symbol,err:=erc20_token.Symbol(copts)
    if err!=nil {
        fmt.Printf("Error during call: %v\n",err)
    }
    fmt.Printf("Symbol: %v\n",symbol)

    from_PrivateKey, err := crypto.HexToECDSA(from_pkey_str)
    if err != nil {
        fmt.Sprintf("Error making private key: %v\n",err)
        os.Exit(1)
    }
    from_publicKey := from_PrivateKey.Public()
    from_publicKeyECDSA, ok := from_publicKey.(*ecdsa.PublicKey)
    if !ok {
        fmt.Printf("Couldn't derive public key for Sender")
        os.Exit(1)
    }
    from_address := crypto.PubkeyToAddress(*from_publicKeyECDSA)
    from_nonce, err := eclient.PendingNonceAt(context.Background(), from_address)
    if err != nil {
        fmt.Printf("Error getting account's nonce: %v\n",err)
        os.Exit(1)
    }
    gasPrice, err := eclient.SuggestGasPrice(context.Background())
    if err != nil {
        fmt.Printf("Error getting suggested gas price: %v\n",err)
        os.Exit(1)
    }
    big_chain_id := big.NewInt(CHAIN_ID)
    txopts := bind.NewKeyedTransactor(from_PrivateKey)
    txopts.Nonce = big.NewInt(int64(from_nonce))
    txopts.Value = big.NewInt(0)     // in wei
    txopts.GasLimit = uint64(10000000) // in units
    txopts.GasPrice = gasPrice

    signfunc := func(address common.Address, tx *types.Transaction) (*types.Transaction, error) {
        signer := types.NewEIP155Signer(big_chain_id)
        signature, err := crypto.Sign(signer.Hash(tx).Bytes(), from_PrivateKey)
        if err != nil {
            fmt.Printf("Error signing: %v\n",err)
            os.Exit(1)
            return nil,nil
        }
        return tx.WithSignature(signer, signature)
    }
    txopts.Signer = signfunc

    tx,err := erc20_token.Transfer(txopts,dst_addr,tok_amount)
    if err!=nil {
        fmt.Printf("Error sending tx: %v\n",err)
        os.Exit(1)
    }
    fmt.Printf("Tx hash = %v\n",tx.Hash().String())
}

the ERC20 is the standard ERC20 contract, you can generate it with these commands:

abigen --abi token.abi --pkg main --type Token --out token.go

abigen command is in cmd/abigen in go-ethereum sources and must be compiled with go build . command

1
  • It seems there is a difference in return types between a functions that return a value and a function that does not. A function that does not return a value returns a transaction, where as a function that returns a value does not. It means it is not a good idea to return a value by a mutable function.
    – ethnoob
    Dec 21, 2022 at 2:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.