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 &paramData, 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