1 #include <util/contractabi.h>
2 #include <univalue.h>
3 #include <libethcore/ABI.h>
4 #include <math.h>
5
6 namespace ContractABI_NS
7 {
8 // Defining json preprocessor functions in order to avoid repetitive code with slight difference
9 #define ReadJsonString(json, param, result) if(json.exists(#param) && json[#param].isStr())\
10 result.param = json[#param].get_str();
11 #define ReadJsonBool(json, param, result) if(json.exists(#param) && json[#param].isBool())\
12 result.param = json[#param].get_bool();
13 #define ReadJsonArray(json, param, result) if(json.exists(#param) && json[#param].isArray())\
14 result = json[#param].get_array();
15 #define JsonExist(json, param) json.exists(#param)
16
17 // String parsing functions
startsWithString(const std::string & str,const std::string & s,size_t & pos)18 inline bool startsWithString(const std::string& str, const std::string& s, size_t& pos)
19 {
20 if(pos >= str.length()) return false;
21
22 size_t length = s.length();
23 bool ret = (str.substr(pos, length) == s);
24 if(ret) pos += length;
25 return ret;
26 }
27
startsWithNumber(const std::string & str,size_t & pos)28 inline std::string startsWithNumber(const std::string& str, size_t& pos)
29 {
30 if(pos >= str.length()) return "";
31
32 std::stringstream ss;
33 for(size_t i = pos; i < str.size(); i++)
34 {
35 char c = str[i];
36 if(c >= '0' && c <= '9')
37 ss << c;
38 else
39 break;
40 }
41
42 std::string s = ss.str();
43 pos += s.length();
44 return s;
45 }
46
47 // define constransts
48 const static int HEX_INSTRUCTION_SIZE = 64;
49 }
50 using namespace ContractABI_NS;
51
ContractABI()52 ContractABI::ContractABI()
53 {}
54
ContractABI(const std::string & json_data)55 ContractABI::ContractABI(const std::string& json_data)
56 {
57 loads(json_data);
58 }
59
loads(const std::string & json_data)60 bool ContractABI::loads(const std::string &json_data)
61 {
62 clean();
63
64 UniValue json_contract;
65 bool ret = json_contract.read(json_data);
66 if(ret && json_contract.isArray())
67 {
68 // Read all functions from the contract
69 size_t size = json_contract.size();
70 for(size_t i = 0; i < size; i++)
71 {
72 const UniValue& json_function = json_contract[i];
73 FunctionABI function;
74 ReadJsonString(json_function, name, function);
75 ReadJsonString(json_function, type, function);
76 ReadJsonBool(json_function, anonymous, function);
77 ReadJsonString(json_function, stateMutability, function);
78
79 // Payable might not exist in newer ABI, so determine it from state mutability if it not exists
80 if(JsonExist(json_function, payable))
81 {
82 ReadJsonBool(json_function, payable, function);
83 }
84 else
85 {
86 function.payable = function.stateMutability == "payable";
87 }
88
89 // Constant might not exist in newer ABI, so determine it from state mutability if it not exists
90 if(JsonExist(json_function, constant))
91 {
92 ReadJsonBool(json_function, constant, function);
93 }
94 else
95 {
96 function.constant = function.stateMutability == "pure"
97 || function.stateMutability == "view";
98 }
99
100 UniValue json_inputs;
101 ReadJsonArray(json_function, inputs, json_inputs);
102 for(size_t j = 0; j < json_inputs.size(); j++)
103 {
104 const UniValue& json_param = json_inputs[j];
105 ParameterABI param;
106 ReadJsonString(json_param, name, param);
107 ReadJsonString(json_param, type, param);
108 ReadJsonBool(json_param, indexed, param);
109 function.inputs.push_back(param);
110 }
111
112 UniValue json_outputs;
113 ReadJsonArray(json_function, outputs, json_outputs);
114 for(size_t j = 0; j < json_outputs.size(); j++)
115 {
116 const UniValue& json_param = json_outputs[j];
117 ParameterABI param;
118 ReadJsonString(json_param, name, param);
119 ReadJsonString(json_param, type, param);
120 ReadJsonBool(json_param, indexed, param);
121 function.outputs.push_back(param);
122 }
123
124 function.cache();
125 functions.push_back(function);
126 }
127 }
128
129 FunctionABI function;
130 function.type = "default";
131 function.payable = true;
132 function.cache();
133 functions.push_back(function);
134
135 return ret;
136 }
137
operator [](std::string name) const138 FunctionABI ContractABI::operator[](std::string name) const
139 {
140 for(const FunctionABI& func : functions)
141 {
142 if(func.name == name)
143 return func;
144 }
145 return FunctionABI();
146 }
147
clean()148 void ContractABI::clean()
149 {
150 functions.clear();
151 }
152
FunctionABI(const std::string & _name,const std::string & _type,const std::vector<ParameterABI> & _inputs,const std::vector<ParameterABI> & _outputs,bool _payable,bool _constant,bool _anonymous)153 FunctionABI::FunctionABI(const std::string &_name,
154 const std::string &_type,
155 const std::vector<ParameterABI> &_inputs,
156 const std::vector<ParameterABI> &_outputs,
157 bool _payable, bool _constant, bool _anonymous):
158 name(_name),
159 type(_type),
160 inputs(_inputs),
161 outputs(_outputs),
162 payable(_payable),
163 constant(_constant),
164 anonymous(_anonymous),
165 cached(false)
166 {}
167
abiIn(const std::vector<std::vector<std::string>> & values,std::string & data,std::vector<ParameterABI::ErrorType> & errors) const168 bool FunctionABI::abiIn(const std::vector<std::vector<std::string>> &values, std::string &data, std::vector<ParameterABI::ErrorType>& errors) const
169 {
170 bool ret = inputs.size() == values.size();
171 std::string params;
172 std::map<int, std::string> mapDynamic;
173 for(size_t i = 0; i < inputs.size(); i++)
174 {
175 ret &= inputs[i].abiIn(values[i], params, mapDynamic);
176 errors.push_back(inputs[i].lastError());
177 }
178 if(ret)
179 {
180 processDynamicParams(mapDynamic, params);
181 data = selector() + params;
182 }
183 return ret;
184 }
185
abiOut(const std::string & data,std::vector<std::vector<std::string>> & values,std::vector<ParameterABI::ErrorType> & errors) const186 bool FunctionABI::abiOut(const std::string &data, std::vector<std::vector<std::string>> &values, std::vector<ParameterABI::ErrorType>& errors) const
187 {
188 size_t pos = 0;
189 bool ret = true;
190 for(size_t i = 0; i < outputs.size(); i++)
191 {
192 std::vector<std::string> value;
193 ret &= outputs[i].abiOut(data, pos, value);
194 values.push_back(value);
195 errors.push_back(outputs[i].lastError());
196 }
197 return ret;
198 }
199
abiOut(const std::vector<std::string> & topics,const std::string & data,std::vector<std::vector<std::string>> & values,std::vector<ParameterABI::ErrorType> & errors) const200 bool FunctionABI::abiOut(const std::vector<std::string>& topics, const std::string& data, std::vector<std::vector<std::string>>& values, std::vector<ParameterABI::ErrorType>& errors) const
201 {
202 size_t pos = 0;
203 bool ret = true;
204 if(type == "event")
205 {
206 // Get the event name
207 size_t ti = 0;
208 if(!anonymous)
209 {
210 if(topics.size() == 0) return false;
211 if(topics[ti++] != selector()) return false;
212 }
213
214 // Get the inputs
215 for(size_t i = 0; i < inputs.size(); i++)
216 {
217 std::vector<std::string> value;
218 if(inputs[i].indexed)
219 {
220 size_t pos = 0;
221 ret &= topics.size() > ti ? inputs[i].abiOut(topics[ti++], pos, value) : false;
222 }
223 else
224 {
225 ret &= inputs[i].abiOut(data, pos, value);
226 }
227
228 values.push_back(value);
229 errors.push_back(inputs[i].lastError());
230 }
231 }
232 else
233 {
234 // Get the outputs
235 for(size_t i = 0; i < outputs.size(); i++)
236 {
237 std::vector<std::string> value;
238 ret &= outputs[i].abiOut(data, pos, value);
239 values.push_back(value);
240 errors.push_back(outputs[i].lastError());
241 }
242 }
243
244 return ret;
245 }
246
selector() const247 std::string FunctionABI::selector() const
248 {
249 if(cached)
250 return cacheSelector;
251
252 if(type == "default")
253 {
254 return defaultSelector();
255 }
256
257 if(type == "constructor" || (type == "event" && anonymous))
258 {
259 return "";
260 }
261
262 std::stringstream id;
263 id << name;
264 id << "(";
265 if(inputs.size() > 0)
266 {
267 id << inputs[0].type;
268 }
269 for(size_t i = 1; i < inputs.size(); i++)
270 {
271 id << "," << inputs[i].type;
272 }
273 id << ")";
274 std::string sig = id.str();
275
276 dev::bytes hash;
277 if(type == "event")
278 {
279 hash = dev::sha3(sig).ref().toBytes();
280 }
281 else
282 {
283 hash = dev::sha3(sig).ref().cropped(0, 4).toBytes();
284 }
285
286 return dev::toHex(hash);
287 }
288
defaultSelector()289 std::string FunctionABI::defaultSelector()
290 {
291 return "00";
292 }
293
cache()294 void FunctionABI::cache()
295 {
296 cacheSelector = selector();
297 cached = true;
298 }
299
processDynamicParams(const std::map<int,std::string> & mapDynamic,std::string & data) const300 void FunctionABI::processDynamicParams(const std::map<int, std::string> &mapDynamic, std::string &data) const
301 {
302 for(auto i = mapDynamic.begin(); i != mapDynamic.end(); i++)
303 {
304 int pos = i->first;
305 std::string value = i->second;
306 dev::u256 inRef = data.size() / 2;
307 dev::bytes rawRef = dev::eth::ABISerialiser<dev::u256>::serialise(inRef);
308 std::string strRef = dev::toHex(rawRef);
309 data.replace(pos, strRef.size(), strRef);
310 data += value;
311 }
312 }
313
ParameterABI(const std::string & _name,const std::string & _type,bool _indexed)314 ParameterABI::ParameterABI(const std::string &_name, const std::string &_type, bool _indexed):
315 name(_name),
316 type(_type),
317 indexed(_indexed),
318 m_lastError(ParameterABI::Ok)
319 {}
320
~ParameterABI()321 ParameterABI::~ParameterABI()
322 {}
323
abiInBasic(ParameterType::Type abiType,std::string value,std::string & data) const324 bool ParameterABI::abiInBasic(ParameterType::Type abiType, std::string value, std::string &data) const
325 {
326 switch (abiType) {
327 case ParameterType::abi_bytes:
328 {
329 value = dev::asString(dev::fromHex(value));
330 dev::string32 inData = dev::eth::toString32(value);
331 data += dev::toHex(inData);
332 }
333 break;
334 case ParameterType::abi_bool:
335 value = value == "false" ? "0" : "1";
336 case ParameterType::abi_int:
337 case ParameterType::abi_uint:
338 {
339 dev::u256 inData(value.c_str());
340 dev::bytes rawData = dev::eth::ABISerialiser<dev::u256>::serialise(inData);
341 data += dev::toHex(rawData);
342 }
343 break;
344 case ParameterType::abi_address:
345 {
346 dev::u160 inData = dev::fromBigEndian<dev::u160, dev::bytes>(dev::fromHex(value));
347 dev::bytes rawData = dev::eth::ABISerialiser<dev::u160>::serialise(inData);
348 data += dev::toHex(rawData);
349 }
350 break;
351 default:
352 m_lastError = UnsupportedABI;
353 return false;
354 }
355 return true;
356 }
357
abiOutBasic(ParameterType::Type abiType,const std::string & data,size_t & pos,std::string & value) const358 bool ParameterABI::abiOutBasic(ParameterType::Type abiType, const std::string &data, size_t &pos, std::string &value) const
359 {
360 switch (abiType) {
361 case ParameterType::abi_bytes:
362 {
363 dev::bytes rawData = dev::fromHex(data.substr(pos, HEX_INSTRUCTION_SIZE));
364 dev::bytesConstRef o(&rawData);
365 std::string outData = dev::toString(dev::eth::ABIDeserialiser<dev::string32>::deserialise(o));
366 value = dev::toHex(outData);
367 }
368 break;
369 case ParameterType::abi_uint:
370 {
371 dev::bytes rawData = dev::fromHex(data.substr(pos, HEX_INSTRUCTION_SIZE));
372 dev::bytesConstRef o(&rawData);
373 dev::u256 outData = dev::eth::ABIDeserialiser<dev::u256>::deserialise(o);
374 value = outData.str();
375 }
376 break;
377 case ParameterType::abi_int:
378 {
379 dev::bytes rawData = dev::fromHex(data.substr(pos, HEX_INSTRUCTION_SIZE));
380 dev::bytesConstRef o(&rawData);
381 dev::s256 outData = dev::u2s(dev::eth::ABIDeserialiser<dev::u256>::deserialise(o));
382 value = outData.str();
383 }
384 break;
385 case ParameterType::abi_address:
386 {
387 dev::bytes rawData = dev::fromHex(data.substr(pos, HEX_INSTRUCTION_SIZE));
388 dev::bytesConstRef o(&rawData);
389 dev::u160 outData = dev::eth::ABIDeserialiser<dev::u160>::deserialise(o);
390 dev::bytes rawAddress(20);
391 dev::toBigEndian<dev::u160, dev::bytes>(outData, rawAddress);
392 value = dev::toHex(rawAddress);
393 }
394 break;
395 case ParameterType::abi_bool:
396 {
397 dev::bytes rawData = dev::fromHex(data.substr(pos, HEX_INSTRUCTION_SIZE));
398 dev::bytesConstRef o(&rawData);
399 dev::u256 outData = dev::eth::ABIDeserialiser<dev::u256>::deserialise(o);
400 value = outData == 0 ? "false" : "true";
401 }
402 break;
403 default:
404 m_lastError = UnsupportedABI;
405 return false;
406 }
407
408 pos += HEX_INSTRUCTION_SIZE;
409
410 return true;
411 }
412
addDynamic(const std::string & paramData,std::string & data,std::map<int,std::string> & mapDynamic) const413 void ParameterABI::addDynamic(const std::string ¶mData, std::string &data, std::map<int, std::string> &mapDynamic) const
414 {
415 int key = data.size();
416 data += paramData.substr(0, HEX_INSTRUCTION_SIZE);
417 mapDynamic[key] = paramData.substr(HEX_INSTRUCTION_SIZE);
418 }
419
abiIn(const std::vector<std::string> & value,std::string & data,std::map<int,std::string> & mapDynamic) const420 bool ParameterABI::abiIn(const std::vector<std::string> &value, std::string &data, std::map<int, std::string>& mapDynamic) const
421 {
422 try
423 {
424 m_lastError = Ok;
425 ParameterType::Type abiType = decodeType().type();
426 if(decodeType().isDynamic() && !decodeType().isList())
427 {
428 // Dynamic basic type (list of bytes or chars)
429 std::string _value = value[0];
430 switch (abiType) {
431 case ParameterType::abi_bytes:
432 _value = dev::asString(dev::fromHex(_value));
433 case ParameterType::abi_string:
434 {
435 std::string paramData = dev::toHex(dev::eth::ABISerialiser<std::string>::serialise(_value));
436 addDynamic(paramData, data, mapDynamic);
437 }
438 break;
439 default:
440 m_lastError = UnsupportedABI;
441 return false;
442 }
443 }
444 else if(!decodeType().isDynamic() && !decodeType().isList())
445 {
446 // Static basic type
447 abiInBasic(abiType, value[0], data);
448 }
449 else if(decodeType().isDynamic() && decodeType().isList())
450 {
451 // Dynamic list type
452 std::string paramData;
453 abiInBasic(ParameterType::abi_uint, "32", paramData);
454 size_t length = value.size();
455 abiInBasic(ParameterType::abi_uint, std::to_string(length), paramData);
456 for(size_t i = 0; i < length; i++)
457 {
458 abiInBasic(abiType, value[i], paramData);
459 }
460 addDynamic(paramData, data, mapDynamic);
461 }
462 else if(!decodeType().isDynamic() && decodeType().isList())
463 {
464 // Static list type
465 size_t length = decodeType().length();
466 for(size_t i = 0; i < length; i++)
467 {
468 abiInBasic(abiType, value[i], data);
469 }
470 }
471 else
472 {
473 // Unknown type
474 m_lastError = UnsupportedABI;
475 return false;
476 }
477 }
478 catch(...)
479 {
480 m_lastError = EncodingError;
481 return false;
482 }
483
484 return true;
485 }
486
deserialiseString(dev::bytesConstRef & io_t,unsigned p)487 std::string deserialiseString(dev::bytesConstRef& io_t, unsigned p)
488 {
489 unsigned o = (uint16_t)dev::u256(dev::h256(io_t.cropped(0, 32))) - p;
490 unsigned s = (uint16_t)dev::u256(dev::h256(io_t.cropped(o, 32)));
491 std::string ret;
492 ret.resize(s);
493 io_t.cropped(o + 32, s).populate(dev::bytesRef((byte*)ret.data(), s));
494 io_t = io_t.cropped(32);
495 return ret;
496 }
497
abiOut(const std::string & data,size_t & pos,std::vector<std::string> & value) const498 bool ParameterABI::abiOut(const std::string &data, size_t &pos, std::vector<std::string> &value) const
499 {
500 try
501 {
502 m_lastError = Ok;
503 ParameterType::Type abiType = decodeType().type();
504 if(decodeType().isDynamic() && !decodeType().isList())
505 {
506 // Dynamic basic type
507 switch (abiType) {
508 case ParameterType::abi_bytes:
509 {
510 dev::bytes rawData = dev::fromHex(data.substr(pos));
511 dev::bytesConstRef o(&rawData);
512 std::string outData = deserialiseString(o, pos/2);
513 value.push_back(dev::toHex(outData));
514 }
515 break;
516 case ParameterType::abi_string:
517 {
518 dev::bytes rawData = dev::fromHex(data.substr(pos));
519 dev::bytesConstRef o(&rawData);
520 value.push_back(deserialiseString(o, pos/2));
521 }
522 break;
523 default:
524 m_lastError = UnsupportedABI;
525 return false;
526 }
527
528 pos += HEX_INSTRUCTION_SIZE;
529 }
530 else if(!decodeType().isDynamic() && !decodeType().isList())
531 {
532 // Static basic type
533 std::string paramValue;
534 if(abiOutBasic(abiType, data, pos, paramValue))
535 {
536 value.push_back(paramValue);
537 }
538 else
539 {
540 return false;
541 }
542 }
543 else if(decodeType().isDynamic() && decodeType().isList())
544 {
545 // Dynamic list type
546
547 // Get position
548 std::string paramValue;
549 if(!abiOutBasic(ParameterType::abi_uint, data, pos, paramValue))
550 return false;
551 size_t oldPos = pos;
552 pos = std::atoi(paramValue.c_str()) * 2;
553
554 // Get length
555 if(!abiOutBasic(ParameterType::abi_uint, data, pos, paramValue))
556 return false;
557 size_t length = std::atoi(paramValue.c_str());
558
559 // Read list
560 for(size_t i = 0; i < length; i++)
561 {
562 if(!abiOutBasic(abiType, data, pos, paramValue))
563 return false;
564 value.push_back(paramValue);
565 }
566
567 // Restore position
568 pos = oldPos;
569 }
570 else if(!decodeType().isDynamic() && decodeType().isList())
571 {
572 // Static list type
573 std::string paramValue;
574 size_t length = decodeType().length();
575
576 // Read list
577 for(size_t i = 0; i < length; i++)
578 {
579 if(!abiOutBasic(abiType, data, pos, paramValue))
580 return false;
581 value.push_back(paramValue);
582 }
583 }
584 else
585 {
586 // Unknown type
587 m_lastError = UnsupportedABI;
588 return false;
589 }
590 }
591 catch(...)
592 {
593 m_lastError = DecodingError;
594 return false;
595 }
596
597 return true;
598 }
599
lastError() const600 ParameterABI::ErrorType ParameterABI::lastError() const
601 {
602 return m_lastError;
603 }
604
decodeType() const605 const ParameterType &ParameterABI::decodeType() const
606 {
607 if(m_decodeType.canonical() != type)
608 {
609 m_decodeType = ParameterType(type);
610 }
611
612 return m_decodeType;
613 }
614
ParameterType(const std::string & _type)615 ParameterType::ParameterType(const std::string& _type):
616 m_type(ParameterType::abi_none),
617 m_whole(0),
618 m_decimal(0),
619 m_length(0),
620 m_isList(false),
621 m_valid(false)
622 {
623 determine(_type);
624 }
625
determine(const std::string & _type)626 bool ParameterType::determine(const std::string &_type)
627 {
628 clean();
629
630 // Initialize variables
631 bool ret = true;
632 size_t pos = 0;
633
634 // Set string representation
635 m_canonical = _type;
636
637 // Determine the basic type
638 if(startsWithString(m_canonical, "uint", pos))
639 {
640 m_type = abi_uint;
641 }
642 else if(startsWithString(m_canonical, "int", pos))
643 {
644 m_type = abi_int;
645 }
646 else if(startsWithString(m_canonical, "address", pos))
647 {
648 m_type = abi_address;
649 }
650 else if(startsWithString(m_canonical, "bool", pos))
651 {
652 m_type = abi_bool;
653 }
654 else if(startsWithString(m_canonical, "fixed", pos))
655 {
656 m_type = abi_fixed;
657 }
658 else if(startsWithString(m_canonical, "ufixed", pos))
659 {
660 m_type = abi_ufixed;
661 }
662 else if(startsWithString(m_canonical, "bytes", pos))
663 {
664 m_type = abi_bytes;
665 }
666 else if(startsWithString(m_canonical, "string", pos))
667 {
668 m_type = abi_string;
669 }
670
671 // Provide more informations about the type
672 if(m_type != abi_none)
673 {
674 // Get the whole number part size
675 std::string strWhole = startsWithNumber(m_canonical, pos);
676 if(!strWhole.empty())
677 {
678 m_whole = atoi(strWhole.c_str());
679 }
680
681 // Get the decimal number part size
682 if(startsWithString(m_canonical, "x", pos))
683 {
684 std::string strDecimal = startsWithNumber(m_canonical, pos);
685 if(!strDecimal.empty())
686 {
687 m_decimal = atoi(strDecimal.c_str());
688 }
689 else
690 {
691 ret = false;
692 }
693 }
694
695 // Get information for list type
696 if(startsWithString(m_canonical, "[", pos))
697 {
698 std::string strLength = startsWithNumber(m_canonical, pos);
699 if(!strLength.empty())
700 {
701 m_length = atoi(strLength.c_str());
702 }
703 if(startsWithString(m_canonical, "]", pos))
704 {
705 m_isList = true;
706 }
707 else
708 {
709 ret = false;
710 }
711 }
712 }
713
714 // Return if not parsed correctly
715 if(m_canonical.length() != pos || ret == false)
716 ret = false;
717
718 // Check the validity of the types
719 if(ret && (m_type == abi_int || m_type == abi_uint))
720 {
721 ret &= m_whole > 0;
722 ret &= m_whole <= 256;
723 ret &= m_whole % 8 == 0;
724 ret &= m_decimal == 0;
725 }
726
727 if(ret && m_type == abi_address)
728 {
729 ret &= m_whole == 0;
730 ret &= m_decimal == 0;
731 if(ret) m_whole = 160;
732 }
733
734 if(ret && (m_type == abi_fixed || m_type == abi_ufixed))
735 {
736 ret &= m_whole > 0;
737 ret &= m_decimal > 0;
738 ret &= (m_whole + m_decimal) <= 256;
739 }
740
741 if(ret && m_type == abi_bytes)
742 {
743 m_whole *= 8;
744 ret &= m_whole > 0;
745 ret &= m_whole <= 256;
746 ret &= m_decimal == 0;
747 }
748
749 if(ret && m_type == abi_function)
750 {
751 ret &= m_whole == 0;
752 ret &= m_decimal == 0;
753 if(ret) m_whole = 196;
754 }
755
756 if(ret && m_type == abi_string)
757 {
758 ret &= m_whole == 0;
759 ret &= m_decimal == 0;
760 }
761
762 m_valid = ret;
763
764 return m_valid;
765 }
766
wholeBits() const767 size_t ParameterType::wholeBits() const
768 {
769 return m_whole;
770 }
771
decimalBits() const772 size_t ParameterType::decimalBits() const
773 {
774 return m_decimal;
775 }
776
totalBytes() const777 size_t ParameterType::totalBytes() const
778 {
779 return ceil((m_whole + m_decimal) / 8.0);
780 }
781
length() const782 size_t ParameterType::length() const
783 {
784 return m_length;
785 }
786
isList() const787 bool ParameterType::isList() const
788 {
789 return m_isList;
790 }
791
isDynamic() const792 bool ParameterType::isDynamic() const
793 {
794 // Type bytes is dynamic when the count of bytes is not known.
795 // Type string is always dynamic.
796 if((m_type == abi_bytes && totalBytes() == 0) || m_type == abi_string)
797 {
798 return true;
799 }
800
801 // Type list is dynamic when the count of elements is not known.
802 if(m_isList)
803 return m_length == 0;
804
805 return false;
806 }
807
isValid() const808 bool ParameterType::isValid() const
809 {
810 return m_valid;
811 }
812
canonical() const813 const std::string& ParameterType::canonical() const
814 {
815 return m_canonical;
816 }
817
clean()818 void ParameterType::clean()
819 {
820 m_type = ParameterType::abi_none;
821 m_whole = 0;
822 m_decimal = 0;
823 m_length = 0;
824 m_isList = false;
825 m_valid = false;
826 m_canonical = "";
827 }
828
type() const829 ParameterType::Type ParameterType::type() const
830 {
831 return m_type;
832 }
833
numIndexed() const834 int FunctionABI::numIndexed() const
835 {
836 int ret = 0;
837 for(const ParameterABI& param : inputs)
838 if(param.indexed)
839 ret++;
840 return ret;
841 }
842