abi_coder_rb 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,26 +1,30 @@
1
1
  module AbiCoderRb
2
2
  def decode_primitive_type(type, data)
3
- case type
4
- when Uint
5
- decode_uint256(data[0, 32])
6
- when Int
7
- u = decode_uint256(data[0, 32])
8
- u >= 2**(type.bits - 1) ? (u - 2**type.bits) : u
9
- when Bool
10
- data[31] == BYTE_ONE
11
- when String
12
- size = decode_uint256(data[0, 32])
13
- data[32...(32 + size)].force_encoding(Encoding::UTF_8)
14
- when Bytes
15
- size = decode_uint256(data[0, 32])
16
- data[32...(32 + size)]
17
- when FixedBytes
18
- data[0, type.length]
19
- when Address
20
- data[12...32].unpack1("H*").force_encoding(Encoding::UTF_8)
21
- else
22
- raise DecodingError, "Unknown primitive type: #{type.class.name} #{type.format}"
23
- end
3
+ result =
4
+ case type
5
+ when Uint
6
+ decode_uint256(data[0, 32])
7
+ when Int
8
+ Utils.abi_to_int_signed(bin_to_hex(data[0, 32]), type.bits)
9
+ when Bool
10
+ data[31] == BYTE_ONE
11
+ when String
12
+ size = decode_uint256(data[0, 32])
13
+ data[32...(32 + size)].force_encoding("UTF-8")
14
+ when Bytes
15
+ size = decode_uint256(data[0, 32])
16
+ data[32...(32 + size)]
17
+ when FixedBytes
18
+ data[0, type.length]
19
+ when Address
20
+ bin_to_hex(data[12...32]).force_encoding("UTF-8")
21
+ else
22
+ raise DecodingError, "Unknown primitive type: #{type.class.name} #{type.format}"
23
+ end
24
+
25
+ result = after_decoding_action.call(type.format, result) if after_decoding_action
26
+
27
+ result
24
28
  end
25
29
 
26
30
  private
@@ -30,6 +34,7 @@ module AbiCoderRb
30
34
  ### todo/check - allow nil - why? why not?
31
35
  ## raise DeserializationError, "Invalid serialization (not minimal length)" if !@size && serial.size > 0 && serial[0] == BYTE_ZERO
32
36
  # bin = bin || BYTE_ZERO
33
- bin.unpack1("H*").to_i(16)
37
+ bin_to_hex(bin).to_i(16)
38
+ # bin.bytes.reduce { |acc, byte| (acc << 8) + byte }
34
39
  end
35
40
  end
@@ -2,4 +2,33 @@ module AbiCoderRb
2
2
  def decode_tuple(type, data)
3
3
  decode_types(type.types, data)
4
4
  end
5
+
6
+ private
7
+
8
+ def decode_types(types, data)
9
+ start_positions = start_positions(types, data)
10
+
11
+ types.map.with_index do |type, index|
12
+ start_position = start_positions[index]
13
+ decode_type(type, data[start_position..])
14
+ end
15
+ end
16
+
17
+ def start_positions(types, data)
18
+ start_positions = ::Array.new(types.size)
19
+ offset = 0
20
+
21
+ types.each_with_index do |type, index|
22
+ if type.dynamic?
23
+ # 读取动态类型的偏移量
24
+ start_positions[index] = decode_uint256(data[offset, 32])
25
+ offset += 32
26
+ else
27
+ start_positions[index] = offset
28
+ offset += type.size
29
+ end
30
+ end
31
+
32
+ start_positions
33
+ end
5
34
  end
@@ -4,18 +4,15 @@ require_relative "decode/decode_array"
4
4
  require_relative "decode/decode_primitive_type"
5
5
 
6
6
  module AbiCoderRb
7
- def decode(types, data)
8
- # Convert types to ABI::Type if they are not already
9
- types = types.map { |type| type.is_a?(Type) ? type : Type.parse(type) }
7
+ def decode(type_str, data)
8
+ raise DecodingError, "Empty data" if data.nil? || data.empty?
10
9
 
11
- decode_types(types, data)
10
+ decode_type(Type.parse(type_str), data)
12
11
  end
