etheruby 0.0.2 → 0.0.3
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/lib/etheruby/arguments_generator.rb +60 -52
- data/lib/etheruby/client.rb +1 -1
- data/lib/etheruby/response_parser.rb +110 -0
- data/lib/etheruby/type_matchers.rb +25 -0
- data/lib/etheruby.rb +6 -1
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0c566325afa370e6f3d4dc52964b205b26a53da7
|
4
|
+
data.tar.gz: 10cd9eac53229fe3a293fe0cefc879abf9d2cc3f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6dc714bdcc04e5778b508d809e5e29fb230c4a1640f3e377c55d123a12d9929eb879f6d73175274816b7491a0943c2e96a0b60216ce240b2630e3038ff5553e8
|
7
|
+
data.tar.gz: c3cae2decb6fb2c2f8e79c3d27ed2dcbf3cf2c2ece666382445892cba8f226a4946e1f598a4f2803dd358b0158f35fab32c9cf24b3c1270a83c2ab8a97ea708b
|
@@ -1,9 +1,12 @@
|
|
1
|
+
require 'bigdecimal'
|
2
|
+
require_relative 'type_matchers'
|
3
|
+
|
1
4
|
module Etheruby
|
2
5
|
|
3
6
|
class IncorrectTypeError < StandardError; end
|
4
7
|
class ArgumentsCountError < StandardError; end
|
8
|
+
class InvalidFormatForDataError < StandardError; end
|
5
9
|
|
6
|
-
# https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI
|
7
10
|
class ArgumentsGenerator
|
8
11
|
|
9
12
|
attr_reader :params, :args
|
@@ -13,51 +16,33 @@ module Etheruby
|
|
13
16
|
@args = args
|
14
17
|
end
|
15
18
|
|
16
|
-
def
|
17
|
-
|
18
|
-
|
19
|
+
def treat_variable(param, arg)
|
20
|
+
if match = TypeMatchers.is_sized_type(param)
|
21
|
+
# Parameter is a sized type, e.g. uint256, byte32 ...
|
22
|
+
send("#{match[1]}_encode".to_sym, match[2].to_i, arg)
|
19
23
|
|
20
|
-
|
21
|
-
|
22
|
-
|
24
|
+
elsif match = TypeMatchers.is_dualsized_type(param)
|
25
|
+
# Parameter is a dual sized array type, e.g. fixed16x16
|
26
|
+
send("#{match[1]}_encode".to_sym, match[2].to_i, match[3].to_i, arg)
|
27
|
+
|
28
|
+
elsif match = TypeMatchers.is_static_array_type(param)
|
29
|
+
# Parameter is a staticly sized array type, e.g. uint256[24]
|
30
|
+
static_array_encode(match[1], match[2].to_i, arg)
|
31
|
+
|
32
|
+
elsif match = TypeMatchers.is_dynamic_array_type(param)
|
33
|
+
# Parameter is a dynamicaly sized array type, e.g. uint256[]
|
34
|
+
dynamic_array_encode(match[1], arg)
|
23
35
|
|
24
|
-
|
25
|
-
|
36
|
+
else
|
37
|
+
# Parameter is a single-word type : string, bytes, address etc...
|
38
|
+
send("#{param}_encode".to_sym, arg)
|
39
|
+
|
40
|
+
end
|
26
41
|
end
|
27
42
|
|
28
43
|
def to_s
|
29
44
|
raise ArgumentsCountError.new unless params.count == args.count
|
30
|
-
|
31
|
-
# For each parameter of the method called, we
|
32
|
-
# match the corresponding type to encode and we send the
|
33
|
-
# parameter given to this encoder
|
34
|
-
(0..params.count-1).each do |i|
|
35
|
-
param, arg = params[i], args[i]
|
36
|
-
if match = is_sized_type(param)
|
37
|
-
# Parameter is a sized type, e.g. uint256, byte32 ...
|
38
|
-
method_name = "#{match[1]}_encode".to_sym
|
39
|
-
if respond_to?(method_name)
|
40
|
-
arguments += send(method_name, match[2].to_i, arg)
|
41
|
-
else
|
42
|
-
raise IncorrectTypeError.new("Type #{param} cannot be encoded")
|
43
|
-
end
|
44
|
-
elsif match = is_static_array_type(param)
|
45
|
-
# Parameter is a staticly sized array type, e.g. uint256[24]
|
46
|
-
arguments += static_array(match[1], match[2].to_i, arg)
|
47
|
-
elsif match = is_dynamic_array_type(param)
|
48
|
-
# Parameter is a dynamicaly sized array type, e.g. uint256[]
|
49
|
-
arguments += dynamic_array(match[1], arg)
|
50
|
-
else
|
51
|
-
# Parameter is a single-word type : string, bytes, address etc...
|
52
|
-
method_name = "#{param}_encode".to_sym
|
53
|
-
if respond_to?(method_name)
|
54
|
-
arguments += send(method_name, arg)
|
55
|
-
else
|
56
|
-
raise IncorrectTypeError.new("Type #{param} cannot be encoded")
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
60
|
-
arguments
|
45
|
+
(0..params.count-1).map { |i| treat_variable(params[i], args[i]) }.join
|
61
46
|
end
|
62
47
|
|
63
48
|
##
|
@@ -74,37 +59,60 @@ module Etheruby
|
|
74
59
|
##
|
75
60
|
# uint<X> encoding
|
76
61
|
def uint_encode(size, arg)
|
77
|
-
|
62
|
+
raise InvalidFormatForDataError.new("unsigned integer #{arg} < 0") if arg < 0
|
63
|
+
int_encode(size, arg)
|
64
|
+
end
|
65
|
+
|
66
|
+
##
|
67
|
+
# ufixed<X> encoding
|
68
|
+
def ufixed_encode(size_i, size_d, arg)
|
69
|
+
raise InvalidFormatForDataError.new("unsigned fixed #{arg} < 0") if arg < 0
|
70
|
+
fixed_encode(size_i, size_d, arg)
|
78
71
|
end
|
79
72
|
|
80
73
|
##
|
81
74
|
# fixed<X> encoding
|
82
|
-
def fixed_encode(
|
83
|
-
|
75
|
+
def fixed_encode(size_i, size_d, arg)
|
76
|
+
raise InvalidFormatForDataError.new("Please use BigDecimal !") unless arg.is_a? BigDecimal
|
77
|
+
if arg >= 0
|
78
|
+
int_part, dec_part = arg.to_i, arg - arg.to_i
|
79
|
+
else
|
80
|
+
int_part, dec_part = arg.to_i, (arg + arg.to_i.abs).abs
|
81
|
+
end
|
82
|
+
int_encode(size_i, int_part) + \
|
83
|
+
decimal_representation(size_d, dec_part)
|
84
84
|
end
|
85
85
|
|
86
86
|
##
|
87
|
-
#
|
88
|
-
def
|
89
|
-
|
87
|
+
# Represent the decimal part in hexadimal according to the precision
|
88
|
+
def decimal_representation(precision, value)
|
89
|
+
(0..precision-1).map {
|
90
|
+
int_part, value = (value*2).to_i, (value*2) - (value*2).to_i
|
91
|
+
int_part
|
92
|
+
}.each_slice(8).map { |slice|
|
93
|
+
slice.join.to_i(2).to_s(16).rjust(2,'0')
|
94
|
+
}.join
|
90
95
|
end
|
91
96
|
|
92
97
|
##
|
93
98
|
# Encode a static array
|
94
|
-
def
|
95
|
-
|
99
|
+
def static_array_encode(type, size, arg)
|
100
|
+
raise InvalidFormatForDataError.new(
|
101
|
+
"Array have #{arg.count} items for #{size} sized variable"
|
102
|
+
) unless arg.count == size
|
103
|
+
arg.map { |item| treat_variable(type, item) }.join
|
96
104
|
end
|
97
105
|
|
98
106
|
##
|
99
107
|
# Creates a dynamic array
|
100
|
-
def
|
101
|
-
|
108
|
+
def dynamic_array_encode(type, arg)
|
109
|
+
uint_encode(256, arg.count) + static_array_encode(type, arg.count, arg)
|
102
110
|
end
|
103
111
|
|
104
112
|
##
|
105
113
|
# byte<X> encodeing
|
106
114
|
def byte_encode(size, arg)
|
107
|
-
arg.map{ |b| b.to_s(16) }.join.rjust(size,'0')
|
115
|
+
arg.map{ |b| b.to_s(16).rjust(2,'0') }.join.rjust(size,'0')
|
108
116
|
end
|
109
117
|
|
110
118
|
##
|
@@ -122,7 +130,7 @@ module Etheruby
|
|
122
130
|
##
|
123
131
|
# bytes (dynamic size) encoding
|
124
132
|
def bytes_encode(arg)
|
125
|
-
uint_encode(256, arg.count) + arg.map{ |b| b.to_s(16) }.join
|
133
|
+
uint_encode(256, arg.count) + arg.map{ |b| b.to_s(16).rjust(2,'0') }.join
|
126
134
|
end
|
127
135
|
|
128
136
|
##
|
data/lib/etheruby/client.rb
CHANGED
@@ -20,7 +20,7 @@ module Etheruby
|
|
20
20
|
@sym = sym
|
21
21
|
end
|
22
22
|
def method_missing(sym, *data)
|
23
|
-
body = { 'id' => '
|
23
|
+
body = { 'id' => '1', 'method' => "#{@sym}_#{sym}", 'params' => data }
|
24
24
|
text_response = http_post_request(::MultiJson.dump(body))
|
25
25
|
::MultiJson.load(text_response)
|
26
26
|
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require_relative 'type_matchers'
|
2
|
+
|
3
|
+
module Etheruby
|
4
|
+
|
5
|
+
class ResponseParser
|
6
|
+
|
7
|
+
def initialize(_returns, _response)
|
8
|
+
@returns = _returns
|
9
|
+
@response = _response
|
10
|
+
end
|
11
|
+
|
12
|
+
def treat_variable(param)
|
13
|
+
if match = TypeMatchers.is_sized_type(param)
|
14
|
+
# Parameter is a sized type, e.g. uint256, byte32 ...
|
15
|
+
send("#{match[1]}_decode".to_sym, match[2].to_i)
|
16
|
+
|
17
|
+
elsif match = TypeMatchers.is_dualsized_type(param)
|
18
|
+
# Parameter is a dual sized array type, e.g. fixed16x16
|
19
|
+
send("#{match[1]}_decode".to_sym, match[2].to_i, match[3].to_i)
|
20
|
+
|
21
|
+
elsif match = TypeMatchers.is_static_array_type(param)
|
22
|
+
# Parameter is a staticly sized array type, e.g. uint256[24]
|
23
|
+
static_array_decode(match[1], match[2].to_i)
|
24
|
+
|
25
|
+
elsif match = TypeMatchers.is_dynamic_array_type(param)
|
26
|
+
# Parameter is a dynamicaly sized array type, e.g. uint256[]
|
27
|
+
dynamic_array_decode(match[1])
|
28
|
+
|
29
|
+
else
|
30
|
+
# Parameter is a single-word type : string, bytes, address etc...
|
31
|
+
send("#{param}_decode".to_sym)
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def parse
|
37
|
+
if @returns.count == 1
|
38
|
+
treat_variable(@returns[0])
|
39
|
+
else
|
40
|
+
@returns.map { |type| treat_variable(type) }
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Each decode method will receive in parameters the response string remaining
|
45
|
+
# to parse. It will extract the type of the response considering it as the
|
46
|
+
# first thing in the string and returns the string without it. Doing this,
|
47
|
+
# method calls will be chainable easily.
|
48
|
+
|
49
|
+
##
|
50
|
+
# int<X> decoding
|
51
|
+
def int_decode(size)
|
52
|
+
end
|
53
|
+
|
54
|
+
##
|
55
|
+
# uint<X> decoding
|
56
|
+
def uint_decode(size)
|
57
|
+
v, @response = @response[0..(size/4)].to_i(16),
|
58
|
+
@response[(size/4)..@response.length]
|
59
|
+
v
|
60
|
+
end
|
61
|
+
|
62
|
+
##
|
63
|
+
# ufixed<X> decoding
|
64
|
+
def ufixed_decode(size_i, size_d)
|
65
|
+
end
|
66
|
+
|
67
|
+
##
|
68
|
+
# fixed<X> decoding
|
69
|
+
def fixed_decode(size_i, size_d)
|
70
|
+
end
|
71
|
+
|
72
|
+
##
|
73
|
+
# Decodes a static array
|
74
|
+
def static_array_decode(type, size)
|
75
|
+
end
|
76
|
+
|
77
|
+
##
|
78
|
+
# Decodes a dynamic array
|
79
|
+
def dynamic_array_decode(type)
|
80
|
+
end
|
81
|
+
|
82
|
+
##
|
83
|
+
# byte<X> decoding
|
84
|
+
def byte_decode(size)
|
85
|
+
end
|
86
|
+
|
87
|
+
##
|
88
|
+
# address<X> decoding
|
89
|
+
def address_decode
|
90
|
+
end
|
91
|
+
|
92
|
+
##
|
93
|
+
# string<x> decoding (as bytes)
|
94
|
+
def string_decode
|
95
|
+
end
|
96
|
+
|
97
|
+
##
|
98
|
+
# bytes (dynamic size) decoding
|
99
|
+
def bytes_decode
|
100
|
+
end
|
101
|
+
|
102
|
+
##
|
103
|
+
# boolean decoding (as uint8)
|
104
|
+
def bool_decode
|
105
|
+
uint_decode(8) == 1
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Etheruby
|
2
|
+
|
3
|
+
module TypeMatchers
|
4
|
+
|
5
|
+
def is_sized_type(param)
|
6
|
+
param.to_s.match /^([a-z]+)(\d+)$/
|
7
|
+
end
|
8
|
+
|
9
|
+
def is_dualsized_type(param)
|
10
|
+
param.to_s.match /^(.+)(\d+)x(\d+)$/
|
11
|
+
end
|
12
|
+
|
13
|
+
def is_static_array_type(param)
|
14
|
+
param.to_s.match(/^(.+)\[(\d+)\]$/)
|
15
|
+
end
|
16
|
+
|
17
|
+
def is_dynamic_array_type(param)
|
18
|
+
param.to_s.match(/^(.+)\[\]$/)
|
19
|
+
end
|
20
|
+
|
21
|
+
module_function :is_sized_type, :is_dualsized_type,
|
22
|
+
:is_static_array_type, :is_dynamic_array_type
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
data/lib/etheruby.rb
CHANGED
@@ -3,6 +3,7 @@ require 'logger'
|
|
3
3
|
require_relative 'etheruby/client'
|
4
4
|
require_relative 'etheruby/contract_method_dsl'
|
5
5
|
require_relative 'etheruby/arguments_generator'
|
6
|
+
require_relative 'etheruby/response_parser'
|
6
7
|
|
7
8
|
module Etheruby
|
8
9
|
class NoContractMethodError < StandardError; end
|
@@ -52,7 +53,11 @@ module Etheruby
|
|
52
53
|
else
|
53
54
|
@@logger.debug("Response from API for #{method_info[:name]} : #{response.inspect}")
|
54
55
|
end
|
55
|
-
|
56
|
+
if method_info.has_key? :returns
|
57
|
+
ResponseParser.new(method_info[:returns], response['result']).parse
|
58
|
+
else
|
59
|
+
response['result']
|
60
|
+
end
|
56
61
|
end
|
57
62
|
|
58
63
|
def self.address
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: etheruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jérémy SEBAN
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-01-
|
11
|
+
date: 2017-01-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: digest-sha3
|
@@ -80,7 +80,8 @@ dependencies:
|
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '3.5'
|
83
|
-
description:
|
83
|
+
description: Etheruby is a library including a client for the JSON-RPC API and a Object-Contract
|
84
|
+
Mapper to interact with smart-contracts.
|
84
85
|
email: jeremy@seban.eu
|
85
86
|
executables: []
|
86
87
|
extensions: []
|
@@ -90,6 +91,8 @@ files:
|
|
90
91
|
- lib/etheruby/arguments_generator.rb
|
91
92
|
- lib/etheruby/client.rb
|
92
93
|
- lib/etheruby/contract_method_dsl.rb
|
94
|
+
- lib/etheruby/response_parser.rb
|
95
|
+
- lib/etheruby/type_matchers.rb
|
93
96
|
homepage: https://github.com/MechanicalSloth/etheruby
|
94
97
|
licenses:
|
95
98
|
- MIT
|