Skip to content

Commit

Permalink
Made some progress - internal parsing of bound parameters now working
Browse files Browse the repository at this point in the history
Added fixtures to make manual testing self-contained:
- OwnableERC721 (simple case)
- DiamondCutFacet (complex case - lots of nesting)

Next: Start generating command handlers.
  • Loading branch information
zomglings committed Feb 3, 2024
1 parent a898624 commit d8420e5
Show file tree
Hide file tree
Showing 5 changed files with 681 additions and 60 deletions.
190 changes: 130 additions & 60 deletions evm/generators.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,16 @@ import (
"go/parser"
"go/printer"
"go/token"
"strconv"
"text/template"

"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/iancoleman/strcase"
)

var ErrParsingCLIParams error = errors.New("error parsing CLI parameters")
var ErrUnrecognizedType error = errors.New("unrecognized type")
var ErrParameterUnnamed error = errors.New("parameter is unnamed")

// GenerateTypes generates Go bindings to an Ethereum contract ABI (or union of such). This functionality
// is roughly equivalent to that provided by the `abigen` tool provided by go-ethereum:
Expand All @@ -36,26 +39,46 @@ func GenerateTypes(structName string, abi []byte, bytecode []byte, packageName s
return bind.Bind([]string{structName}, []string{string(abi)}, []string{string(bytecode)}, []map[string]string{}, packageName, bind.LangGo, map[string]string{}, map[string]string{})
}