13
12
 
14
13
  private
15
14
 
16
15
  def decode_type(type, data)
17
- return nil if data.nil? || data.empty?
18
-
19
16
  case type
20
17
  when Tuple ## todo: support empty (unit) tuple - why? why not?
21
18
  decode_tuple(type, data)
@@ -27,31 +24,4 @@ module AbiCoderRb
27
24
  decode_primitive_type(type, data)
28
25
  end
29
26
  end
30
-
31
- def decode_types(types, data)
32
- start_positions = start_positions(types, data)
33
-
34
- types.map.with_index do |type, index|
35
- start_position = start_positions[index]
36
- decode_type(type, data[start_position..])
37
- end
38
- end
39
-
40
- def start_positions(types, data)
41
- start_positions = ::Array.new(types.size)
42
- offset = 0
43
-
44
- types.each_with_index do |type, index|
45
- if type.dynamic?
46
- # 读取动态类型的偏移量
47
- start_positions[index] = decode_uint256(data[offset, 32])
48
- offset += 32
49
- else
50
- start_positions[index] = offset
51
- offset += type.size
52
- end
53
- end
54
-
55
- start_positions
56
- end
57
27
  end
@@ -3,6 +3,20 @@ module AbiCoderRb
3
3
  raise ArgumentError, "arg must be an array" unless args.is_a?(::Array)
4
4
  raise ArgumentError, "Wrong array size: found #{args.size}, expecting #{type.dim}" unless args.size == type.dim
5
5
 
6
- args.map { |arg| encode_type(type.subtype, arg) }.join
6
+ # fixed_array,是没有元素数量的编码de
7
+ # 如果内部类型是静态的,就是一个一个元素编码后加起来。
8
+ # 如果内部类型是动态的,先用位置一个一个编码加起来,然后是元素本体
9
+ subtype = type.subtype
10
+ if subtype.dynamic?
11
+ head = "".b
12
+ tail = "".b
13
+ args.each do |arg|
14
+ head += encode_uint256(32 * args.size + tail.size)
15
+ tail += encode_type(subtype, arg)
16
+ end
17
+ head + tail
18
+ else
19
+ args.map { |arg| encode_type(type.subtype, arg) }.join
20
+ end
7
21
  end
8
22
  end
@@ -1,5 +1,6 @@
1
1
  module AbiCoderRb
2
2
  def encode_primitive_type(type, arg)
3
+ arg = before_encoding_action.call(type.format, arg) if before_encoding_action
3
4
  # 根据类型选择相应的编码方法
4
5
  case type
5
6
  when Uint
@@ -34,12 +35,11 @@ module AbiCoderRb
34
35
  encode_uint(arg, 256)
35
36
  end
36
37
 
37
- def encode_int(arg, bits)
38
+ def encode_int(arg, _bits)
38
39
  ## raise EncodingError or ArgumentError - why? why not?
39
40
  raise ArgumentError, "arg is not integer: #{arg}" unless arg.is_a?(Integer)
40
- raise ValueOutOfBounds, arg unless arg >= -2**(bits - 1) && arg < 2**(bits - 1)
41
41
 
42
- lpad_int(arg % 2**bits)
42
+ hex_to_bin(Utils.int_to_abi_signed_256bit(arg))
43
43
  end
44
44
 
45
45
  def encode_bool(arg)
@@ -53,7 +53,7 @@ module AbiCoderRb
53
53
  ## raise EncodingError or ArgumentError - why? why not?
54
54
  raise EncodingError, "Expecting string: #{arg}" unless arg.is_a?(::String)
55
55
 
56
- arg = arg.b if arg.encoding != Encoding::BINARY ## was: name == 'UTF-8'
56
+ arg = arg.b if arg.encoding != "BINARY" ## was: name == 'UTF-8', wasm
57
57
 
58
58
  raise ValueOutOfBounds, "Integer invalid or out of range: #{arg.size}" if arg.size > UINT_MAX
59
59
 
@@ -69,7 +69,7 @@ module AbiCoderRb
69
69
  arg = arg.b if arg.encoding != Encoding::BINARY
70
70
 
