module Eth::Abi::Decoder
def primitive_type(type, data)
-
(DecodingError)
- if decoding fails for type.
Returns:
-
(String)
- the decoded data for the type.
Parameters:
-
data
(String
) -- encoded primitive type data string. -
type
(Eth::Abi::Type
) -- type to be decoded.
def primitive_type(type, data) case type.base_type when "address" # decoded address with 0x-prefix Address.new(Util.bin_to_hex data[12..-1]).to_s.downcase when "string", "bytes" if type.sub_type.empty? size = Util.deserialize_big_endian_to_int data[0, 32] # decoded dynamic-sized array data[32..-1][0, size] else # decoded static-sized array data[0, type.sub_type.to_i] end when "hash" # decoded hash data[(32 - type.sub_type.to_i), type.sub_type.to_i] when "uint" # decoded unsigned integer Util.deserialize_big_endian_to_int data when "int" u = Util.deserialize_big_endian_to_int data i = u >= 2 ** (type.sub_type.to_i - 1) ? (u - 2 ** 256) : u # decoded integer i when "ureal", "ufixed" high, low = type.sub_type.split("x").map(&:to_i) # decoded unsigned fixed point numeric Util.deserialize_big_endian_to_int(data) * 1.0 / 2 ** low when "real", "fixed" high, low = type.sub_type.split("x").map(&:to_i) u = Util.deserialize_big_endian_to_int data i = u >= 2 ** (high + low - 1) ? (u - 2 ** (high + low)) : u # decoded fixed point numeric i * 1.0 / 2 ** low when "bool" # decoded boolean data[-1] == Constant::BYTE_ONE else raise DecodingError, "Unknown primitive type: #{type.base_type}" end end
def type(type, arg)
-
(DecodingError)
- if decoding fails for type.
Returns:
-
(String)
- the decoded data for the type.
Parameters:
-
arg
(String
) -- encoded type data string. -
type
(Eth::Abi::Type
) -- type to be decoded.
def type(type, arg) if %w(string bytes).include?(type.base_type) and type.sub_type.empty? # Case: decoding a string/bytes if type.dimensions.empty? l = Util.deserialize_big_endian_to_int arg[0, 32] data = arg[32..-1] raise DecodingError, "Wrong data size for string/bytes object" unless data.size == Util.ceil32(l) # decoded strings and bytes data[0, l] # Case: decoding array of string/bytes else l = Util.deserialize_big_endian_to_int arg[0, 32] # Decode each element of the array (1..l).map do |i| pointer = Util.deserialize_big_endian_to_int arg[i * 32, 32] # Pointer to the size of the array's element data_l = Util.deserialize_big_endian_to_int arg[32 + pointer, 32] # length of the element type(Type.parse(type.base_type), arg[pointer + 32, Util.ceil32(data_l) + 32]) end end elsif type.base_type == "tuple" offset = 0 data = {} raise DecodingError, "Cannot decode tuples without known components" if type.components.nil? type.components.each do |c| if c.dynamic? pointer = Util.deserialize_big_endian_to_int arg[offset, 32] # Pointer to the size of the array's element data_len = Util.deserialize_big_endian_to_int arg[pointer, 32] # length of the element data[c.name] = type(c, arg[pointer, Util.ceil32(data_len) + 32]) offset += 32 else size = c.size data[c.name] = type(c, arg[offset, size]) offset += size end end data elsif type.dynamic? l = Util.deserialize_big_endian_to_int arg[0, 32] nested_sub = type.nested_sub # ref https://github.com/ethereum/tests/issues/691 raise NotImplementedError, "Decoding dynamic arrays with nested dynamic sub-types is not implemented for ABI." if nested_sub.dynamic? # decoded dynamic-sized arrays (0...l).map { |i| type(nested_sub, arg[32 + nested_sub.size * i, nested_sub.size]) } elsif !type.dimensions.empty? l = type.dimensions.first nested_sub = type.nested_sub # decoded static-size arrays (0...l).map { |i| type(nested_sub, arg[nested_sub.size * i, nested_sub.size]) } else # decoded primitive types primitive_type type, arg end end