type MethodArgument struct {
Name string
ArgumentType ast.Expr
InnerArgumentTypeString string
CLIVar string
CLIName string
CLIType string
PFlagHandler string
Container bool
// ABIBoundParameter represents a Go type that is bound to an Ethereum contract ABI item.
// The different types of types we need to deal with (based on https://github.com/ethereum/go-ethereum/blob/47d76c5f9508d3594bfc9aafa95c04edae71c5a1/accounts/abi/bind/bind.go#L338):
// - uint8
// - uint16
// - uint32
// - uint64
// - int8
// - int16
// - int32
// - int64
// - *big.Int
// - [n]byte
// - []byte
// - string
// - bool
// - array
// - struct
type ABIBoundParameter struct {
Name string
GoType string
Node ast.Node
IsArray bool
Length int
Subtypes []ABIBoundParameter
}

type MethodReturnValue struct {
ReturnType string
type MethodArgument struct {
Argument ABIBoundParameter
CLIVar string
CLIName string
CLIType string
PFlagHandler string
Container bool
}

type HandlerDefinition struct {
MethodName string
HandlerName string
MethodArgs []MethodArgument
MethodReturns []MethodReturnValue
MethodReturns []ABIBoundParameter
}

// Data structure that parametrizes CLI generation.
Expand All @@ -66,33 +89,80 @@ type CLIParams struct {
TransactHandlers []HandlerDefinition
}

// // This handles types which can be output by bind.bindBasicTypeGo:
// // https://github.com/ethereum/go-ethereum/blob/eaac53ec383342fa6ef9c333659d40f7c5dac108/accounts/abi/bind/bind.go#L312
// func CLITypeForBasicType(basicType string) string {
// if basicType == "uint8" || basicType == "uint16" || basicType == "uint32" || basicType == "uint64" || basicType == "int8" || basicType == "int16" || basicType == "int32" || basicType == "int64" {
// return basicType
// } else if strings.HasSuffix(basicType, "]byte") {
// return "[]byte"
// }
// return "string"
// }

func ParseMethodArguments(method *ast.FuncDecl) ([]MethodArgument, error) {
result := make([]MethodArgument, len(method.Type.Params.List))
for i, param := range method.Type.Params.List {
if len(param.Names) != 1 {
return result, ErrParsingCLIParams
// ParseBoundParameter parses an ast.Node representing a method parameter (or return value). It inspects
// the ast.Node recursively to determine the information needed to parse that node to the user from command-line
// input or to present an instance of that type to a user as command output.
func ParseBoundParameter(arg ast.Node) (ABIBoundParameter, error) {
result := ABIBoundParameter{Node: arg}

switch n := arg.(type) {

// Entrypoint of recursion - highest level of abstraction and we'll never see a field again in subsequent
// invocations.
case *ast.Field:
if len(n.Names) > 0 {
result.Name = n.Names[0].Name
}
subresult, subresultErr := ParseBoundParameter(n.Type)
if subresultErr != nil {
return subresult, subresultErr
}
result.GoType = subresult.GoType
result.IsArray = subresult.IsArray
result.Length = subresult.Length
result.Subtypes = subresult.Subtypes

case *ast.ArrayType:
result.IsArray = true

// Check if the array is of fixed length. If so, extract the length into the result.Length field.
switch t1 := n.Elt.(type) {
case *ast.ArrayType:
if t1.Len != nil {
var conversionErr error
result.Length, conversionErr = strconv.Atoi(t1.Len.(*ast.BasicLit).Value)
if conversionErr != nil {
return result, conversionErr
}
}
}
result[i].Name = param.Names[0].Name
result[i].ArgumentType = param.Type

// Set result.Subtypes to be the type of the array elements.
result.Subtypes = make([]ABIBoundParameter, 1)
subtype, subtypeErr := ParseBoundParameter(n.Elt)
if subtypeErr != nil {
return result, subtypeErr
}
result.Subtypes[0] = subtype

result.GoType = fmt.Sprintf("[]%s", subtype.GoType)

default:
var b bytes.Buffer
printer.Fprint(&b, token.NewFileSet(), n)
result.GoType = b.String()
}

return result, nil
}

// Fills in the information required to represent the given parameters as command-line argument. Takes
// an array of ABIBoundParameter structs because it deduplicates flags.
func DeriveMethodArguments(parameters []ABIBoundParameter) ([]MethodArgument, error) {
result := make([]MethodArgument, len(parameters))

for i, parameter := range parameters {
if parameter.Name == "" {
return result, ErrParameterUnnamed
}
result[i].Argument = parameter
}
}

Check failure on line 160 in evm/generators.go

View workflow job for this annotation

GitHub Actions / build

missing return

func ParseCLIParams(structName string, deployMethod *ast.FuncDecl, viewMethods map[string]*ast.FuncDecl, transactMethods map[string]*ast.FuncDecl) (CLIParams, error) {
result := CLIParams{StructName: structName}

tempFileset := token.NewFileSet()
fset := token.NewFileSet()

result.DeployHandler = HandlerDefinition{
MethodName: deployMethod.Name.Name,
Expand All @@ -107,37 +177,20 @@ func ParseCLIParams(structName string, deployMethod *ast.FuncDecl, viewMethods m
return result, ErrParsingCLIParams
}
result.DeployHandler.MethodArgs = make([]MethodArgument, len(deployMethod.Type.Params.List)-2)
for i := 0; i < len(deployMethod.Type.Params.List)-2; i++ {
methodArg := MethodArgument{
Name: deployMethod.Type.Params.List[i+2].Names[0].Name,
ArgumentType: deployMethod.Type.Params.List[i+2].Type,
}

var b bytes.Buffer

switch methodArg.ArgumentType.(type) {
case *ast.ArrayType:
printer.Fprint(&b, tempFileset, methodArg.ArgumentType.(*ast.ArrayType).Elt)
methodArg.Container = true
methodArg.InnerArgumentTypeString = b.String()
default:
printer.Fprint(&b, tempFileset, methodArg.ArgumentType)
methodArg.InnerArgumentTypeString = b.String()
}

methodArg.CLIName = strcase.ToKebab(methodArg.Name)

switch methodArg.InnerArgumentTypeString {
case "common.Address":
methodArg.CLIType = "string"
methodArg.PFlagHandler = "StringVar"
case "*big.Int":
fmt.Println("PARAKEET")
for methodName, decl := range transactMethods {
fmt.Printf("Method: %s\n", methodName)
ast.Print(fset, decl)

for i, arg := range decl.Type.Params.List {
argType, argTypeErr := ParseBoundParameter(arg)
if argTypeErr != nil {
return result, argTypeErr
}

fmt.Printf("Argument %d: $%v\n", i, argType)
}

fmt.Printf("\t%v\n", methodArg)

methodArg.CLIVar = fmt.Sprintf("%sRaw", methodArg.Name)
}

return result, nil
Expand Down Expand Up @@ -206,7 +259,6 @@ func AddCLI(sourceCode, structName string) (string, error) {
return code, cliTemplateParseErr
}

fmt.Println("PARAKEET")
params, paramsErr := ParseCLIParams(structName, deployMethod, structViewMethods, structTransactionMethods)
if paramsErr != nil {
return code, paramsErr
Expand Down Expand Up @@ -354,3 +406,21 @@ func Create{{.StructName}}Command() *cobra.Command {
return cmd
}
`

// This template generates the handler for smart contract deployment. It is intended to be used with a
// HandlerDefinition struct.
var DeployCommandTemplate string = `
func {{.HandlerName}}
`

// This template generates the handler for smart contract methods that submit transactions. It is intended
// to be used with a HandlerDefinition struct.
var TransactMethodCommandTemplate string = `
func {{.HandlerName}}
`

// This template generates the handler for smart contract call methods. It is intended to be used with
// a HandlerDefinition struct.
var ViewMethodCommandTemplate string = `
func {{.HandlerName}}
`
1 change: 1 addition & 0 deletions fixtures/DiamondCutFacet.bin
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
608060405234801561001057600080fd5b506114aa806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c80631f931c1c14610030575b600080fd5b61004361003e366004610eb1565b610045565b005b61004d61009e565b61009761005a8587610ff7565b8484848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061011a92505050565b5050505050565b600080516020611409833981519152600401546001600160a01b031633146101185760405162461bcd60e51b815260206004820152602260248201527f4c69624469616d6f6e643a204d75737420626520636f6e7472616374206f776e60448201526132b960f11b60648201526084015b60405180910390fd5b565b60005b83518110156102e057600084828151811061013a5761013a61113b565b60200260200101516020015190506000600281111561015b5761015b611151565b81600281111561016d5761016d611151565b036101bb576101b68583815181106101875761018761113b565b6020026020010151600001518684815181106101a5576101a561113b565b60200260200101516040015161032b565b6102cd565b60018160028111156101cf576101cf611151565b03610218576101b68583815181106101e9576101e961113b565b6020026020010151600001518684815181106102075761020761113b565b6020026020010151604001516104a3565b600281600281111561022c5761022c611151565b03610275576101b68583815181106102465761024661113b565b6020026020010151600001518684815181106102645761026461113b565b602002602001015160400151610633565b60405162461bcd60e51b815260206004820152602760248201527f4c69624469616d6f6e644375743a20496e636f727265637420466163657443756044820152663a20b1ba34b7b760c91b606482015260840161010f565b50806102d88161117d565b91505061011d565b507f8faa70878671ccd212d20771b795c50af8fd3ff6cf27f4bde57e5d4de0aeb673838383604051610314939291906111e6565b60405180910390a16103268282610751565b505050565b600081511161034c5760405162461bcd60e51b815260040161010f906112e6565b6000805160206114098339815191526001600160a01b0383166103815760405162461bcd60e51b815260040161010f90611331565b6001600160a01b0383166000908152600182016020526040812054906001600160601b03821690036103b7576103b7828561095e565b60005b83518110156100975760008482815181106103d7576103d761113b565b6020908102919091018101516001600160e01b031981166000908152918690526040909120549091506001600160a01b031680156104755760405162461bcd60e51b815260206004820152603560248201527f4c69624469616d6f6e644375743a2043616e2774206164642066756e6374696f6044820152746e207468617420616c72656164792065786973747360581b606482015260840161010f565b6104818583868a6109c8565b8361048b8161137d565b9450505050808061049b9061117d565b9150506103ba565b60008151116104c45760405162461bcd60e51b815260040161010f906112e6565b6000805160206114098339815191526001600160a01b0383166104f95760405162461bcd60e51b815260040161010f90611331565b6001600160a01b0383166000908152600182016020526040812054906001600160601b038216900361052f5761052f828561095e565b60005b835181101561009757600084828151811061054f5761054f61113b565b6020908102919091018101516001600160e01b031981166000908152918690526040909120549091506001600160a01b0390811690871681036105fa5760405162461bcd60e51b815260206004820152603860248201527f4c69624469616d6f6e644375743a2043616e2774207265706c6163652066756e60448201527f6374696f6e20776974682073616d652066756e6374696f6e0000000000000000606482015260840161010f565b610605858284610a68565b6106118583868a6109c8565b8361061b8161137d565b9450505050808061062b9061117d565b915050610532565b60008151116106545760405162461bcd60e51b815260040161010f906112e6565b6000805160206114098339815191526001600160a01b038316156106d95760405162461bcd60e51b815260206004820152603660248201527f4c69624469616d6f6e644375743a2052656d6f76652066616365742061646472604482015275657373206d757374206265206164647265737328302960501b606482015260840161010f565b60005b825181101561074b5760008382815181106106f9576106f961113b565b6020908102919091018101516001600160e01b031981166000908152918590526040909120549091506001600160a01b0316610736848284610a68565b505080806107439061117d565b9150506106dc565b50505050565b6001600160a01b0382166107d8578051156107d45760405162461bcd60e51b815260206004820152603c60248201527f4c69624469616d6f6e644375743a205f696e697420697320616464726573732860448201527f3029206275745f63616c6c64617461206973206e6f7420656d70747900000000606482015260840161010f565b5050565b600081511161084f5760405162461bcd60e51b815260206004820152603d60248201527f4c69624469616d6f6e644375743a205f63616c6c6461746120697320656d707460448201527f7920627574205f696e6974206973206e6f742061646472657373283029000000606482015260840161010f565b6001600160a01b0382163014610881576108818260405180606001604052806028815260200161142960289139610e2b565b600080836001600160a01b03168360405161089c91906113a3565b600060405180830381855af49150503d80600081146108d7576040519150601f19603f3d011682016040523d82523d6000602084013e6108dc565b606091505b50915091508161074b57805115610907578060405162461bcd60e51b815260040161010f91906113bf565b60405162461bcd60e51b815260206004820152602660248201527f4c69624469616d6f6e644375743a205f696e69742066756e6374696f6e2072656044820152651d995c9d195960d21b606482015260840161010f565b6109808160405180606001604052806024815260200161145160249139610e2b565b6002820180546001600160a01b0390921660008181526001948501602090815260408220860185905594840183559182529290200180546001600160a01b0319169091179055565b6001600160e01b0319831660008181526020868152604080832080546001600160601b03909716600160a01b026001600160a01b0397881617815594909516808352600180890183529583208054968701815583528183206008870401805460e09890981c60046007909816979097026101000a96870263ffffffff9097021990971695909517909555529290915281546001600160a01b031916179055565b6001600160a01b038216610ae45760405162461bcd60e51b815260206004820152603760248201527f4c69624469616d6f6e644375743a2043616e27742072656d6f76652066756e6360448201527f74696f6e207468617420646f65736e2774206578697374000000000000000000606482015260840161010f565b306001600160a01b03831603610b535760405162461bcd60e51b815260206004820152602e60248201527f4c69624469616d6f6e644375743a2043616e27742072656d6f766520696d6d7560448201526d3a30b1363290333ab731ba34b7b760911b606482015260840161010f565b6001600160e01b03198116600090815260208481526040808320546001600160a01b0386168452600180880190935290832054600160a01b9091046001600160601b03169291610ba2916113d9565b9050808214610c94576001600160a01b03841660009081526001860160205260408120805483908110610bd757610bd761113b565b600091825260208083206008830401546001600160a01b038916845260018a019091526040909220805460079092166004026101000a90920460e01b925082919085908110610c2857610c2861113b565b600091825260208083206008830401805463ffffffff60079094166004026101000a938402191660e09590951c929092029390931790556001600160e01b03199290921682528690526040902080546001600160a01b0316600160a01b6001600160601b038516021790555b6001600160a01b03841660009081526001860160205260409020805480610cbd57610cbd6113f2565b60008281526020808220600860001990940193840401805463ffffffff600460078716026101000a0219169055919092556001600160e01b03198516825286905260408120819055819003610097576002850154600090610d20906001906113d9565b6001600160a01b0386166000908152600180890160205260409091200154909150808214610dcf576000876002018381548110610d5f57610d5f61113b565b6000918252602090912001546002890180546001600160a01b039092169250829184908110610d9057610d9061113b565b600091825260208083209190910180546001600160a01b0319166001600160a01b03948516179055929091168152600189810190925260409020018190555b86600201805480610de257610de26113f2565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b0388168252600189810190915260408220015550505050505050565b813b818161074b5760405162461bcd60e51b815260040161010f91906113bf565b80356001600160a01b0381168114610e6357600080fd5b919050565b60008083601f840112610e7a57600080fd5b50813567ffffffffffffffff811115610e9257600080fd5b602083019150836020828501011115610eaa57600080fd5b9250929050565b600080600080600060608688031215610ec957600080fd5b853567ffffffffffffffff80821115610ee157600080fd5b818801915088601f830112610ef557600080fd5b813581811115610f0457600080fd5b8960208260051b8501011115610f1957600080fd5b60208301975080965050610f2f60208901610e4c565b94506040880135915080821115610f4557600080fd5b50610f5288828901610e68565b969995985093965092949392505050565b634e487b7160e01b600052604160045260246000fd5b6040516060810167ffffffffffffffff81118282101715610f9c57610f9c610f63565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715610fcb57610fcb610f63565b604052919050565b600067ffffffffffffffff821115610fed57610fed610f63565b5060051b60200190565b600061100a61100584610fd3565b610fa2565b83815260208082019190600586811b86013681111561102857600080fd5b865b8181101561112e57803567ffffffffffffffff8082111561104b5760008081fd5b818a019150606082360312156110615760008081fd5b611069610f79565b61107283610e4c565b815286830135600381106110865760008081fd5b818801526040838101358381111561109e5760008081fd5b939093019236601f8501126110b557600092508283fd5b833592506110c561100584610fd3565b83815292871b840188019288810190368511156110e25760008081fd5b948901945b848610156111175785356001600160e01b0319811681146111085760008081fd5b825294890194908901906110e7565b91830191909152508852505094830194830161102a565b5092979650505050505050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601160045260246000fd5b60006001820161118f5761118f611167565b5060010190565b60005b838110156111b1578181015183820152602001611199565b50506000910152565b600081518084526111d2816020860160208601611196565b601f01601f19169290920160200192915050565b60006060808301818452808751808352608092508286019150828160051b8701016020808b0160005b848110156112b657898403607f19018652815180516001600160a01b0316855283810151898601906003811061125557634e487b7160e01b600052602160045260246000fd5b868601526040918201519186018a905281519081905290840190600090898701905b808310156112a15783516001600160e01b0319168252928601926001929092019190860190611277565b5097850197955050509082019060010161120f565b50506001600160a01b038a169088015286810360408801526112d881896111ba565b9a9950505050505050505050565b6020808252602b908201527f4c69624469616d6f6e644375743a204e6f2073656c6563746f727320696e206660408201526a1858d95d081d1bc818dd5d60aa1b606082015260800190565b6020808252602c908201527f4c69624469616d6f6e644375743a204164642066616365742063616e2774206260408201526b65206164647265737328302960a01b606082015260800190565b60006001600160601b0380831681810361139957611399611167565b6001019392505050565b600082516113b5818460208701611196565b9190910192915050565b6020815260006113d260208301846111ba565b9392505050565b818103818111156113ec576113ec611167565b92915050565b634e487b7160e01b600052603160045260246000fdfec8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131c4c69624469616d6f6e644375743a205f696e6974206164647265737320686173206e6f20636f64654c69624469616d6f6e644375743a204e657720666163657420686173206e6f20636f6465a26469706673582212204f2e3d47e243b75e9234a76454b22ce67d27124351c793e3e80c0f81a096be3164736f6c63430008150033
Loading

0 comments on commit d8420e5

Please sign in to comment.