71
71
  if length # fixed length type
72
- raise ValueOutOfBounds, "invalid bytes length #{length}" if arg.size > length
72
+ raise ValueOutOfBounds, "invalid bytes length #{arg.size}, should be #{length}" if arg.size > length
73
73
  raise ValueOutOfBounds, "invalid bytes length #{length}" if length < 0 || length > 32
74
74
 
75
75
  rpad(arg)
@@ -100,6 +100,18 @@ module AbiCoderRb
100
100
 
101
101
  private
102
102
 
103
+ def int_to_eth_abi(value, bits)
104
+ # 计算补码,如果是负数
105
+ value = 2**bits + value if value < 0
106
+
107
+ # 将值转换为十六进制字符串
108
+ hex = (value % 2**bits).to_s(16)
109
+ hex = "0#{hex}" if hex.length.odd?
110
+
111
+ # 确保字符串长度为16位(8个字节)
112
+ hex.rjust(bits / 4, "0")
113
+ end
114
+
103
115
  ###########
104
116
  # encoding helpers / utils
105
117
  # with "hard-coded" fill symbol as BYTE_ZERO
@@ -124,8 +136,8 @@ module AbiCoderRb
124
136
  raise ArgumentError, "Integer invalid or out of range: #{n}" unless n.is_a?(Integer) && n >= 0 && n <= UINT_MAX
125
137
 
126
138
  hex = n.to_s(16)
127
- hex = "0" + hex if hex.size.odd?
128
- bin = [hex].pack("H*")
139
+ hex = "0#{hex}" if hex.length.odd? # wasm, no .odd?
140
+ bin = hex_to_bin(hex)
129
141
 
130
142
  lpad(bin)
131
143
  end
@@ -135,7 +147,7 @@ module AbiCoderRb
135
147
  raise TypeError, "Value must be a string" unless hex.is_a?(::String)
136
148
  raise TypeError, "Non-hexadecimal digit found" unless hex =~ /\A[0-9a-fA-F]*\z/
137
149
 
138
- bin = [hex].pack("H*")
150
+ bin = hex_to_bin(hex)
139
151
 
140
152
  lpad(bin)
141
153
  end
@@ -2,4 +2,36 @@ module AbiCoderRb
2
2
  def encode_tuple(tuple, args)
3
3
  encode_types(tuple.types, args)
4
4
  end
5
+
6
+ private
7
+
8
+ def encode_types(types, args)
9
+ raise ArgumentError, "args must be an array" unless args.is_a?(::Array)
10
+
11
+ unless args.size == types.size
12
+ raise ArgumentError,
13
+ "Wrong number of args: found #{args.size}, expecting #{types.size}"
14
+ end
15
+
16
+ # 计算头部大小
17
+ head_size = types.map { |type| type.size || 32 }.sum
18
+
19
+ # 初始化头部和尾部
20
+ head = "".b
21
+ tail = "".b # 使用二进制字符串
22
+
23
+ # 遍历类型并编码
24
+ types.each_with_index do |type, i|
25
+ if type.dynamic?
26
+ # 动态类型: 更新头部和尾部
27
+ head += encode_uint256(head_size + tail.size)
28
+ tail += encode_type(type, args[i])
29
+ else
30
+ # 静态类型: 只更新头部
31
+ head += encode_type(type, args[i])
32
+ end
33
+ end
34
+
35
+ head + tail
36
+ end
5
37
  end
@@ -4,56 +4,26 @@ require_relative "encode/encode_array"
4
4
  require_relative "encode/encode_primitive_type"
5
5
 
6
6
  module AbiCoderRb
7
- ##
8
- # Encodes multiple arguments using the head/tail mechanism.
9
- # returns binary string (with BINARY / ASCII_8BIT encoding)
10
- #
11
- def encode(types, args)
12
- # 如果 types 是字符串,则转换为 ABI::Type 实例
13
- types = types.map { |type| type.is_a?(Type) ? type : Type.parse(type) }
7
+ # returns byte array
8
+ def encode(type, value)
9
+ # TODO: more checks?
10
+ raise EncodingError, "Value can not be nil" if value.nil?
14
11
 
