I am writing a CLI in Go that should faciliate users to be able to make contract function calls from it. This entails generating contract ABIs and providing input parameters to the function arguments but requires knowledge of the argument type to be able to construct a transaction payload correctly. This payload becomes the data component of an Ethereum transaction to make a function call.

My CLI prompts for input which then needs to be converted to a specific type for that parameter as defined by its ABI.

// Compile solidity contract given a path to file
contract, err := compiler.CompileSolidity("", contractPath)
if err != nil {
    log.Fatal("ERROR failed to compile contract:", err)

path := strings.Split(contractPath, "/")
contractName := path[len(path)-1]

// Resulting compiled contract instance
compiledContract = contract[contractPath+":"+strings.Replace(contractName, ".sol", "", -1)]

// Retrieve the ABI definition as a JSON string from the compiled contract
abiStr, err := json.Marshal(compiledContract.Info.AbiDefinition)
if err != nil {
    log.Fatal("ERROR marshalling abi to string", err)

// Go format ABI from JSON
abiContract, err := abi.JSON(strings.NewReader(string(abiStr)))
if err != nil {
    log.Fatal("ERROR reading contract ABI ", err)

inputParameters := abi.Methods[methodName].Inputs
// Gets input parameters to named method as strings
args := getArguments(inputParameters)

payload, err := abiContract.Pack(methodName, args...)
if err != nil {
    log.Fatal("ERROR packing the method name for the contract call: ", err)

As shown above, a contract instance is compiled and its generated ABI used to discern the method metadata. For a given methodName, a Method contains Inputs as type Arguments which contain information for each input argument including parameter name and type. This code is here.

Above, args is an array of string that have been input as parameters to the methodName function call but need to be casted to the correct type before abiContract.Pack where it panics due to type mismatch of provided parameters vs the expected type as defined by the ABI.

Given a variable of type string and another variable of type abi.Type how can I perform a type conversion to convert the string variable into the type defined by the abi.Type variable?

1 Answer 1


abi.Pack rest arguments must be of type interface{} so create an []interface{} to hold your values in order to spread them:

args := []string{"foo"}
var iargs []interface{}
for _, arg := range args {
    iargs = append(iargs, args)

packed, err := abiContract.Pack(methodName, iargs...)
if err != nil {


Here's a full example demonstrating how to use Pack and Unpack:

Store.sol (example smart contract)

pragma solidity ^0.4.24;

contract Store {
  mapping (bytes32 => bytes32) public items;

  function setItem(bytes32 key, bytes32 value) external {
    items[key] = value;

main.go (full example code)

package main

import (

    ethereum "github.com/ethereum/go-ethereum"

    store "./contracts" // where the abigen compiled contract is

func main() {
    client, err := ethclient.Dial("https://rinkeby.infura.io")
    if err != nil {

    abiContract, err := abi.JSON(strings.NewReader(string(store.StoreABI)))
    if err != nil {

    var key [32]byte
    copy(key[:], []byte("foo"))
    iargs := []interface{}{key}

    packed, err := abiContract.Pack("items", iargs...)
    if err != nil {

    fmt.Println(packed) // [72 243 67 243 102 111 111 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]

    contractAddress := common.HexToAddress("0x147b8eb97fd247d06c4006d269c90c1908fb5d54")

    msg := ethereum.CallMsg{
        To:   &contractAddress,
        Data: packed,

    output, err := client.CallContract(context.Background(), msg, nil)
    if err != nil {

    var item [32]byte
    err = abiContract.Unpack(&item, "items", output)
    if err != nil {

    fmt.Println(string(item[:])) // "bar"
  • Your variable is already of type [32]byte which would only satisfy the Pack call in this case. The problem in itself is being able to assert, given the variable in some other type, the type that is required for the Pack function. In these cases it seems that for required types such as bytes32[] or bytes2[5], or 2D arrays, it seems impossible to convert a variable from any other type to the required type in general where we need to be able to handle bytesn[m] without hard coding 2^256 different permutations of byte arrays: bytes1[1], bytes1[2],... bytes32[254],bytes32[255]
    – Shiri
    Mar 10, 2020 at 18:53

Your Answer

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

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