abi_coder_rb 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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