15
- encode_types(types, args)
12
+ parsed = Type.parse(type)
13
+ encode_type(parsed, value)
16
14
  end
17
15
 
18
16
  private
19
17
 
20
- def encode_type(type, arg)
18
+ def encode_type(type, value)
21
19
  if type.is_a?(Tuple)
22
- encode_tuple(type, arg)
23
- elsif type.is_a?(Array) || type.is_a?(FixedArray)
24
- type.dynamic? ? encode_array(type, arg) : encode_fixed_array(type, arg)
20
+ encode_tuple(type, value)
21
+ elsif type.is_a?(Array)
22
+ encode_array(type, value)
23
+ elsif type.is_a?(FixedArray)
24
+ encode_fixed_array(type, value)
25
25
  else
26
- encode_primitive_type(type, arg)
26
+ encode_primitive_type(type, value)
27
27
  end
28
28
  end
29
-
30
- def encode_types(types, args)
31
- raise ArgumentError, "args must be an array" unless args.is_a?(::Array)
32
-
33
- unless args.size == types.size
34
- raise ArgumentError,
35
- "Wrong number of args: found #{args.size}, expecting #{types.size}"
36
- end
37
-
38
- # 计算头部大小
39
- head_size = types.map { |type| type.size || 32 }.sum
40
-
41
- # 初始化头部和尾部
42
- head = "".b
43
- tail = "".b # 使用二进制字符串
44
-
45
- # 遍历类型并编码
46
- types.each_with_index do |type, i|
47
- if type.dynamic?
48
- # 动态类型: 更新头部和尾部
49
- head += encode_uint256(head_size + tail.size)
50
- tail += encode_type(type, args[i])
51
- else
52
- # 静态类型: 只更新头部
53
- head += encode_type(type, args[i])
54
- end
55
- end
56
-
57
- head + tail
58
- end
59
29
  end
@@ -9,6 +9,8 @@ module AbiCoderRb
9
9
  /x
10
10
 
11
11
  def self.parse(type)
12
+ type = type.strip
13
+
12
14
  if type =~ TUPLE_TYPE_RX
13
15
  types = _parse_tuple_type(::Regexp.last_match(1))
14
16
  dims = _parse_dims(::Regexp.last_match(2))
@@ -18,8 +20,13 @@ module AbiCoderRb
18
20
  return _parse_array_type(Tuple.new(parsed_types), dims)
19
21
  end
20
22
 
23
+ # uint256 => uint, 256, nil
24
+ # uint256[2] => uint, 256, [2]
25
+ # uint256[] => uint, 256, [-1]
26
+ # bytes => bytes, nil, []
21
27
  base, sub, dims = _parse_base_type(type)
22
28
 
29
+ sub ||= 256 if type.start_with?("uint") || type.start_with?("int") # default to 256 if no sub given
23
30
  _validate_base_type(base, sub)
24
31
 
25
32
  subtype = case base
@@ -96,7 +103,7 @@ module AbiCoderRb
96
103
  # NOTE: string can not have any suffix
97
104
  raise ParseError, "String cannot have suffix" if sub
98
105
  when "bytes"
99
- raise ParseError, "Maximum 32 bytes for fixed-length bytes" if sub && sub > 32
106
+ raise ParseError, "Maximum 32 bytes for fixed-length bytes" if sub && sub > 32
100
107
  when "uint", "int"
101
108
  raise ParseError, "Integer type must have numerical suffix" unless sub
102
109
  raise ParseError, "Integer size out of bounds" unless sub >= 8 && sub <= 256
@@ -210,12 +210,19 @@ module AbiCoderRb
210
210
 
211
211
  def size
212
212
  s = 0
213
+ has_dynamic = false
213
214
  @types.each do |type|
214
215
  ts = type.size
215
- return nil if ts.nil?
216
-
217
- s += ts
216
+ if ts.nil?
217
+ # can not return nil here? if wasm
218
+ has_dynamic = true
219
+ else
220
+ s += ts
221
+ end
218
222
  end
223
+
224
+ return if has_dynamic
225
+
219
226
  s
220
227
  end
221
228
 
