class Eth::Abi::Type
Provides a class to handle and parse common ABI types.
def self.size_type
-
(Eth::Abi::Type)
- a uint256 size type.
def self.size_type @size_type ||= new("uint", 256, []) end
def ==(another_type)
-
(Boolean)
- true if all attributes match.
Parameters:
-
another_type
(Eth::Abi::Type
) -- another type to be compared.
def ==(another_type) base_type == another_type.base_type and sub_type == another_type.sub_type and dimensions == another_type.dimensions end
def dynamic?
-
(Boolean)
- true if array is of dynamic size.
def dynamic? size.nil? end
def initialize(base_type, sub_type, dimensions, components = nil, component_name = nil)
-
(Eth::Abi::Type)
- an ABI type object.
Parameters:
-
component_name
(String
) -- the tuple component's name. -
components
(Array
) -- the components attribute. -
dimensions
(Array
) -- the dimension attribute. -
sub_type
(String
) -- the sub-type attribute. -
base_type
(String
) -- the base-type attribute.
def initialize(base_type, sub_type, dimensions, components = nil, component_name = nil) sub_type = sub_type.to_s @base_type = base_type @sub_type = sub_type @dimensions = dimensions @components = components @name = component_name end
def nested_sub
-
(Eth::Abi::Type)
- nested sub-type.
def nested_sub @nested_sub ||= self.class.new(base_type, sub_type, dimensions[0...-1], components, name) end
def parse(type, components = nil, component_name = nil)
-
(ParseError)
- if it fails to parse the type.
Returns:
-
(Eth::Abi::Type)
- a parsed Type object.
Parameters:
-
component_name
(String
) -- the tuple component's name. -
components
(Array
) -- the components attribute. -
type
(String
) -- a common Solidity type.
def parse(type, components = nil, component_name = nil) return type if type.is_a?(Type) _, base_type, sub_type, dimension = /([a-z]*)([0-9]*x?[0-9]*)((\[[0-9]*\])*)/.match(type).to_a # type dimension can only be numeric dims = dimension.scan(/\[[0-9]*\]/) raise ParseError, "Unknown characters found in array declaration" if dims.join != dimension # enforce base types validate_base_type base_type, sub_type # return a new Type (using konstructor) sub_type = sub_type.to_s @base_type = base_type @sub_type = sub_type @dimensions = dims.map { |x| x[1...-1].to_i } @components = components.map { |component| Abi::Type.parse(component["type"], component.dig("components"), component.dig("name")) } unless components.nil? @name = component_name end
def size
-
(Integer)
- the size of the type; or nil if not available.
def size s = nil if dimensions.empty? if !(["string", "bytes", "tuple"].include?(base_type) and sub_type.empty?) s = 32 elsif base_type == "tuple" && components.none?(&:dynamic?) s = components.sum(&:size) end elsif dimensions.last != 0 && !nested_sub.dynamic? s = dimensions.last * nested_sub.size end @size ||= s end
def to_s
-
(String)
- the type string.
def to_s if base_type == "tuple" "(" + components.map(&:to_s).join(",") + ")" + (dimensions.size > 0 ? dimensions.map { |x| "[#{x == 0 ? "" : x}]" }.join : "") elsif dimensions.empty? if %w[string bytes].include?(base_type) && sub_type.empty? base_type else "#{base_type}#{sub_type}" end else "#{base_type}#{sub_type}#{dimensions.map { |x| "[#{x == 0 ? "" : x}]" }.join}" end end
def validate_base_type(base_type, sub_type)
def validate_base_type(base_type, sub_type) case base_type when "string" # string can not have any suffix raise ParseError, "String type must have no suffix or numerical suffix" unless sub_type.empty? when "bytes" # bytes can be no longer than 32 bytes raise ParseError, "Maximum 32 bytes for fixed-length string or bytes" unless sub_type.empty? || sub_type.to_i <= 32 when "tuple" # tuples can not have any suffix raise ParseError, "Tuple type must have no suffix or numerical suffix" unless sub_type.empty? when "uint", "int" # integers must have a numerical suffix raise ParseError, "Integer type must have numerical suffix" unless sub_type =~ /\A[0-9]+\z/ # integer size must be valid size = sub_type.to_i raise ParseError, "Integer size out of bounds" unless size >= 8 && size <= 256 raise ParseError, "Integer size must be multiple of 8" unless size % 8 == 0 when "ureal", "real", "fixed", "ufixed" # floats must have valid dimensional suffix raise ParseError, "Real type must have suffix of form <high>x<low>, e.g. 128x128" unless sub_type =~ /\A[0-9]+x[0-9]+\z/ high, low = sub_type.split("x").map(&:to_i) total = high + low raise ParseError, "Real size out of bounds (max 32 bytes)" unless total >= 8 && total <= 256 raise ParseError, "Real high/low sizes must be multiples of 8" unless high % 8 == 0 && low % 8 == 0 when "hash" # hashs must have numerical suffix raise ParseError, "Hash type must have numerical suffix" unless sub_type =~ /\A[0-9]+\z/ when "address" # addresses cannot have any suffix raise ParseError, "Address cannot have suffix" unless sub_type.empty? when "bool" # booleans cannot have any suffix raise ParseError, "Bool cannot have suffix" unless sub_type.empty? else # we cannot parse arbitrary types such as 'decimal' or 'hex' raise ParseError, "Unknown base type" end end