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.
- checksums.yaml +4 -4
- data/.DS_Store +0 -0
- data/Gemfile.lock +3 -1
- data/README.md +60 -2
- data/flatten.rb +8 -0
- data/flattened_abi_coder.rb +669 -0
- data/lib/.DS_Store +0 -0
- data/lib/abi_coder_rb/decode/decode_array.rb +6 -6
- data/lib/abi_coder_rb/decode/decode_primitive_type.rb +27 -22
- data/lib/abi_coder_rb/decode/decode_tuple.rb +29 -0
- data/lib/abi_coder_rb/decode.rb +3 -33
- data/lib/abi_coder_rb/encode/encode_fixed_array.rb +15 -1
- data/lib/abi_coder_rb/encode/encode_primitive_type.rb +20 -8
- data/lib/abi_coder_rb/encode/encode_tuple.rb +32 -0
- data/lib/abi_coder_rb/encode.rb +13 -43
- data/lib/abi_coder_rb/parser.rb +8 -1
- data/lib/abi_coder_rb/types.rb +10 -3
- data/lib/abi_coder_rb/utils.rb +111 -0
- data/lib/abi_coder_rb/version.rb +1 -1
- data/lib/abi_coder_rb.rb +20 -12
- metadata +20 -3
@@ -1,26 +1,30 @@
|
|
1
1
|
module AbiCoderRb
|
2
2
|
def decode_primitive_type(type, data)
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
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
|
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
|
data/lib/abi_coder_rb/decode.rb
CHANGED
@@ -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(
|
8
|
-
|
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
|
-
|
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
|
-
|
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,
|
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
|
-
|
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 !=
|
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"
|
128
|
-
bin =
|
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 =
|
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
|
data/lib/abi_coder_rb/encode.rb
CHANGED
@@ -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
|
-
|
9
|
-
|
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
|
-
|
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,
|
18
|
+
def encode_type(type, value)
|
21
19
|
if type.is_a?(Tuple)
|
22
|
-
encode_tuple(type,
|
23
|
-
elsif type.is_a?(Array)
|
24
|
-
|
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,
|
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
|
data/lib/abi_coder_rb/parser.rb
CHANGED
@@ -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"
|
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
|
data/lib/abi_coder_rb/types.rb
CHANGED
@@ -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
|
-
|
216
|
-
|
217
|
-
|
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
|
data/lib/abi_coder_rb/version.rb
CHANGED
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
|
-
|
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.
|
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.
|
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-
|
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
|