accounts/abi: implement new fallback functions (#20764)
* accounts/abi: implement new fackball functions In Solidity v0.6.0, the original fallback is separated into two different sub types: fallback and receive. This PR addes the support for parsing new format abi and the relevant abigen functionalities. * accounts/abi: fix unit tests * accounts/abi: minor fixes * accounts/abi, mobile: support jave binding * accounts/abi: address marius's comment * accounts/abi: Work around the uin64 conversion issue Co-authored-by: Guillaume Ballet <gballet@gmail.com>
This commit is contained in:
		
							parent
							
								
									2a836bb259
								
							
						
					
					
						commit
						00064ddcfb
					
				| @ -19,6 +19,7 @@ package abi | |||||||
| import ( | import ( | ||||||
| 	"bytes" | 	"bytes" | ||||||
| 	"encoding/json" | 	"encoding/json" | ||||||
|  | 	"errors" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"io" | 	"io" | ||||||
| 
 | 
 | ||||||
| @ -32,6 +33,12 @@ type ABI struct { | |||||||
| 	Constructor Method | 	Constructor Method | ||||||
| 	Methods     map[string]Method | 	Methods     map[string]Method | ||||||
| 	Events      map[string]Event | 	Events      map[string]Event | ||||||
|  | 
 | ||||||
|  | 	// Additional "special" functions introduced in solidity v0.6.0.
 | ||||||
|  | 	// It's separated from the original default fallback. Each contract
 | ||||||
|  | 	// can only define one fallback and receive function.
 | ||||||
|  | 	Fallback Method // Note it's also used to represent legacy fallback before v0.6.0
 | ||||||
|  | 	Receive  Method | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // JSON returns a parsed ABI interface and error if it failed.
 | // JSON returns a parsed ABI interface and error if it failed.
 | ||||||
| @ -42,7 +49,6 @@ func JSON(reader io.Reader) (ABI, error) { | |||||||
| 	if err := dec.Decode(&abi); err != nil { | 	if err := dec.Decode(&abi); err != nil { | ||||||
| 		return ABI{}, err | 		return ABI{}, err | ||||||
| 	} | 	} | ||||||
| 
 |  | ||||||
| 	return abi, nil | 	return abi, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -108,13 +114,22 @@ func (abi ABI) UnpackIntoMap(v map[string]interface{}, name string, data []byte) | |||||||
| // UnmarshalJSON implements json.Unmarshaler interface
 | // UnmarshalJSON implements json.Unmarshaler interface
 | ||||||
| func (abi *ABI) UnmarshalJSON(data []byte) error { | func (abi *ABI) UnmarshalJSON(data []byte) error { | ||||||
| 	var fields []struct { | 	var fields []struct { | ||||||
| 		Type            string | 		Type    string | ||||||
| 		Name            string | 		Name    string | ||||||
| 		Constant        bool | 		Inputs  []Argument | ||||||
|  | 		Outputs []Argument | ||||||
|  | 
 | ||||||
|  | 		// Status indicator which can be: "pure", "view",
 | ||||||
|  | 		// "nonpayable" or "payable".
 | ||||||
| 		StateMutability string | 		StateMutability string | ||||||
| 		Anonymous       bool | 
 | ||||||
| 		Inputs          []Argument | 		// Deprecated Status indicators, but removed in v0.6.0.
 | ||||||
| 		Outputs         []Argument | 		Constant bool // True if function is either pure or view
 | ||||||
|  | 		Payable  bool // True if function is payable
 | ||||||
|  | 
 | ||||||
|  | 		// Event relevant indicator represents the event is
 | ||||||
|  | 		// declared as anonymous.
 | ||||||
|  | 		Anonymous bool | ||||||
| 	} | 	} | ||||||
| 	if err := json.Unmarshal(data, &fields); err != nil { | 	if err := json.Unmarshal(data, &fields); err != nil { | ||||||
| 		return err | 		return err | ||||||
| @ -126,22 +141,82 @@ func (abi *ABI) UnmarshalJSON(data []byte) error { | |||||||
| 		case "constructor": | 		case "constructor": | ||||||
| 			abi.Constructor = Method{ | 			abi.Constructor = Method{ | ||||||
| 				Inputs: field.Inputs, | 				Inputs: field.Inputs, | ||||||
|  | 
 | ||||||
|  | 				// Note for constructor the `StateMutability` can only
 | ||||||
|  | 				// be payable or nonpayable according to the output of
 | ||||||
|  | 				// compiler. So constant is always false.
 | ||||||
|  | 				StateMutability: field.StateMutability, | ||||||
|  | 
 | ||||||
|  | 				// Legacy fields, keep them for backward compatibility
 | ||||||
|  | 				Constant: field.Constant, | ||||||
|  | 				Payable:  field.Payable, | ||||||
| 			} | 			} | ||||||
| 		// empty defaults to function according to the abi spec
 | 		case "function": | ||||||
| 		case "function", "": |  | ||||||
| 			name := field.Name | 			name := field.Name | ||||||
| 			_, ok := abi.Methods[name] | 			_, ok := abi.Methods[name] | ||||||
| 			for idx := 0; ok; idx++ { | 			for idx := 0; ok; idx++ { | ||||||
| 				name = fmt.Sprintf("%s%d", field.Name, idx) | 				name = fmt.Sprintf("%s%d", field.Name, idx) | ||||||
| 				_, ok = abi.Methods[name] | 				_, ok = abi.Methods[name] | ||||||
| 			} | 			} | ||||||
| 			isConst := field.Constant || field.StateMutability == "pure" || field.StateMutability == "view" |  | ||||||
| 			abi.Methods[name] = Method{ | 			abi.Methods[name] = Method{ | ||||||
| 				Name:    name, | 				Name:            name, | ||||||
| 				RawName: field.Name, | 				RawName:         field.Name, | ||||||
| 				Const:   isConst, | 				StateMutability: field.StateMutability, | ||||||
| 				Inputs:  field.Inputs, | 				Inputs:          field.Inputs, | ||||||
| 				Outputs: field.Outputs, | 				Outputs:         field.Outputs, | ||||||
|  | 
 | ||||||
|  | 				// Legacy fields, keep them for backward compatibility
 | ||||||
|  | 				Constant: field.Constant, | ||||||
|  | 				Payable:  field.Payable, | ||||||
|  | 			} | ||||||
|  | 		case "fallback": | ||||||
|  | 			// New introduced function type in v0.6.0, check more detail
 | ||||||
|  | 			// here https://solidity.readthedocs.io/en/v0.6.0/contracts.html#fallback-function
 | ||||||
|  | 			if abi.HasFallback() { | ||||||
|  | 				return errors.New("only single fallback is allowed") | ||||||
|  | 			} | ||||||
|  | 			abi.Fallback = Method{ | ||||||
|  | 				Name:    "", | ||||||
|  | 				RawName: "", | ||||||
|  | 
 | ||||||
|  | 				// The `StateMutability` can only be payable or nonpayable,
 | ||||||
|  | 				// so the constant is always false.
 | ||||||
|  | 				StateMutability: field.StateMutability, | ||||||
|  | 				IsFallback:      true, | ||||||
|  | 
 | ||||||
|  | 				// Fallback doesn't have any input or output
 | ||||||
|  | 				Inputs:  nil, | ||||||
|  | 				Outputs: nil, | ||||||
|  | 
 | ||||||
|  | 				// Legacy fields, keep them for backward compatibility
 | ||||||
|  | 				Constant: field.Constant, | ||||||
|  | 				Payable:  field.Payable, | ||||||
|  | 			} | ||||||
|  | 		case "receive": | ||||||
|  | 			// New introduced function type in v0.6.0, check more detail
 | ||||||
|  | 			// here https://solidity.readthedocs.io/en/v0.6.0/contracts.html#fallback-function
 | ||||||
|  | 			if abi.HasReceive() { | ||||||
|  | 				return errors.New("only single receive is allowed") | ||||||
|  | 			} | ||||||
|  | 			if field.StateMutability != "payable" { | ||||||
|  | 				return errors.New("the statemutability of receive can only be payable") | ||||||
|  | 			} | ||||||
|  | 			abi.Receive = Method{ | ||||||
|  | 				Name:    "", | ||||||
|  | 				RawName: "", | ||||||
|  | 
 | ||||||
|  | 				// The `StateMutability` can only be payable, so constant
 | ||||||
|  | 				// is always true while payable is always false.
 | ||||||
|  | 				StateMutability: field.StateMutability, | ||||||
|  | 				IsReceive:       true, | ||||||
|  | 
 | ||||||
|  | 				// Receive doesn't have any input or output
 | ||||||
|  | 				Inputs:  nil, | ||||||
|  | 				Outputs: nil, | ||||||
|  | 
 | ||||||
|  | 				// Legacy fields, keep them for backward compatibility
 | ||||||
|  | 				Constant: field.Constant, | ||||||
|  | 				Payable:  field.Payable, | ||||||
| 			} | 			} | ||||||
| 		case "event": | 		case "event": | ||||||
| 			name := field.Name | 			name := field.Name | ||||||
| @ -158,7 +233,6 @@ func (abi *ABI) UnmarshalJSON(data []byte) error { | |||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 |  | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -186,3 +260,13 @@ func (abi *ABI) EventByID(topic common.Hash) (*Event, error) { | |||||||
| 	} | 	} | ||||||
| 	return nil, fmt.Errorf("no event with id: %#x", topic.Hex()) | 	return nil, fmt.Errorf("no event with id: %#x", topic.Hex()) | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | // HasFallback returns an indicator whether a fallback function is included.
 | ||||||
|  | func (abi *ABI) HasFallback() bool { | ||||||
|  | 	return abi.Fallback.IsFallback | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // HasReceive returns an indicator whether a receive function is included.
 | ||||||
|  | func (abi *ABI) HasReceive() bool { | ||||||
|  | 	return abi.Receive.IsReceive | ||||||
|  | } | ||||||
|  | |||||||
| @ -31,29 +31,29 @@ import ( | |||||||
| 
 | 
 | ||||||
| const jsondata = ` | const jsondata = ` | ||||||
| [ | [ | ||||||
| 	{ "type" : "function", "name" : "balance", "constant" : true }, | 	{ "type" : "function", "name" : "balance", "stateMutability" : "view" }, | ||||||
| 	{ "type" : "function", "name" : "send", "constant" : false, "inputs" : [ { "name" : "amount", "type" : "uint256" } ] } | 	{ "type" : "function", "name" : "send", "inputs" : [ { "name" : "amount", "type" : "uint256" } ] } | ||||||
| ]` | ]` | ||||||
| 
 | 
 | ||||||
| const jsondata2 = ` | const jsondata2 = ` | ||||||
| [ | [ | ||||||
| 	{ "type" : "function", "name" : "balance", "constant" : true }, | 	{ "type" : "function", "name" : "balance", "stateMutability" : "view" }, | ||||||
| 	{ "type" : "function", "name" : "send", "constant" : false, "inputs" : [ { "name" : "amount", "type" : "uint256" } ] }, | 	{ "type" : "function", "name" : "send", "inputs" : [ { "name" : "amount", "type" : "uint256" } ] }, | ||||||
| 	{ "type" : "function", "name" : "test", "constant" : false, "inputs" : [ { "name" : "number", "type" : "uint32" } ] }, | 	{ "type" : "function", "name" : "test", "inputs" : [ { "name" : "number", "type" : "uint32" } ] }, | ||||||
| 	{ "type" : "function", "name" : "string", "constant" : false, "inputs" : [ { "name" : "inputs", "type" : "string" } ] }, | 	{ "type" : "function", "name" : "string", "inputs" : [ { "name" : "inputs", "type" : "string" } ] }, | ||||||
| 	{ "type" : "function", "name" : "bool", "constant" : false, "inputs" : [ { "name" : "inputs", "type" : "bool" } ] }, | 	{ "type" : "function", "name" : "bool", "inputs" : [ { "name" : "inputs", "type" : "bool" } ] }, | ||||||
| 	{ "type" : "function", "name" : "address", "constant" : false, "inputs" : [ { "name" : "inputs", "type" : "address" } ] }, | 	{ "type" : "function", "name" : "address", "inputs" : [ { "name" : "inputs", "type" : "address" } ] }, | ||||||
| 	{ "type" : "function", "name" : "uint64[2]", "constant" : false, "inputs" : [ { "name" : "inputs", "type" : "uint64[2]" } ] }, | 	{ "type" : "function", "name" : "uint64[2]", "inputs" : [ { "name" : "inputs", "type" : "uint64[2]" } ] }, | ||||||
| 	{ "type" : "function", "name" : "uint64[]", "constant" : false, "inputs" : [ { "name" : "inputs", "type" : "uint64[]" } ] }, | 	{ "type" : "function", "name" : "uint64[]", "inputs" : [ { "name" : "inputs", "type" : "uint64[]" } ] }, | ||||||
| 	{ "type" : "function", "name" : "foo", "constant" : false, "inputs" : [ { "name" : "inputs", "type" : "uint32" } ] }, | 	{ "type" : "function", "name" : "foo", "inputs" : [ { "name" : "inputs", "type" : "uint32" } ] }, | ||||||
| 	{ "type" : "function", "name" : "bar", "constant" : false, "inputs" : [ { "name" : "inputs", "type" : "uint32" }, { "name" : "string", "type" : "uint16" } ] }, | 	{ "type" : "function", "name" : "bar", "inputs" : [ { "name" : "inputs", "type" : "uint32" }, { "name" : "string", "type" : "uint16" } ] }, | ||||||
| 	{ "type" : "function", "name" : "slice", "constant" : false, "inputs" : [ { "name" : "inputs", "type" : "uint32[2]" } ] }, | 	{ "type" : "function", "name" : "slice", "inputs" : [ { "name" : "inputs", "type" : "uint32[2]" } ] }, | ||||||
| 	{ "type" : "function", "name" : "slice256", "constant" : false, "inputs" : [ { "name" : "inputs", "type" : "uint256[2]" } ] }, | 	{ "type" : "function", "name" : "slice256", "inputs" : [ { "name" : "inputs", "type" : "uint256[2]" } ] }, | ||||||
| 	{ "type" : "function", "name" : "sliceAddress", "constant" : false, "inputs" : [ { "name" : "inputs", "type" : "address[]" } ] }, | 	{ "type" : "function", "name" : "sliceAddress", "inputs" : [ { "name" : "inputs", "type" : "address[]" } ] }, | ||||||
| 	{ "type" : "function", "name" : "sliceMultiAddress", "constant" : false, "inputs" : [ { "name" : "a", "type" : "address[]" }, { "name" : "b", "type" : "address[]" } ] }, | 	{ "type" : "function", "name" : "sliceMultiAddress", "inputs" : [ { "name" : "a", "type" : "address[]" }, { "name" : "b", "type" : "address[]" } ] }, | ||||||
| 	{ "type" : "function", "name" : "nestedArray", "constant" : false, "inputs" : [ { "name" : "a", "type" : "uint256[2][2]" }, { "name" : "b", "type" : "address[]" } ] }, | 	{ "type" : "function", "name" : "nestedArray", "inputs" : [ { "name" : "a", "type" : "uint256[2][2]" }, { "name" : "b", "type" : "address[]" } ] }, | ||||||
| 	{ "type" : "function", "name" : "nestedArray2", "constant" : false, "inputs" : [ { "name" : "a", "type" : "uint8[][2]" } ] }, | 	{ "type" : "function", "name" : "nestedArray2", "inputs" : [ { "name" : "a", "type" : "uint8[][2]" } ] }, | ||||||
| 	{ "type" : "function", "name" : "nestedSlice", "constant" : false, "inputs" : [ { "name" : "a", "type" : "uint8[][]" } ] } | 	{ "type" : "function", "name" : "nestedSlice", "inputs" : [ { "name" : "a", "type" : "uint8[][]" } ] } | ||||||
| ]` | ]` | ||||||
| 
 | 
 | ||||||
| func TestReader(t *testing.T) { | func TestReader(t *testing.T) { | ||||||
| @ -61,10 +61,10 @@ func TestReader(t *testing.T) { | |||||||
| 	exp := ABI{ | 	exp := ABI{ | ||||||
| 		Methods: map[string]Method{ | 		Methods: map[string]Method{ | ||||||
| 			"balance": { | 			"balance": { | ||||||
| 				"balance", "balance", true, nil, nil, | 				"balance", "balance", "view", false, false, false, false, nil, nil, | ||||||
| 			}, | 			}, | ||||||
| 			"send": { | 			"send": { | ||||||
| 				"send", "send", false, []Argument{ | 				"send", "send", "", false, false, false, false, []Argument{ | ||||||
| 					{"amount", Uint256, false}, | 					{"amount", Uint256, false}, | ||||||
| 				}, nil, | 				}, nil, | ||||||
| 			}, | 			}, | ||||||
| @ -173,7 +173,7 @@ func TestTestSlice(t *testing.T) { | |||||||
| 
 | 
 | ||||||
| func TestMethodSignature(t *testing.T) { | func TestMethodSignature(t *testing.T) { | ||||||
| 	String, _ := NewType("string", "", nil) | 	String, _ := NewType("string", "", nil) | ||||||
| 	m := Method{"foo", "foo", false, []Argument{{"bar", String, false}, {"baz", String, false}}, nil} | 	m := Method{"foo", "foo", "", false, false, false, false, []Argument{{"bar", String, false}, {"baz", String, false}}, nil} | ||||||
| 	exp := "foo(string,string)" | 	exp := "foo(string,string)" | ||||||
| 	if m.Sig() != exp { | 	if m.Sig() != exp { | ||||||
| 		t.Error("signature mismatch", exp, "!=", m.Sig()) | 		t.Error("signature mismatch", exp, "!=", m.Sig()) | ||||||
| @ -185,7 +185,7 @@ func TestMethodSignature(t *testing.T) { | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	uintt, _ := NewType("uint256", "", nil) | 	uintt, _ := NewType("uint256", "", nil) | ||||||
| 	m = Method{"foo", "foo", false, []Argument{{"bar", uintt, false}}, nil} | 	m = Method{"foo", "foo", "", false, false, false, false, []Argument{{"bar", uintt, false}}, nil} | ||||||
| 	exp = "foo(uint256)" | 	exp = "foo(uint256)" | ||||||
| 	if m.Sig() != exp { | 	if m.Sig() != exp { | ||||||
| 		t.Error("signature mismatch", exp, "!=", m.Sig()) | 		t.Error("signature mismatch", exp, "!=", m.Sig()) | ||||||
| @ -204,7 +204,7 @@ func TestMethodSignature(t *testing.T) { | |||||||
| 			{Name: "y", Type: "int256"}, | 			{Name: "y", Type: "int256"}, | ||||||
| 		}}, | 		}}, | ||||||
| 	}) | 	}) | ||||||
| 	m = Method{"foo", "foo", false, []Argument{{"s", s, false}, {"bar", String, false}}, nil} | 	m = Method{"foo", "foo", "", false, false, false, false, []Argument{{"s", s, false}, {"bar", String, false}}, nil} | ||||||
| 	exp = "foo((int256,int256[],(int256,int256)[],(int256,int256)[2]),string)" | 	exp = "foo((int256,int256[],(int256,int256)[],(int256,int256)[2]),string)" | ||||||
| 	if m.Sig() != exp { | 	if m.Sig() != exp { | ||||||
| 		t.Error("signature mismatch", exp, "!=", m.Sig()) | 		t.Error("signature mismatch", exp, "!=", m.Sig()) | ||||||
| @ -582,7 +582,7 @@ func TestInputFixedArrayAndVariableInputLength(t *testing.T) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestDefaultFunctionParsing(t *testing.T) { | func TestDefaultFunctionParsing(t *testing.T) { | ||||||
| 	const definition = `[{ "name" : "balance" }]` | 	const definition = `[{ "name" : "balance", "type" : "function" }]` | ||||||
| 
 | 
 | ||||||
| 	abi, err := JSON(strings.NewReader(definition)) | 	abi, err := JSON(strings.NewReader(definition)) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
|  | |||||||
| @ -171,12 +171,24 @@ func (c *BoundContract) Transact(opts *TransactOpts, method string, params ...in | |||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
|  | 	// todo(rjl493456442) check the method is payable or not,
 | ||||||
|  | 	// reject invalid transaction at the first place
 | ||||||
| 	return c.transact(opts, &c.address, input) | 	return c.transact(opts, &c.address, input) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // RawTransact initiates a transaction with the given raw calldata as the input.
 | ||||||
|  | // It's usually used to initiates transaction for invoking **Fallback** function.
 | ||||||
|  | func (c *BoundContract) RawTransact(opts *TransactOpts, calldata []byte) (*types.Transaction, error) { | ||||||
|  | 	// todo(rjl493456442) check the method is payable or not,
 | ||||||
|  | 	// reject invalid transaction at the first place
 | ||||||
|  | 	return c.transact(opts, &c.address, calldata) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // Transfer initiates a plain transaction to move funds to the contract, calling
 | // Transfer initiates a plain transaction to move funds to the contract, calling
 | ||||||
| // its default method if one is available.
 | // its default method if one is available.
 | ||||||
| func (c *BoundContract) Transfer(opts *TransactOpts) (*types.Transaction, error) { | func (c *BoundContract) Transfer(opts *TransactOpts) (*types.Transaction, error) { | ||||||
|  | 	// todo(rjl493456442) check the payable fallback or receive is defined
 | ||||||
|  | 	// or not, reject invalid transaction at the first place
 | ||||||
| 	return c.transact(opts, &c.address, nil) | 	return c.transact(opts, &c.address, nil) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -77,6 +77,8 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string] | |||||||
| 			calls     = make(map[string]*tmplMethod) | 			calls     = make(map[string]*tmplMethod) | ||||||
| 			transacts = make(map[string]*tmplMethod) | 			transacts = make(map[string]*tmplMethod) | ||||||
| 			events    = make(map[string]*tmplEvent) | 			events    = make(map[string]*tmplEvent) | ||||||
|  | 			fallback  *tmplMethod | ||||||
|  | 			receive   *tmplMethod | ||||||
| 
 | 
 | ||||||
| 			// identifiers are used to detect duplicated identifier of function
 | 			// identifiers are used to detect duplicated identifier of function
 | ||||||
| 			// and event. For all calls, transacts and events, abigen will generate
 | 			// and event. For all calls, transacts and events, abigen will generate
 | ||||||
| @ -92,7 +94,7 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string] | |||||||
| 			normalizedName := methodNormalizer[lang](alias(aliases, original.Name)) | 			normalizedName := methodNormalizer[lang](alias(aliases, original.Name)) | ||||||
| 			// Ensure there is no duplicated identifier
 | 			// Ensure there is no duplicated identifier
 | ||||||
| 			var identifiers = callIdentifiers | 			var identifiers = callIdentifiers | ||||||
| 			if !original.Const { | 			if !original.IsConstant() { | ||||||
| 				identifiers = transactIdentifiers | 				identifiers = transactIdentifiers | ||||||
| 			} | 			} | ||||||
| 			if identifiers[normalizedName] { | 			if identifiers[normalizedName] { | ||||||
| @ -121,7 +123,7 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string] | |||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 			// Append the methods to the call or transact lists
 | 			// Append the methods to the call or transact lists
 | ||||||
| 			if original.Const { | 			if original.IsConstant() { | ||||||
| 				calls[original.Name] = &tmplMethod{Original: original, Normalized: normalized, Structured: structured(original.Outputs)} | 				calls[original.Name] = &tmplMethod{Original: original, Normalized: normalized, Structured: structured(original.Outputs)} | ||||||
| 			} else { | 			} else { | ||||||
| 				transacts[original.Name] = &tmplMethod{Original: original, Normalized: normalized, Structured: structured(original.Outputs)} | 				transacts[original.Name] = &tmplMethod{Original: original, Normalized: normalized, Structured: structured(original.Outputs)} | ||||||
| @ -156,7 +158,13 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string] | |||||||
| 			// Append the event to the accumulator list
 | 			// Append the event to the accumulator list
 | ||||||
| 			events[original.Name] = &tmplEvent{Original: original, Normalized: normalized} | 			events[original.Name] = &tmplEvent{Original: original, Normalized: normalized} | ||||||
| 		} | 		} | ||||||
| 
 | 		// Add two special fallback functions if they exist
 | ||||||
|  | 		if evmABI.HasFallback() { | ||||||
|  | 			fallback = &tmplMethod{Original: evmABI.Fallback} | ||||||
|  | 		} | ||||||
|  | 		if evmABI.HasReceive() { | ||||||
|  | 			receive = &tmplMethod{Original: evmABI.Receive} | ||||||
|  | 		} | ||||||
| 		// There is no easy way to pass arbitrary java objects to the Go side.
 | 		// There is no easy way to pass arbitrary java objects to the Go side.
 | ||||||
| 		if len(structs) > 0 && lang == LangJava { | 		if len(structs) > 0 && lang == LangJava { | ||||||
| 			return "", errors.New("java binding for tuple arguments is not supported yet") | 			return "", errors.New("java binding for tuple arguments is not supported yet") | ||||||
| @ -169,6 +177,8 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string] | |||||||
| 			Constructor: evmABI.Constructor, | 			Constructor: evmABI.Constructor, | ||||||
| 			Calls:       calls, | 			Calls:       calls, | ||||||
| 			Transacts:   transacts, | 			Transacts:   transacts, | ||||||
|  | 			Fallback:    fallback, | ||||||
|  | 			Receive:     receive, | ||||||
| 			Events:      events, | 			Events:      events, | ||||||
| 			Libraries:   make(map[string]string), | 			Libraries:   make(map[string]string), | ||||||
| 		} | 		} | ||||||
| @ -619,11 +629,22 @@ func formatMethod(method abi.Method, structs map[string]*tmplStruct) string { | |||||||
| 			outputs[i] += fmt.Sprintf(" %v", output.Name) | 			outputs[i] += fmt.Sprintf(" %v", output.Name) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	constant := "" | 	// Extract meaningful state mutability of solidity method.
 | ||||||
| 	if method.Const { | 	// If it's default value, never print it.
 | ||||||
| 		constant = "constant " | 	state := method.StateMutability | ||||||
|  | 	if state == "nonpayable" { | ||||||
|  | 		state = "" | ||||||
| 	} | 	} | ||||||
| 	return fmt.Sprintf("function %v(%v) %sreturns(%v)", method.RawName, strings.Join(inputs, ", "), constant, strings.Join(outputs, ", ")) | 	if state != "" { | ||||||
|  | 		state = state + " " | ||||||
|  | 	} | ||||||
|  | 	identity := fmt.Sprintf("function %v", method.RawName) | ||||||
|  | 	if method.IsFallback { | ||||||
|  | 		identity = "fallback" | ||||||
|  | 	} else if method.IsReceive { | ||||||
|  | 		identity = "receive" | ||||||
|  | 	} | ||||||
|  | 	return fmt.Sprintf("%s(%v) %sreturns(%v)", identity, strings.Join(inputs, ", "), state, strings.Join(outputs, ", ")) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // formatEvent transforms raw event representation into a user friendly one.
 | // formatEvent transforms raw event representation into a user friendly one.
 | ||||||
|  | |||||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @ -35,6 +35,8 @@ type tmplContract struct { | |||||||
| 	Constructor abi.Method             // Contract constructor for deploy parametrization
 | 	Constructor abi.Method             // Contract constructor for deploy parametrization
 | ||||||
| 	Calls       map[string]*tmplMethod // Contract calls that only read state data
 | 	Calls       map[string]*tmplMethod // Contract calls that only read state data
 | ||||||
| 	Transacts   map[string]*tmplMethod // Contract calls that write state data
 | 	Transacts   map[string]*tmplMethod // Contract calls that write state data
 | ||||||
|  | 	Fallback    *tmplMethod            // Additional special fallback function
 | ||||||
|  | 	Receive     *tmplMethod            // Additional special receive function
 | ||||||
| 	Events      map[string]*tmplEvent  // Contract events accessors
 | 	Events      map[string]*tmplEvent  // Contract events accessors
 | ||||||
| 	Libraries   map[string]string      // Same as tmplData, but filtered to only keep what the contract needs
 | 	Libraries   map[string]string      // Same as tmplData, but filtered to only keep what the contract needs
 | ||||||
| 	Library     bool                   // Indicator whether the contract is a library
 | 	Library     bool                   // Indicator whether the contract is a library
 | ||||||
| @ -351,6 +353,52 @@ var ( | |||||||
| 		} | 		} | ||||||
| 	{{end}} | 	{{end}} | ||||||
| 
 | 
 | ||||||
|  | 	{{if .Fallback}}  | ||||||
|  | 		// Fallback is a paid mutator transaction binding the contract fallback function.
 | ||||||
|  | 		//
 | ||||||
|  | 		// Solidity: {{formatmethod .Fallback.Original $structs}}
 | ||||||
|  | 		func (_{{$contract.Type}} *{{$contract.Type}}Transactor) Fallback(opts *bind.TransactOpts, calldata []byte) (*types.Transaction, error) { | ||||||
|  | 			return _{{$contract.Type}}.contract.RawTransact(opts, calldata) | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		// Fallback is a paid mutator transaction binding the contract fallback function.
 | ||||||
|  | 		//
 | ||||||
|  | 		// Solidity: {{formatmethod .Fallback.Original $structs}}
 | ||||||
|  | 		func (_{{$contract.Type}} *{{$contract.Type}}Session) Fallback(calldata []byte) (*types.Transaction, error) { | ||||||
|  | 		  return _{{$contract.Type}}.Contract.Fallback(&_{{$contract.Type}}.TransactOpts, calldata) | ||||||
|  | 		} | ||||||
|  | 	 | ||||||
|  | 		// Fallback is a paid mutator transaction binding the contract fallback function.
 | ||||||
|  | 		// 
 | ||||||
|  | 		// Solidity: {{formatmethod .Fallback.Original $structs}}
 | ||||||
|  | 		func (_{{$contract.Type}} *{{$contract.Type}}TransactorSession) Fallback(calldata []byte) (*types.Transaction, error) { | ||||||
|  | 		  return _{{$contract.Type}}.Contract.Fallback(&_{{$contract.Type}}.TransactOpts, calldata) | ||||||
|  | 		} | ||||||
|  | 	{{end}} | ||||||
|  | 
 | ||||||
|  | 	{{if .Receive}}  | ||||||
|  | 		// Receive is a paid mutator transaction binding the contract receive function.
 | ||||||
|  | 		//
 | ||||||
|  | 		// Solidity: {{formatmethod .Receive.Original $structs}}
 | ||||||
|  | 		func (_{{$contract.Type}} *{{$contract.Type}}Transactor) Receive(opts *bind.TransactOpts) (*types.Transaction, error) { | ||||||
|  | 			return _{{$contract.Type}}.contract.RawTransact(opts, nil) // calldata is disallowed for receive function
 | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		// Receive is a paid mutator transaction binding the contract receive function.
 | ||||||
|  | 		//
 | ||||||
|  | 		// Solidity: {{formatmethod .Receive.Original $structs}}
 | ||||||
|  | 		func (_{{$contract.Type}} *{{$contract.Type}}Session) Receive() (*types.Transaction, error) { | ||||||
|  | 		  return _{{$contract.Type}}.Contract.Receive(&_{{$contract.Type}}.TransactOpts) | ||||||
|  | 		} | ||||||
|  | 	 | ||||||
|  | 		// Receive is a paid mutator transaction binding the contract receive function.
 | ||||||
|  | 		// 
 | ||||||
|  | 		// Solidity: {{formatmethod .Receive.Original $structs}}
 | ||||||
|  | 		func (_{{$contract.Type}} *{{$contract.Type}}TransactorSession) Receive() (*types.Transaction, error) { | ||||||
|  | 		  return _{{$contract.Type}}.Contract.Receive(&_{{$contract.Type}}.TransactOpts) | ||||||
|  | 		} | ||||||
|  | 	{{end}} | ||||||
|  | 
 | ||||||
| 	{{range .Events}} | 	{{range .Events}} | ||||||
| 		// {{$contract.Type}}{{.Normalized.Name}}Iterator is returned from Filter{{.Normalized.Name}} and is used to iterate over the raw logs and unpacked data for {{.Normalized.Name}} events raised by the {{$contract.Type}} contract.
 | 		// {{$contract.Type}}{{.Normalized.Name}}Iterator is returned from Filter{{.Normalized.Name}} and is used to iterate over the raw logs and unpacked data for {{.Normalized.Name}} events raised by the {{$contract.Type}} contract.
 | ||||||
| 		type {{$contract.Type}}{{.Normalized.Name}}Iterator struct { | 		type {{$contract.Type}}{{.Normalized.Name}}Iterator struct { | ||||||
| @ -611,6 +659,24 @@ import java.util.*; | |||||||
| 		return this.Contract.transact(opts, "{{.Original.Name}}"	, args); | 		return this.Contract.transact(opts, "{{.Original.Name}}"	, args); | ||||||
| 	} | 	} | ||||||
| 	{{end}} | 	{{end}} | ||||||
|  | 
 | ||||||
|  |     {{if .Fallback}} | ||||||
|  | 	// Fallback is a paid mutator transaction binding the contract fallback function.
 | ||||||
|  | 	//
 | ||||||
|  | 	// Solidity: {{formatmethod .Fallback.Original $structs}}
 | ||||||
|  | 	public Transaction Fallback(TransactOpts opts, byte[] calldata) throws Exception {  | ||||||
|  | 		return this.Contract.rawTransact(opts, calldata); | ||||||
|  | 	} | ||||||
|  |     {{end}} | ||||||
|  | 
 | ||||||
|  |     {{if .Receive}} | ||||||
|  | 	// Receive is a paid mutator transaction binding the contract receive function.
 | ||||||
|  | 	//
 | ||||||
|  | 	// Solidity: {{formatmethod .Receive.Original $structs}}
 | ||||||
|  | 	public Transaction Receive(TransactOpts opts) throws Exception {  | ||||||
|  | 		return this.Contract.rawTransact(opts, null); | ||||||
|  | 	} | ||||||
|  |     {{end}} | ||||||
| } | } | ||||||
| {{end}} | {{end}} | ||||||
| ` | ` | ||||||
|  | |||||||
| @ -41,10 +41,23 @@ type Method struct { | |||||||
| 	// * foo(uint,uint)
 | 	// * foo(uint,uint)
 | ||||||
| 	// The method name of the first one will be resolved as foo while the second one
 | 	// The method name of the first one will be resolved as foo while the second one
 | ||||||
| 	// will be resolved as foo0.
 | 	// will be resolved as foo0.
 | ||||||
| 	Name string | 	Name    string | ||||||
| 	// RawName is the raw method name parsed from ABI.
 | 	RawName string // RawName is the raw method name parsed from ABI
 | ||||||
| 	RawName string | 
 | ||||||
| 	Const   bool | 	// StateMutability indicates the mutability state of method,
 | ||||||
|  | 	// the default value is nonpayable. It can be empty if the abi
 | ||||||
|  | 	// is generated by legacy compiler.
 | ||||||
|  | 	StateMutability string | ||||||
|  | 
 | ||||||
|  | 	// Legacy indicators generated by compiler before v0.6.0
 | ||||||
|  | 	Constant bool | ||||||
|  | 	Payable  bool | ||||||
|  | 
 | ||||||
|  | 	// The following two flags indicates whether the method is a
 | ||||||
|  | 	// special fallback introduced in solidity v0.6.0
 | ||||||
|  | 	IsFallback bool | ||||||
|  | 	IsReceive  bool | ||||||
|  | 
 | ||||||
| 	Inputs  Arguments | 	Inputs  Arguments | ||||||
| 	Outputs Arguments | 	Outputs Arguments | ||||||
| } | } | ||||||
| @ -57,6 +70,11 @@ type Method struct { | |||||||
| //
 | //
 | ||||||
| // Please note that "int" is substitute for its canonical representation "int256"
 | // Please note that "int" is substitute for its canonical representation "int256"
 | ||||||
| func (method Method) Sig() string { | func (method Method) Sig() string { | ||||||
|  | 	// Short circuit if the method is special. Fallback
 | ||||||
|  | 	// and Receive don't have signature at all.
 | ||||||
|  | 	if method.IsFallback || method.IsReceive { | ||||||
|  | 		return "" | ||||||
|  | 	} | ||||||
| 	types := make([]string, len(method.Inputs)) | 	types := make([]string, len(method.Inputs)) | ||||||
| 	for i, input := range method.Inputs { | 	for i, input := range method.Inputs { | ||||||
| 		types[i] = input.Type.String() | 		types[i] = input.Type.String() | ||||||
| @ -76,11 +94,22 @@ func (method Method) String() string { | |||||||
| 			outputs[i] += fmt.Sprintf(" %v", output.Name) | 			outputs[i] += fmt.Sprintf(" %v", output.Name) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	constant := "" | 	// Extract meaningful state mutability of solidity method.
 | ||||||
| 	if method.Const { | 	// If it's default value, never print it.
 | ||||||
| 		constant = "constant " | 	state := method.StateMutability | ||||||
|  | 	if state == "nonpayable" { | ||||||
|  | 		state = "" | ||||||
| 	} | 	} | ||||||
| 	return fmt.Sprintf("function %v(%v) %sreturns(%v)", method.RawName, strings.Join(inputs, ", "), constant, strings.Join(outputs, ", ")) | 	if state != "" { | ||||||
|  | 		state = state + " " | ||||||
|  | 	} | ||||||
|  | 	identity := fmt.Sprintf("function %v", method.RawName) | ||||||
|  | 	if method.IsFallback { | ||||||
|  | 		identity = "fallback" | ||||||
|  | 	} else if method.IsReceive { | ||||||
|  | 		identity = "receive" | ||||||
|  | 	} | ||||||
|  | 	return fmt.Sprintf("%v(%v) %sreturns(%v)", identity, strings.Join(inputs, ", "), state, strings.Join(outputs, ", ")) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // ID returns the canonical representation of the method's signature used by the
 | // ID returns the canonical representation of the method's signature used by the
 | ||||||
| @ -88,3 +117,14 @@ func (method Method) String() string { | |||||||
| func (method Method) ID() []byte { | func (method Method) ID() []byte { | ||||||
| 	return crypto.Keccak256([]byte(method.Sig()))[:4] | 	return crypto.Keccak256([]byte(method.Sig()))[:4] | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | // IsConstant returns the indicator whether the method is read-only.
 | ||||||
|  | func (method Method) IsConstant() bool { | ||||||
|  | 	return method.StateMutability == "view" || method.StateMutability == "pure" || method.Constant | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // IsPayable returns the indicator whether the method can process
 | ||||||
|  | // plain ether transfers.
 | ||||||
|  | func (method Method) IsPayable() bool { | ||||||
|  | 	return method.StateMutability == "payable" || method.Payable | ||||||
|  | } | ||||||
|  | |||||||
| @ -23,13 +23,15 @@ import ( | |||||||
| 
 | 
 | ||||||
| const methoddata = ` | const methoddata = ` | ||||||
| [ | [ | ||||||
| 	{"type": "function", "name": "balance", "constant": true }, | 	{"type": "function", "name": "balance", "stateMutability": "view"}, | ||||||
| 	{"type": "function", "name": "send", "constant": false, "inputs": [{ "name": "amount", "type": "uint256" }]}, | 	{"type": "function", "name": "send", "inputs": [{ "name": "amount", "type": "uint256" }]}, | ||||||
| 	{"type": "function", "name": "transfer", "constant": false, "inputs": [{"name": "from", "type": "address"}, {"name": "to", "type": "address"}, {"name": "value", "type": "uint256"}], "outputs": [{"name": "success", "type": "bool"}]}, | 	{"type": "function", "name": "transfer", "inputs": [{"name": "from", "type": "address"}, {"name": "to", "type": "address"}, {"name": "value", "type": "uint256"}], "outputs": [{"name": "success", "type": "bool"}]}, | ||||||
| 	{"constant":false,"inputs":[{"components":[{"name":"x","type":"uint256"},{"name":"y","type":"uint256"}],"name":"a","type":"tuple"}],"name":"tuple","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}, | 	{"constant":false,"inputs":[{"components":[{"name":"x","type":"uint256"},{"name":"y","type":"uint256"}],"name":"a","type":"tuple"}],"name":"tuple","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}, | ||||||
| 	{"constant":false,"inputs":[{"components":[{"name":"x","type":"uint256"},{"name":"y","type":"uint256"}],"name":"a","type":"tuple[]"}],"name":"tupleSlice","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}, | 	{"constant":false,"inputs":[{"components":[{"name":"x","type":"uint256"},{"name":"y","type":"uint256"}],"name":"a","type":"tuple[]"}],"name":"tupleSlice","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}, | ||||||
| 	{"constant":false,"inputs":[{"components":[{"name":"x","type":"uint256"},{"name":"y","type":"uint256"}],"name":"a","type":"tuple[5]"}],"name":"tupleArray","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}, | 	{"constant":false,"inputs":[{"components":[{"name":"x","type":"uint256"},{"name":"y","type":"uint256"}],"name":"a","type":"tuple[5]"}],"name":"tupleArray","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}, | ||||||
| 	{"constant":false,"inputs":[{"components":[{"name":"x","type":"uint256"},{"name":"y","type":"uint256"}],"name":"a","type":"tuple[5][]"}],"name":"complexTuple","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"} | 	{"constant":false,"inputs":[{"components":[{"name":"x","type":"uint256"},{"name":"y","type":"uint256"}],"name":"a","type":"tuple[5][]"}],"name":"complexTuple","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}, | ||||||
|  | 	{"stateMutability":"nonpayable","type":"fallback"}, | ||||||
|  | 	{"stateMutability":"payable","type":"receive"} | ||||||
| ]` | ]` | ||||||
| 
 | 
 | ||||||
| func TestMethodString(t *testing.T) { | func TestMethodString(t *testing.T) { | ||||||
| @ -39,7 +41,7 @@ func TestMethodString(t *testing.T) { | |||||||
| 	}{ | 	}{ | ||||||
| 		{ | 		{ | ||||||
| 			method:      "balance", | 			method:      "balance", | ||||||
| 			expectation: "function balance() constant returns()", | 			expectation: "function balance() view returns()", | ||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			method:      "send", | 			method:      "send", | ||||||
| @ -65,6 +67,14 @@ func TestMethodString(t *testing.T) { | |||||||
| 			method:      "complexTuple", | 			method:      "complexTuple", | ||||||
| 			expectation: "function complexTuple((uint256,uint256)[5][] a) returns()", | 			expectation: "function complexTuple((uint256,uint256)[5][] a) returns()", | ||||||
| 		}, | 		}, | ||||||
|  | 		{ | ||||||
|  | 			method:      "fallback", | ||||||
|  | 			expectation: "fallback() returns()", | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			method:      "receive", | ||||||
|  | 			expectation: "receive() payable returns()", | ||||||
|  | 		}, | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	abi, err := JSON(strings.NewReader(methoddata)) | 	abi, err := JSON(strings.NewReader(methoddata)) | ||||||
| @ -73,7 +83,14 @@ func TestMethodString(t *testing.T) { | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	for _, test := range table { | 	for _, test := range table { | ||||||
| 		got := abi.Methods[test.method].String() | 		var got string | ||||||
|  | 		if test.method == "fallback" { | ||||||
|  | 			got = abi.Fallback.String() | ||||||
|  | 		} else if test.method == "receive" { | ||||||
|  | 			got = abi.Receive.String() | ||||||
|  | 		} else { | ||||||
|  | 			got = abi.Methods[test.method].String() | ||||||
|  | 		} | ||||||
| 		if got != test.expectation { | 		if got != test.expectation { | ||||||
| 			t.Errorf("expected string to be %s, got %s", test.expectation, got) | 			t.Errorf("expected string to be %s, got %s", test.expectation, got) | ||||||
| 		} | 		} | ||||||
|  | |||||||
| @ -443,7 +443,7 @@ var unpackTests = []unpackTest{ | |||||||
| func TestUnpack(t *testing.T) { | func TestUnpack(t *testing.T) { | ||||||
| 	for i, test := range unpackTests { | 	for i, test := range unpackTests { | ||||||
| 		t.Run(strconv.Itoa(i), func(t *testing.T) { | 		t.Run(strconv.Itoa(i), func(t *testing.T) { | ||||||
| 			def := fmt.Sprintf(`[{ "name" : "method", "outputs": %s}]`, test.def) | 			def := fmt.Sprintf(`[{ "name" : "method", "type": "function", "outputs": %s}]`, test.def) | ||||||
| 			abi, err := JSON(strings.NewReader(def)) | 			abi, err := JSON(strings.NewReader(def)) | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				t.Fatalf("invalid ABI definition %s: %v", def, err) | 				t.Fatalf("invalid ABI definition %s: %v", def, err) | ||||||
| @ -522,7 +522,7 @@ type methodMultiOutput struct { | |||||||
| 
 | 
 | ||||||
| func methodMultiReturn(require *require.Assertions) (ABI, []byte, methodMultiOutput) { | func methodMultiReturn(require *require.Assertions) (ABI, []byte, methodMultiOutput) { | ||||||
| 	const definition = `[ | 	const definition = `[ | ||||||
| 	{ "name" : "multi", "constant" : false, "outputs": [ { "name": "Int", "type": "uint256" }, { "name": "String", "type": "string" } ] }]` | 	{ "name" : "multi", "type": "function", "outputs": [ { "name": "Int", "type": "uint256" }, { "name": "String", "type": "string" } ] }]` | ||||||
| 	var expected = methodMultiOutput{big.NewInt(1), "hello"} | 	var expected = methodMultiOutput{big.NewInt(1), "hello"} | ||||||
| 
 | 
 | ||||||
| 	abi, err := JSON(strings.NewReader(definition)) | 	abi, err := JSON(strings.NewReader(definition)) | ||||||
| @ -611,7 +611,7 @@ func TestMethodMultiReturn(t *testing.T) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestMultiReturnWithArray(t *testing.T) { | func TestMultiReturnWithArray(t *testing.T) { | ||||||
| 	const definition = `[{"name" : "multi", "outputs": [{"type": "uint64[3]"}, {"type": "uint64"}]}]` | 	const definition = `[{"name" : "multi", "type": "function", "outputs": [{"type": "uint64[3]"}, {"type": "uint64"}]}]` | ||||||
| 	abi, err := JSON(strings.NewReader(definition)) | 	abi, err := JSON(strings.NewReader(definition)) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		t.Fatal(err) | 		t.Fatal(err) | ||||||
| @ -634,7 +634,7 @@ func TestMultiReturnWithArray(t *testing.T) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestMultiReturnWithStringArray(t *testing.T) { | func TestMultiReturnWithStringArray(t *testing.T) { | ||||||
| 	const definition = `[{"name" : "multi", "outputs": [{"name": "","type": "uint256[3]"},{"name": "","type": "address"},{"name": "","type": "string[2]"},{"name": "","type": "bool"}]}]` | 	const definition = `[{"name" : "multi", "type": "function", "outputs": [{"name": "","type": "uint256[3]"},{"name": "","type": "address"},{"name": "","type": "string[2]"},{"name": "","type": "bool"}]}]` | ||||||
| 	abi, err := JSON(strings.NewReader(definition)) | 	abi, err := JSON(strings.NewReader(definition)) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		t.Fatal(err) | 		t.Fatal(err) | ||||||
| @ -664,7 +664,7 @@ func TestMultiReturnWithStringArray(t *testing.T) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestMultiReturnWithStringSlice(t *testing.T) { | func TestMultiReturnWithStringSlice(t *testing.T) { | ||||||
| 	const definition = `[{"name" : "multi", "outputs": [{"name": "","type": "string[]"},{"name": "","type": "uint256[]"}]}]` | 	const definition = `[{"name" : "multi", "type": "function", "outputs": [{"name": "","type": "string[]"},{"name": "","type": "uint256[]"}]}]` | ||||||
| 	abi, err := JSON(strings.NewReader(definition)) | 	abi, err := JSON(strings.NewReader(definition)) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		t.Fatal(err) | 		t.Fatal(err) | ||||||
| @ -700,7 +700,7 @@ func TestMultiReturnWithDeeplyNestedArray(t *testing.T) { | |||||||
| 	//  values of nested static arrays count towards the size as well, and any element following
 | 	//  values of nested static arrays count towards the size as well, and any element following
 | ||||||
| 	//  after such nested array argument should be read with the correct offset,
 | 	//  after such nested array argument should be read with the correct offset,
 | ||||||
| 	//  so that it does not read content from the previous array argument.
 | 	//  so that it does not read content from the previous array argument.
 | ||||||
| 	const definition = `[{"name" : "multi", "outputs": [{"type": "uint64[3][2][4]"}, {"type": "uint64"}]}]` | 	const definition = `[{"name" : "multi", "type": "function", "outputs": [{"type": "uint64[3][2][4]"}, {"type": "uint64"}]}]` | ||||||
| 	abi, err := JSON(strings.NewReader(definition)) | 	abi, err := JSON(strings.NewReader(definition)) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		t.Fatal(err) | 		t.Fatal(err) | ||||||
| @ -737,15 +737,15 @@ func TestMultiReturnWithDeeplyNestedArray(t *testing.T) { | |||||||
| 
 | 
 | ||||||
| func TestUnmarshal(t *testing.T) { | func TestUnmarshal(t *testing.T) { | ||||||
| 	const definition = `[ | 	const definition = `[ | ||||||
| 	{ "name" : "int", "constant" : false, "outputs": [ { "type": "uint256" } ] }, | 	{ "name" : "int", "type": "function", "outputs": [ { "type": "uint256" } ] }, | ||||||
| 	{ "name" : "bool", "constant" : false, "outputs": [ { "type": "bool" } ] }, | 	{ "name" : "bool", "type": "function", "outputs": [ { "type": "bool" } ] }, | ||||||
| 	{ "name" : "bytes", "constant" : false, "outputs": [ { "type": "bytes" } ] }, | 	{ "name" : "bytes", "type": "function", "outputs": [ { "type": "bytes" } ] }, | ||||||
| 	{ "name" : "fixed", "constant" : false, "outputs": [ { "type": "bytes32" } ] }, | 	{ "name" : "fixed", "type": "function", "outputs": [ { "type": "bytes32" } ] }, | ||||||
| 	{ "name" : "multi", "constant" : false, "outputs": [ { "type": "bytes" }, { "type": "bytes" } ] }, | 	{ "name" : "multi", "type": "function", "outputs": [ { "type": "bytes" }, { "type": "bytes" } ] }, | ||||||
| 	{ "name" : "intArraySingle", "constant" : false, "outputs": [ { "type": "uint256[3]" } ] }, | 	{ "name" : "intArraySingle", "type": "function", "outputs": [ { "type": "uint256[3]" } ] }, | ||||||
| 	{ "name" : "addressSliceSingle", "constant" : false, "outputs": [ { "type": "address[]" } ] }, | 	{ "name" : "addressSliceSingle", "type": "function", "outputs": [ { "type": "address[]" } ] }, | ||||||
| 	{ "name" : "addressSliceDouble", "constant" : false, "outputs": [ { "name": "a", "type": "address[]" }, { "name": "b", "type": "address[]" } ] }, | 	{ "name" : "addressSliceDouble", "type": "function", "outputs": [ { "name": "a", "type": "address[]" }, { "name": "b", "type": "address[]" } ] }, | ||||||
| 	{ "name" : "mixedBytes", "constant" : true, "outputs": [ { "name": "a", "type": "bytes" }, { "name": "b", "type": "bytes32" } ] }]` | 	{ "name" : "mixedBytes", "type": "function", "stateMutability" : "view", "outputs": [ { "name": "a", "type": "bytes" }, { "name": "b", "type": "bytes32" } ] }]` | ||||||
| 
 | 
 | ||||||
| 	abi, err := JSON(strings.NewReader(definition)) | 	abi, err := JSON(strings.NewReader(definition)) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| @ -985,7 +985,7 @@ func TestUnmarshal(t *testing.T) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestUnpackTuple(t *testing.T) { | func TestUnpackTuple(t *testing.T) { | ||||||
| 	const simpleTuple = `[{"name":"tuple","constant":false,"outputs":[{"type":"tuple","name":"ret","components":[{"type":"int256","name":"a"},{"type":"int256","name":"b"}]}]}]` | 	const simpleTuple = `[{"name":"tuple","type":"function","outputs":[{"type":"tuple","name":"ret","components":[{"type":"int256","name":"a"},{"type":"int256","name":"b"}]}]}]` | ||||||
| 	abi, err := JSON(strings.NewReader(simpleTuple)) | 	abi, err := JSON(strings.NewReader(simpleTuple)) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		t.Fatal(err) | 		t.Fatal(err) | ||||||
| @ -1014,7 +1014,7 @@ func TestUnpackTuple(t *testing.T) { | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Test nested tuple
 | 	// Test nested tuple
 | ||||||
| 	const nestedTuple = `[{"name":"tuple","constant":false,"outputs":[ | 	const nestedTuple = `[{"name":"tuple","type":"function","outputs":[ | ||||||
| 		{"type":"tuple","name":"s","components":[{"type":"uint256","name":"a"},{"type":"uint256[]","name":"b"},{"type":"tuple[]","name":"c","components":[{"name":"x", "type":"uint256"},{"name":"y","type":"uint256"}]}]}, | 		{"type":"tuple","name":"s","components":[{"type":"uint256","name":"a"},{"type":"uint256[]","name":"b"},{"type":"tuple[]","name":"c","components":[{"name":"x", "type":"uint256"},{"name":"y","type":"uint256"}]}]}, | ||||||
| 		{"type":"tuple","name":"t","components":[{"name":"x", "type":"uint256"},{"name":"y","type":"uint256"}]}, | 		{"type":"tuple","name":"t","components":[{"name":"x", "type":"uint256"},{"name":"y","type":"uint256"}]}, | ||||||
| 		{"type":"uint256","name":"a"} | 		{"type":"uint256","name":"a"} | ||||||
| @ -1136,7 +1136,7 @@ func TestOOMMaliciousInput(t *testing.T) { | |||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
| 	for i, test := range oomTests { | 	for i, test := range oomTests { | ||||||
| 		def := fmt.Sprintf(`[{ "name" : "method", "outputs": %s}]`, test.def) | 		def := fmt.Sprintf(`[{ "name" : "method", "type": "function", "outputs": %s}]`, test.def) | ||||||
| 		abi, err := JSON(strings.NewReader(def)) | 		abi, err := JSON(strings.NewReader(def)) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			t.Fatalf("invalid ABI definition %s: %v", def, err) | 			t.Fatalf("invalid ABI definition %s: %v", def, err) | ||||||
|  | |||||||
| @ -92,7 +92,10 @@ func (e *ExpiredValue) Add(amount int64, logOffset Fixed64) int64 { | |||||||
| 		e.Exp = integer | 		e.Exp = integer | ||||||
| 	} | 	} | ||||||
| 	if base >= 0 || uint64(-base) <= e.Base { | 	if base >= 0 || uint64(-base) <= e.Base { | ||||||
| 		e.Base += uint64(base) | 		// This is a temporary fix to circumvent a golang
 | ||||||
|  | 		// uint conversion issue on arm64, which needs to
 | ||||||
|  | 		// be investigated further. FIXME
 | ||||||
|  | 		e.Base = uint64(int64(e.Base) + int64(base)) | ||||||
| 		return amount | 		return amount | ||||||
| 	} | 	} | ||||||
| 	net := int64(-float64(e.Base) / factor) | 	net := int64(-float64(e.Base) / factor) | ||||||
|  | |||||||
| @ -16,7 +16,9 @@ | |||||||
| 
 | 
 | ||||||
| package utils | package utils | ||||||
| 
 | 
 | ||||||
| import "testing" | import ( | ||||||
|  | 	"testing" | ||||||
|  | ) | ||||||
| 
 | 
 | ||||||
| func TestValueExpiration(t *testing.T) { | func TestValueExpiration(t *testing.T) { | ||||||
| 	var cases = []struct { | 	var cases = []struct { | ||||||
|  | |||||||
| @ -197,6 +197,15 @@ func (c *BoundContract) Transact(opts *TransactOpts, method string, args *Interf | |||||||
| 	return &Transaction{rawTx}, nil | 	return &Transaction{rawTx}, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // RawTransact invokes the (paid) contract method with raw calldata as input values.
 | ||||||
|  | func (c *BoundContract) RawTransact(opts *TransactOpts, calldata []byte) (tx *Transaction, _ error) { | ||||||
|  | 	rawTx, err := c.contract.RawTransact(&opts.opts, calldata) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	return &Transaction{rawTx}, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // Transfer initiates a plain transaction to move funds to the contract, calling
 | // Transfer initiates a plain transaction to move funds to the contract, calling
 | ||||||
| // its default method if one is available.
 | // its default method if one is available.
 | ||||||
| func (c *BoundContract) Transfer(opts *TransactOpts) (tx *Transaction, _ error) { | func (c *BoundContract) Transfer(opts *TransactOpts) (tx *Transaction, _ error) { | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user