package vm import ( "encoding/json" "fmt" ) // ABI describes the callable interface of a deployed contract. type ABI struct { Methods []ABIMethod `json:"methods"` } // ABIMethod describes a single callable method. type ABIMethod struct { Name string `json:"name"` Args []ABIArg `json:"args"` // may be nil / empty for zero-arg methods } // ABIArg describes one parameter of a method. type ABIArg struct { Name string `json:"name"` // e.g. "amount" Type string `json:"type,omitempty"` // e.g. "uint64", "string", "bytes" } // ParseABI deserializes an ABI from JSON. func ParseABI(jsonStr string) (*ABI, error) { var a ABI if err := json.Unmarshal([]byte(jsonStr), &a); err != nil { return nil, fmt.Errorf("invalid ABI JSON: %w", err) } return &a, nil } // HasMethod returns true if the ABI declares the named method. func (a *ABI) HasMethod(name string) bool { for _, m := range a.Methods { if m.Name == name { return true } } return false } // Validate checks that method exists in the ABI and args_json has the right // number of elements. argsJSON may be empty ("" or "[]") for zero-arg methods. func (a *ABI) Validate(method string, argsJSON []byte) error { var target *ABIMethod for i := range a.Methods { if a.Methods[i].Name == method { target = &a.Methods[i] break } } if target == nil { return fmt.Errorf("method %q not found in ABI", method) } if len(target.Args) == 0 { return nil // no args expected — nothing to validate } if len(argsJSON) > 0 { var args []any if err := json.Unmarshal(argsJSON, &args); err != nil { return fmt.Errorf("args_json is not a JSON array: %w", err) } if len(args) != len(target.Args) { return fmt.Errorf("method %q expects %d args, got %d", method, len(target.Args), len(args)) } } return nil }