@@ -0,0 +1,111 @@
1
+ module AbiCoderRb
2
+ module Utils
3
+ class << self
4
+ def hex_to_bin(hex)
5
+ hex = hex[2..] if %w[0x 0X].include?(hex[0, 2]) ## cut-of leading 0x or 0X if present
6
+ hex.scan(/../).map { |x| x.hex.chr }.join
7
+ end
8
+
9
+ def bin_to_hex(bin)
10
+ bin.each_byte.map { |byte| "%02x" % byte }.join
11
+ end
12
+
13
+ def hex?(str)
14
+ str.start_with?("0x") && str.length.even? && str[2..].match?(/\A\b[0-9a-fA-F]+\b\z/)
15
+ end
16
+
17
+ # example:
18
+ # lpad("hello", 'x', 10) => "xxxxxxhello"
19
+ def lpad(str, sym, len)
20
+ return str if str.size >= len
21
+
22
+ sym * (len - str.size) + str
23
+ end
24
+
25
+ def zpad(str, len)
26
+ lpad str, BYTE_ZERO, len
27
+ end
28
+
29
+ def ffpad(str, len)
30
+ lpad str, BYTE_FF, len
31
+ end
32
+
33
+ def uint_to_big_endian(num, size)
34
+ raise "Can only serialize integers" unless num.is_a?(Integer)
35
+ raise "Cannot serialize negative integers" if num.negative?
36
+ raise "Integer too large (does not fit in #{size} bytes)" if size && num >= 256**size
37
+
38
+ # Convert num into a binary string
39
+ s = if num.zero?
40
+ BYTE_EMPTY
41
+ else
42
+ hex = num.to_s(16)
43
+ hex = "0#{hex}" if hex.size.odd?
44
+ hex_to_bin hex
45
+ end
46
+
47
+ # Adjust the size of the binary string to match the specified `size` in bytes, if `size` is given.
48
+ s = size ? "#{BYTE_ZERO * [0, size - s.size].max}#{s}" : s
49
+
50
+ zpad s, size
51
+ end
52
+
53
+ def int_to_abi_signed_256bit(value)
54
+ # 确保值在256位有符号整数范围内
55
+ min = -2**255
56
+ max = 2**255 - 1
57
+ raise "Value out of range" if value < min || value > max
58
+
59
+ # 为负数计算补码
60
+ value = (1 << 256) + value if value < 0
61
+
62
+ # 转换为十六进制字符串
63
+ hex_str = value.to_s(16)
64
+
65
+ # 确保字符串长度为64字符(256位)
66
+ hex_str.rjust(64, "0")
67
+ end
68
+
69
+ def int_to_abi_signed(value)
70
+ # 确保值在32位有符号整数范围内
71
+ raise "Value out of range" if value < -2**31 || value > 2**31 - 1
72
+
73
+ # 转换为32位有符号整数的二进制表示,然后转换为十六进制
74
+ hex_str = [value].pack("l>").unpack1("H*")
75
+
76
+ # 如果是正数,补齐前导零以达到64位长度
77
+ # 如果是负数,pack方法会产生正确的补码形式,但需要确保长度为64位
78
+ if value >= 0
79
+ hex_str.rjust(64, "0")
80
+ else
81
+ hex_str.rjust(64, "f")
82
+ end
83
+ end
84
+
85
+ def abi_to_int_signed(hex_str, bits)
86
+ hex_str = "0x#{hex_str}" if hex_str[0, 2] != "0x" || hex_str[0, 2] != "0X"
87
+
88
+ # 计算预期的十六进制字符串长度
89
+ expected_length = bits / 4
90
+ extended_hex_str = if hex_str.length < expected_length
91
+ # 如果输入长度小于预期,根据首位字符扩展字符串
92
+ extend_char = hex_str[0] == "f" ? "f" : "0"
93
+ extend_char * (expected_length - hex_str.length) + hex_str
94
+ else
95
+ hex_str
96
+ end
97
+
98
+ # 将十六进制字符串转换为二进制字符串
99
+ binary_str = extended_hex_str.to_i(16).to_s(2).rjust(bits, extended_hex_str[0])
100
+
101
+ # 检查符号位并转换为整数
102
+ if binary_str[0] == "1" # 负数
103
+ # 取反加一以计算补码,然后转换为负数
104
+ -((binary_str.tr("01", "10").to_i(2) + 1) & ((1 << bits) - 1))
105
+ else # 正数
106
+ binary_str.to_i(2)
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AbiCoderRb
4
- VERSION = "0.1.0"
4
+ VERSION = "0.2.0"
5
5
  end
