github.com/hyperledger/burrow@v0.34.5-0.20220512172541-77f09336001d/cmd/burrow/commands/abi.go (about)

     1  package commands
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	"github.com/hyperledger/burrow/execution/evm/abi"
     8  	cli "github.com/jawher/mow.cli"
     9  	hex "github.com/tmthrgd/go-hex"
    10  )
    11  
    12  // Abi is a command line tool for ABI encoding and decoding. Event encoding/decoding still be added
    13  func Abi(output Output) func(cmd *cli.Cmd) {
    14  	return func(cmd *cli.Cmd) {
    15  		cmd.Command("list", "List the functions and events",
    16  			func(cmd *cli.Cmd) {
    17  				dirs := cmd.StringsArg("DIR", nil, "ABI file or directory")
    18  
    19  				cmd.Action = func() {
    20  					for _, d := range *dirs {
    21  						output.Printf("In %s\n", d)
    22  						spec, err := abi.LoadPath(d)
    23  						if err != nil {
    24  							output.Printf("could not read %s: %v", d, err)
    25  						}
    26  						for id, e := range spec.EventsByID {
    27  							fmt.Printf("event %s: %s\n", id, e.String())
    28  						}
    29  						for _, f := range spec.Functions {
    30  							fmt.Printf("func %x: %s\n", f.FunctionID, f.String())
    31  						}
    32  					}
    33  				}
    34  			})
    35  
    36  		cmd.Command("encode-function-call", "ABI encode function call",
    37  			func(cmd *cli.Cmd) {
    38  				abiPath := cmd.StringOpt("abi", ".", "ABI file or directory")
    39  				fname := cmd.StringArg("FUNCTION", "", "Function name")
    40  				args := cmd.StringsArg("ARGS", nil, "Function arguments")
    41  
    42  				cmd.Spec = "--abi=<path> FUNCTION [ARGS...]"
    43  
    44  				cmd.Action = func() {
    45  					spec, err := abi.LoadPath(*abiPath)
    46  					if err != nil {
    47  						output.Fatalf("could not read %v: %v", *abiPath, err)
    48  					}
    49  
    50  					argsInInterface := make([]interface{}, len(*args))
    51  					for i, a := range *args {
    52  						argsInInterface[i] = a
    53  					}
    54  
    55  					data, _, err := spec.Pack(*fname, argsInInterface...)
    56  					if err != nil {
    57  						output.Fatalf("could not encode function call %v", err)
    58  					}
    59  
    60  					output.Printf("%X\n", data)
    61  				}
    62  			})
    63  
    64  		cmd.Command("decode-function-call", "ABI decode function call",
    65  			func(cmd *cli.Cmd) {
    66  				abiPath := cmd.StringOpt("abi", ".", "ABI file or directory")
    67  				data := cmd.StringArg("DATA", "", "Encoded function call")
    68  
    69  				cmd.Action = func() {
    70  					spec, err := abi.LoadPath(*abiPath)
    71  					if err != nil {
    72  						output.Fatalf("could not read %v: %v", *abiPath, err)
    73  					}
    74  
    75  					bs, err := hex.DecodeString(*data)
    76  					if err != nil {
    77  						output.Fatalf("could not hex decode %s: %v", data, err)
    78  					}
    79  
    80  					var funcid abi.FunctionID
    81  					copy(funcid[:], bs)
    82  					found := false
    83  					for name, fspec := range spec.Functions {
    84  						if fspec.FunctionID == funcid {
    85  							args := make([]string, len(fspec.Inputs))
    86  							intf := make([]interface{}, len(args))
    87  							for i := range args {
    88  								intf[i] = &args[i]
    89  							}
    90  							err = abi.Unpack(fspec.Inputs, bs[len(funcid):], intf...)
    91  							if err != nil {
    92  								output.Fatalf("unable to decode function %s: %v\n", name, err)
    93  							}
    94  							// prepend function argument names
    95  							for i, a := range args {
    96  								if fspec.Inputs[i].Name != "" {
    97  									args[i] = fspec.Inputs[i].Name + "=" + a
    98  								}
    99  							}
   100  
   101  							output.Printf(fmt.Sprintf("%s(%s)", name, strings.Join(args, ",")))
   102  						}
   103  
   104  					}
   105  
   106  					if !found {
   107  						output.Fatalf("could not find function %X\n", funcid)
   108  					}
   109  				}
   110  			})
   111  
   112  		cmd.Command("decode-function-return", "ABI decode function return",
   113  			func(cmd *cli.Cmd) {
   114  				abiPath := cmd.StringOpt("abi", ".", "ABI file or directory")
   115  				fname := cmd.StringArg("FUNCTION", "", "Function name")
   116  				data := cmd.StringArg("DATA", "", "Encoded function call")
   117  
   118  				cmd.Action = func() {
   119  					spec, err := abi.LoadPath(*abiPath)
   120  					if err != nil {
   121  						output.Fatalf("could not read %v: %v", *abiPath, err)
   122  					}
   123  
   124  					bs, err := hex.DecodeString(*data)
   125  					if err != nil {
   126  						output.Fatalf("could not hex decode %s: %v", data, err)
   127  					}
   128  
   129  					fspec, ok := spec.Functions[*fname]
   130  					if !ok {
   131  						output.Fatalf("no such function %s\n", *fname)
   132  					}
   133  
   134  					args := make([]string, len(fspec.Outputs))
   135  					intf := make([]interface{}, len(args))
   136  					for i := range args {
   137  						intf[i] = &args[i]
   138  					}
   139  					err = abi.Unpack(fspec.Outputs, bs, intf...)
   140  					if err != nil {
   141  						output.Fatalf("unable to decode function %s: %v\n", *fname, err)
   142  					}
   143  					// prepend function return value names
   144  					for i, a := range args {
   145  						if fspec.Outputs[i].Name != "" {
   146  							args[i] = fspec.Outputs[i].Name + "=" + a
   147  						}
   148  					}
   149  
   150  					output.Printf(strings.Join(args, "\n"))
   151  				}
   152  			})
   153  	}
   154  }