Module: Eth::Abi::Encoder

Extended by:
Encoder
Included in:
Encoder
Defined in:
lib/eth/abi/encoder.rb

Overview

Provides a utility module to assist encoding ABIs.

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.primitive_type(type, arg) ⇒ String

Encodes primitive types.

Parameters:

  • type (Eth::Abi::Type)

    type to be encoded.

  • arg (String|Number)

    value to be encoded.

Returns:

  • (String)

    the encoded primitive type.

Raises:

  • (EncodingError)

    if value does not match type.

  • (ValueOutOfBounds)

    if value is out of bounds for type.

  • (ArgumentError)

    if encoding fails for type.



96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/eth/abi/encoder.rb', line 96

def primitive_type(type, arg)
  case type.base_type
  when "uint"
    uint arg, type
  when "int"
    int arg, type
  when "bool"
    bool arg
  when "ureal", "ufixed"
    ufixed arg, type
  when "real", "fixed"
    fixed arg, type
  when "string", "bytes"
    bytes arg, type
  when "tuple"
    tuple arg, type
  when "hash"
    hash arg, type
  when "address"
    address arg
  else
    raise EncodingError, "Unhandled type: #{type.base_type} #{type.sub_type}"
  end
end

.type(type, arg) ⇒ String

Encodes a specific value, either static or dynamic.

Parameters:

  • type (Eth::Abi::Type)

    type to be encoded.

  • arg (String|Number)

    value to be encoded.

Returns:

  • (String)

    the encoded type.

Raises:



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/eth/abi/encoder.rb', line 33

def type(type, arg)
  if %w(string bytes).include? type.base_type and type.sub_type.empty? and type.dimensions.empty?
    raise EncodingError, "Argument must be a String" unless arg.instance_of? String

    # encodes strings and bytes
    size = type Type.size_type, arg.size
    padding = Constant::BYTE_ZERO * (Util.ceil32(arg.size) - arg.size)
    "#{size}#{arg}#{padding}"
  elsif type.base_type == "tuple" && type.dimensions.size == 1 && type.dimensions[0] != 0
    result = ""
    result += struct_offsets(type.nested_sub, arg)
    result += arg.map { |x| type(type.nested_sub, x) }.join
    result
  elsif type.dynamic? && arg.is_a?(Array)

    # encodes dynamic-sized arrays
    head, tail = "", ""
    head += type(Type.size_type, arg.size)
    nested_sub = type.nested_sub

    # calculate offsets
    if %w(string bytes).include?(type.base_type) && type.sub_type.empty?
      offset = 0
      arg.size.times do |i|
        if i == 0
          offset = arg.size * 32
        else
          number_of_words = ((arg[i - 1].size + 32 - 1) / 32).floor
          total_bytes_length = number_of_words * 32
          offset += total_bytes_length + 32
        end

        head += type(Type.size_type, offset)
      end
    elsif nested_sub.base_type == "tuple" && nested_sub.dynamic?
      head += struct_offsets(nested_sub, arg)
    end

    arg.size.times do |i|
      head += type nested_sub, arg[i]
    end
    "#{head}#{tail}"
  else
    if type.dimensions.empty?

      # encode a primitive type
      primitive_type type, arg
    else

      # encode static-size arrays
      arg.map { |x| type(type.nested_sub, x) }.join
    end
  end
end

Instance Method Details

#primitive_type(type, arg) ⇒ String

Encodes primitive types.

Parameters:

  • type (Eth::Abi::Type)

    type to be encoded.

  • arg (String|Number)

    value to be encoded.

Returns:

  • (String)

    the encoded primitive type.

Raises:

  • (EncodingError)

    if value does not match type.

  • (ValueOutOfBounds)

    if value is out of bounds for type.

  • (ArgumentError)

    if encoding fails for type.



96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/eth/abi/encoder.rb', line 96

def primitive_type(type, arg)
  case type.base_type
  when "uint"
    uint arg, type
  when "int"
    int arg, type
  when "bool"
    bool arg
  when "ureal", "ufixed"
    ufixed arg, type
  when "real", "fixed"
    fixed arg, type
  when "string", "bytes"
    bytes arg, type
  when "tuple"
    tuple arg, type
  when "hash"
    hash arg, type
  when "address"
    address arg
  else
    raise EncodingError, "Unhandled type: #{type.base_type} #{type.sub_type}"
  end
end

#type(type, arg) ⇒ String

Encodes a specific value, either static or dynamic.

Parameters:

  • type (Eth::Abi::Type)

    type to be encoded.

  • arg (String|Number)

    value to be encoded.

Returns:

  • (String)

    the encoded type.

Raises:



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/eth/abi/encoder.rb', line 33

def type(type, arg)
  if %w(string bytes).include? type.base_type and type.sub_type.empty? and type.dimensions.empty?
    raise EncodingError, "Argument must be a String" unless arg.instance_of? String

    # encodes strings and bytes
    size = type Type.size_type, arg.size
    padding = Constant::BYTE_ZERO * (Util.ceil32(arg.size) - arg.size)
    "#{size}#{arg}#{padding}"
  elsif type.base_type == "tuple" && type.dimensions.size == 1 && type.dimensions[0] != 0
    result = ""
    result += struct_offsets(type.nested_sub, arg)
    result += arg.map { |x| type(type.nested_sub, x) }.join
    result
  elsif type.dynamic? && arg.is_a?(Array)

    # encodes dynamic-sized arrays
    head, tail = "", ""
    head += type(Type.size_type, arg.size)
    nested_sub = type.nested_sub

    # calculate offsets
    if %w(string bytes).include?(type.base_type) && type.sub_type.empty?
      offset = 0
      arg.size.times do |i|
        if i == 0
          offset = arg.size * 32
        else
          number_of_words = ((arg[i - 1].size + 32 - 1) / 32).floor
          total_bytes_length = number_of_words * 32
          offset += total_bytes_length + 32
        end

        head += type(Type.size_type, offset)
      end
    elsif nested_sub.base_type == "tuple" && nested_sub.dynamic?
      head += struct_offsets(nested_sub, arg)
    end

    arg.size.times do |i|
      head += type nested_sub, arg[i]
    end
    "#{head}#{tail}"
  else
    if type.dimensions.empty?

      # encode a primitive type
      primitive_type type, arg
    else

      # encode static-size arrays
      arg.map { |x| type(type.nested_sub, x) }.join
    end
  end
end