data/lib/abi_coder_rb.rb CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  require_relative "abi_coder_rb/version"
4
4
 
5
+ require_relative "abi_coder_rb/utils"
6
+
5
7
  require_relative "abi_coder_rb/parser"
6
8
  require_relative "abi_coder_rb/types"
7
9
  require_relative "abi_coder_rb/decode"
@@ -13,17 +15,10 @@ module AbiCoderRb
13
15
  class ValueError < StandardError; end
14
16
  class ValueOutOfBounds < ValueError; end
15
17
 
16
- ###################
17
- ### some (shared) constants (move to constants.rb or such - why? why not?)
18
-
19
- ## todo/check: use auto-freeze string literals magic comment - why? why not?
20
- ##
21
- ## todo/fix: move BYTE_EMPTY, BYTE_ZERO, BYTE_ONE to upstream to bytes gem
22
- ## and make "global" constants - why? why not?
23
-
24
- ## BYTE_EMPTY = "".b.freeze
18
+ BYTE_EMPTY = "".b.freeze
25
19
  BYTE_ZERO = "\x00".b.freeze
26
20
  BYTE_ONE = "\x01".b.freeze ## note: used for encoding bool for now
21
+ BYTE_FF = "\xff".b.freeze
27
22
 
28
23
  UINT_MAX = 2**256 - 1 ## same as 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
29
24
  UINT_MIN = 0
@@ -32,12 +27,25 @@ module AbiCoderRb
32
27
 
33
28
  def hex_to_bin(hex) # convert hex(adecimal) string to binary string
34
29
  hex = hex[2..] if %w[0x 0X].include?(hex[0, 2]) ## cut-of leading 0x or 0X if present
35
- [hex].pack("H*")
30
+ hex.scan(/../).map { |x| x.hex.chr }.join
36
31
  end
37
32
  alias hex hex_to_bin
38
33
 
39
34
  def bin_to_hex(bin) # convert binary string to hex string
40
- bin.unpack1("H*")
35
+ bin.each_byte.map { |byte| "%02x" % byte }.join
36
+ end
37
+
38
+ def hex?(str)
39
+ str.start_with?("0x") && str.length.even? && str[2..].match?(/\A\b[0-9a-fA-F]+\b\z/)
40
+ end
41
+
42
+ attr_accessor :before_encoding_action, :after_decoding_action
43
+
44
+ def before_encoding(action)
45
+ self.before_encoding_action = action
46
+ end
47
+
48
+ def after_decoding(action)
49
+ self.after_decoding_action = action
41
50
  end
42
- alias bin bin_to_hex
43
51
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: abi_coder_rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aki Wu
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-11-13 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2023-11-25 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: keccak
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
13
27
  description: An EVM ABI encoding and decoding tool
14
28
  email:
15
29
  - wuminzhe@gmail.com
@@ -26,6 +40,8 @@ files:
26
40
  - LICENSE.txt
27
41
  - README.md
28
42
  - Rakefile
43
+ - flatten.rb
44
+ - flattened_abi_coder.rb
29
45
  - lib/.DS_Store
30
46
  - lib/abi_coder_rb.rb
31
47
  - lib/abi_coder_rb/.DS_Store
@@ -41,6 +57,7 @@ files:
41
57
  - lib/abi_coder_rb/encode/encode_tuple.rb
42
58
  - lib/abi_coder_rb/parser.rb
43
59
  - lib/abi_coder_rb/types.rb
60
+ - lib/abi_coder_rb/utils.rb
44
61
  - lib/abi_coder_rb/version.rb
45
62
  - sig/abi_coder_rb.rbs
46
63
  homepage: https://github.com/wuminzhe/abi_coder_rb