tezos_client 1.2.0 → 1.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (31) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -1
  3. data/.travis.yml +3 -3
  4. data/Gemfile.lock +29 -29
  5. data/lib/tezos_client.rb +2 -0
  6. data/lib/tezos_client/commands.rb +2 -1
  7. data/lib/tezos_client/crypto.rb +20 -0
  8. data/lib/tezos_client/exceptions.rb +3 -0
  9. data/lib/tezos_client/operation_mgr.rb +29 -29
  10. data/lib/tezos_client/rpc_interface/contracts.rb +4 -0
  11. data/lib/tezos_client/smartpy_interface.rb +10 -10
  12. data/lib/tezos_client/tools/annots_to_type.rb +56 -0
  13. data/lib/tezos_client/tools/convert_to_hash.rb +0 -1
  14. data/lib/tezos_client/tools/convert_to_hash/address.rb +1 -1
  15. data/lib/tezos_client/tools/convert_to_hash/base.rb +22 -22
  16. data/lib/tezos_client/tools/convert_to_hash/big_map.rb +1 -1
  17. data/lib/tezos_client/tools/convert_to_hash/bytes.rb +1 -1
  18. data/lib/tezos_client/tools/convert_to_hash/int.rb +1 -1
  19. data/lib/tezos_client/tools/convert_to_hash/key.rb +1 -1
  20. data/lib/tezos_client/tools/convert_to_hash/list.rb +1 -1
  21. data/lib/tezos_client/tools/convert_to_hash/map.rb +31 -0
  22. data/lib/tezos_client/tools/convert_to_hash/nat.rb +1 -1
  23. data/lib/tezos_client/tools/convert_to_hash/option.rb +20 -0
  24. data/lib/tezos_client/tools/convert_to_hash/pair.rb +1 -1
  25. data/lib/tezos_client/tools/convert_to_hash/signature.rb +1 -1
  26. data/lib/tezos_client/tools/convert_to_hash/string.rb +1 -1
  27. data/lib/tezos_client/tools/convert_to_hash/timestamp.rb +8 -2
  28. data/lib/tezos_client/tools/hash_to_micheline.rb +110 -0
  29. data/lib/tezos_client/tools/system_call.rb +1 -1
  30. data/lib/tezos_client/version.rb +1 -1
  31. metadata +10 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b34f7593bef70d5be1219dd4beba9e00f6114da81783148585312cd32eeb82e8
4
- data.tar.gz: 862385f6e2fbf82ac12ab9ce912939b9a9499a10a856d447da5d9878afc08ce5
3
+ metadata.gz: 1e2dc6502a81aa8acb23cab552f03edbb1c94d7e21bfa2e653f9d662b0f2f5b5
4
+ data.tar.gz: 807c964c0919c93331e3e45610195705bed3ead65ca71a51f46b13d557ba4b14
5
5
  SHA512:
6
- metadata.gz: fbf5f33ee51bc2a45edaed55c67bfa7d58addbcc5668eb87198765cdfd50e387bda96769ef238f63011c78e66f802efc89ef293cdd2fb57d9f50de8e0ad2fa45
7
- data.tar.gz: 83682fe26418295979576a1a88d66d5b1af082ca2e4195b47286ccaf1a1cc3c24470a4b5ded42b0062bf17d97ad9ded3d5e1768f645c2985c9c683f9395b5c80
6
+ metadata.gz: 6b8d7f60f470bc533c3305cc33c007614b87461c5c0ec64e9d0a535ded2ba5707108cd5c359b89b5f292d215a2aa1ed2eaeffed9c55efa6a0c8f0dd51b46d08a
7
+ data.tar.gz: 80532f0a06a7f8d4e810c80ef4c90ddac5e1bf4513bb17e10bc2b1659ed0e7319ed620649f655285d03fe34b1e5a971359d7fa676192f02b0089c17a08f8bd39
@@ -1 +1 @@
1
- 2.5.1
1
+ 2.6.5
@@ -13,11 +13,11 @@ rvm:
13
13
  before_install:
14
14
  - sh travis-scripts/prepare-ubuntu.sh
15
15
  - mkdir -p $HOME/bin
16
- - curl -s https://SmartPy.io/SmartPyBasic/SmartPy.sh > SmartPy.sh
16
+ - curl -s https://smartpy.io/dev-20200912-bbb4b34cb579f3d52320c3d2aed8ebcef04429b0/cli/SmartPy.sh > SmartPy.sh
17
17
  - chmod +x ./SmartPy.sh
18
- - ./SmartPy.sh local-install $HOME/bin/smartpy
18
+ - ./SmartPy.sh local-install-auto $HOME/bin/smartpy/cli
19
19
  - rm ./SmartPy.sh
20
- - export PATH="$PATH:$HOME/bin/:$HOME/bin/smartpy/SmartPyBasic/"
20
+ - export PATH="$PATH:$HOME/bin/:$HOME/bin/smartpy/cli/"
21
21
  - npm link michelson-to-micheline
22
22
  - gem install bundler -v 1.16.3
23
23
  script:
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- tezos_client (1.2.0)
4
+ tezos_client (1.3.1)
5
5
  active_interaction (~> 3.7)
6
6
  activesupport (~> 6.0.0)
7
7
  base58 (~> 0.2.3)
@@ -14,68 +14,68 @@ PATH
14
14
  GEM
15
15
  remote: https://rubygems.org/
16
16
  specs:
17
- actionpack (6.0.0)
18
- actionview (= 6.0.0)
19
- activesupport (= 6.0.0)
20
- rack (~> 2.0)
17
+ actionpack (6.0.3.3)
18
+ actionview (= 6.0.3.3)
19
+ activesupport (= 6.0.3.3)
20
+ rack (~> 2.0, >= 2.0.8)
21
21
  rack-test (>= 0.6.3)
22
22
  rails-dom-testing (~> 2.0)
23
23
  rails-html-sanitizer (~> 1.0, >= 1.2.0)
24
- actionview (6.0.0)
25
- activesupport (= 6.0.0)
24
+ actionview (6.0.3.3)
25
+ activesupport (= 6.0.3.3)
26
26
  builder (~> 3.1)
27
27
  erubi (~> 1.4)
28
28
  rails-dom-testing (~> 2.0)
29
29
  rails-html-sanitizer (~> 1.1, >= 1.2.0)
30
- active_interaction (3.8.0)
30
+ active_interaction (3.8.3)
31
31
  activemodel (>= 4, < 7)
32
- activemodel (6.0.0)
33
- activesupport (= 6.0.0)
34
- activesupport (6.0.0)
32
+ activemodel (6.0.3.3)
33
+ activesupport (= 6.0.3.3)
34
+ activesupport (6.0.3.3)
35
35
  concurrent-ruby (~> 1.0, >= 1.0.2)
36
36
  i18n (>= 0.7, < 2)
37
37
  minitest (~> 5.1)
38
38
  tzinfo (~> 1.1)
39
- zeitwerk (~> 2.1, >= 2.1.8)
39
+ zeitwerk (~> 2.2, >= 2.2.2)
40
40
  addressable (2.7.0)
41
41
  public_suffix (>= 2.0.2, < 5.0)
42
42
  ast (2.4.0)
43
43
  base58 (0.2.3)
44
44
  bip_mnemonic (0.0.4)
45
- builder (3.2.3)
45
+ builder (3.2.4)
46
46
  coderay (1.1.2)
47
- concurrent-ruby (1.1.5)
47
+ concurrent-ruby (1.1.7)
48
48
  crack (0.4.3)
49
49
  safe_yaml (~> 1.0.0)
50
- crass (1.0.5)
50
+ crass (1.0.6)
51
51
  diff-lcs (1.3)
52
52
  domain_name (0.5.20190701)
53
53
  unf (>= 0.0.5, < 1.0.0)
54
54
  erubi (1.9.0)
55
- ffi (1.12.2)
55
+ ffi (1.13.1)
56
56
  hashdiff (1.0.0)
57
57
  http-cookie (1.0.3)
58
58
  domain_name (~> 0.5)
59
59
  httparty (0.17.3)
60
60
  mime-types (~> 3.0)
61
61
  multi_xml (>= 0.5.2)
62
- i18n (1.7.0)
62
+ i18n (1.8.5)
63
63
  concurrent-ruby (~> 1.0)
64
64
  jaro_winkler (1.5.3)
65
- loofah (2.3.1)
65
+ loofah (2.7.0)
66
66
  crass (~> 1.0.2)
67
67
  nokogiri (>= 1.5.9)
68
68
  method_source (0.9.2)
69
69
  mime-types (3.3.1)
70
70
  mime-types-data (~> 3.2015)
71
- mime-types-data (3.2019.1009)
71
+ mime-types-data (3.2020.0512)
72
72
  mini_portile2 (2.4.0)
73
- minitest (5.13.0)
73
+ minitest (5.14.2)
74
74
  money-tree (0.10.0)
75
75
  ffi
76
76
  multi_xml (0.6.0)
77
77
  netrc (0.11.0)
78
- nokogiri (1.10.8)
78
+ nokogiri (1.10.10)
79
79
  mini_portile2 (~> 2.4.0)
80
80
  parallel (1.18.0)
81
81
  parser (2.6.5.0)
@@ -84,7 +84,7 @@ GEM
84
84
  coderay (~> 1.1.0)
85
85
  method_source (~> 0.9.0)
86
86
  public_suffix (4.0.1)
87
- rack (2.0.8)
87
+ rack (2.2.3)
88
88
  rack-test (1.1.0)
89
89
  rack (>= 1.0, < 3)
90
90
  rails-dom-testing (2.0.3)
@@ -92,9 +92,9 @@ GEM
92
92
  nokogiri (>= 1.6)
93
93
  rails-html-sanitizer (1.3.0)
94
94
  loofah (~> 2.3)
95
- railties (6.0.0)
96
- actionpack (= 6.0.0)
97
- activesupport (= 6.0.0)
95
+ railties (6.0.3.3)
96
+ actionpack (= 6.0.3.3)
97
+ activesupport (= 6.0.3.3)
98
98
  method_source
99
99
  rake (>= 0.8.7)
100
100
  thor (>= 0.20.3, < 2.0)
@@ -138,20 +138,20 @@ GEM
138
138
  rubocop-rails (~> 2.0)
139
139
  ruby-progressbar (1.10.1)
140
140
  safe_yaml (1.0.5)
141
- thor (0.20.3)
141
+ thor (1.0.1)
142
142
  thread_safe (0.3.6)
143
- tzinfo (1.2.5)
143
+ tzinfo (1.2.7)
144
144
  thread_safe (~> 0.1)
145
145
  unf (0.1.4)
146
146
  unf_ext
147
- unf_ext (0.0.7.6)
147
+ unf_ext (0.0.7.7)
148
148
  unicode-display_width (1.6.0)
149
149
  vcr (4.0.0)
150
150
  webmock (3.7.6)
151
151
  addressable (>= 2.3.6)
152
152
  crack (>= 0.3.2)
153
153
  hashdiff (>= 0.4.0, < 2.0.0)
154
- zeitwerk (2.2.1)
154
+ zeitwerk (2.4.0)
155
155
 
156
156
  PLATFORMS
157
157
  ruby
@@ -36,6 +36,8 @@ require "tezos_client/smartpy_interface"
36
36
 
37
37
  require "tezos_client/tools/convert_to_hash"
38
38
  require "tezos_client/tools/find_big_maps_in_storage"
39
+ require "tezos_client/tools/hash_to_micheline"
40
+ require "tezos_client/tools/annots_to_type"
39
41
 
40
42
  class TezosClient
41
43
  using CurrencyUtils
@@ -25,6 +25,7 @@ class TezosClient
25
25
  :contract_big_maps,
26
26
  :block_operations,
27
27
  :contract_storage_type,
28
- :entrypoint
28
+ :entrypoint,
29
+ :entrypoints
29
30
  end
30
31
  end
@@ -165,6 +165,22 @@ class TezosClient
165
165
  end
166
166
  end
167
167
 
168
+ # payload must be bytes
169
+ def check_signature(public_key:, signature:, payload:)
170
+ verify_key = RbNaCl::VerifyKey.new(decode_tz(public_key).to_bin)
171
+
172
+ bin_sig = decode_tz(signature).to_bin
173
+ payload_hash = RbNaCl::Hash::Blake2b.digest(ignore_0x(payload).to_bin, digest_size: 32)
174
+
175
+ verify_key.verify(bin_sig, payload_hash)
176
+ rescue RbNaCl::BadSignatureError
177
+ false
178
+ end
179
+
180
+ def check_signature!(public_key:, signature:, payload:)
181
+ check_signature(public_key: public_key, signature: signature, payload: payload) || raise(BadSignatureError)
182
+ end
183
+
168
184
  def operation_id(signed_operation_hex)
169
185
  hash = RbNaCl::Hash::Blake2b.digest(
170
186
  signed_operation_hex.to_bin,
@@ -220,5 +236,9 @@ class TezosClient
220
236
  RbNaCl::SigningKey.generate
221
237
  end
222
238
  end
239
+
240
+ def ignore_0x(payload)
241
+ payload.starts_with?("0x") ? payload[2..-1] : payload
242
+ end
223
243
  end
224
244
  end
@@ -23,6 +23,9 @@ class TezosClient
23
23
  class SmartPyError < SysCallError
24
24
  end
25
25
 
26
+ class BadSignatureError < StandardError
27
+ end
28
+
26
29
  class InvalidActivation < RpcRequestFailure
27
30
  attr_reader :pkh
28
31
 
@@ -184,7 +184,8 @@ class TezosClient
184
184
  operations: rpc_operation_args,
185
185
  signature: base_58_signature,
186
186
  protocol: protocol,
187
- branch: branch)
187
+ branch: branch
188
+ )
188
189
 
189
190
  ensure_applied!(rpc_responses)
190
191
 
@@ -201,40 +202,39 @@ class TezosClient
201
202
  end
202
203
 
203
204
  private
205
+ def ensure_applied!(rpc_responses)
206
+ metadatas = rpc_responses.map { |response| response[:metadata] }
207
+ operation_results = metadatas.map { |metadata| metadata[:operation_result] }
208
+ internal_operations = metadatas.map { |metadata| metadata[:internal_operation_results] }.flatten.compact
209
+ operation_results.concat(internal_operations.map { |internal_operation| internal_operation[:result] })
210
+
211
+ failed = operation_results.detect do |operation_result|
212
+ operation_result != nil && operation_result[:status] != "applied"
213
+ end
204
214
 
205
- def ensure_applied!(rpc_responses)
206
- metadatas = rpc_responses.map { |response| response[:metadata] }
207
- operation_results = metadatas.map { |metadata| metadata[:operation_result] }
208
- internal_operations = metadatas.map { |metadata| metadata[:internal_operation_results] }.flatten.compact
209
- operation_results.concat(internal_operations.map { |internal_operation| internal_operation[:result] })
210
-
211
- failed = operation_results.detect do |operation_result|
212
- operation_result != nil && operation_result[:status] != "applied"
213
- end
215
+ return metadatas if failed.nil?
214
216
 
215
- return metadatas if failed.nil?
217
+ failed_operation_result = operation_results.detect do |operation_result|
218
+ operation_result[:status] == "failed"
219
+ end
216
220
 
217
- failed_operation_result = operation_results.detect do |operation_result|
218
- operation_result[:status] == "failed"
221
+ failed!("failed", failed_operation_result[:errors], operation_results)
219
222
  end
220
223
 
221
- failed!("failed", failed_operation_result[:errors], operation_results)
222
- end
223
-
224
- def exception_klass(errors)
225
- error = errors[0]
226
- case error[:id]
227
- when TezBalanceTooLow::FIRST_ERROR_REGEXP
228
- TezBalanceTooLow
229
- when ScriptRuntimeError::FIRST_ERROR_REGEXP
230
- ScriptRuntimeError
231
- else
232
- OperationFailure
224
+ def exception_klass(errors)
225
+ error = errors[0]
226
+ case error[:id]
227
+ when TezBalanceTooLow::FIRST_ERROR_REGEXP
228
+ TezBalanceTooLow
229
+ when ScriptRuntimeError::FIRST_ERROR_REGEXP
230
+ ScriptRuntimeError
231
+ else
232
+ OperationFailure
233
+ end
233
234
  end
234
- end
235
235
 
236
- def failed!(status, errors, metadata)
237
- raise exception_klass(errors).new(metadata: metadata, errors: errors, status: status)
238
- end
236
+ def failed!(status, errors, metadata)
237
+ raise exception_klass(errors).new(metadata: metadata, errors: errors, status: status)
238
+ end
239
239
  end
240
240
  end
@@ -37,6 +37,10 @@ class TezosClient
37
37
  get "#{contract_link(contract_id)}/storage"
38
38
  end
39
39
 
40
+ def entrypoints(contract_id)
41
+ get("#{contract_link(contract_id)}/entrypoints")
42
+ end
43
+
40
44
  def entrypoint(contract_id, entrypoint)
41
45
  get("#{contract_link(contract_id)}/entrypoints/#{entrypoint}")
42
46
  end
@@ -30,16 +30,16 @@ class TezosClient
30
30
  end
31
31
 
32
32
  private
33
- def compile_to_michelson(args)
34
- Tools::TemporaryFile.with_file_copy(args[:script]) do |script_copy_path|
35
- script_basename = script_copy_path.split("/").last.sub(/.py$/, "")
36
- script_path = "/tmp/#{script_basename}/"
37
- init_script_filename = "contractStorage.tz"
38
- contract_script_filename = "contractCode.tz.json"
39
- call_smartpy ["local-compile", script_copy_path, args[:init_params], script_path]
40
-
41
- yield(script_path + contract_script_filename, script_path + init_script_filename)
42
- end
33
+ def compile_to_michelson(args)
34
+ Tools::TemporaryFile.with_file_copy(args[:script]) do |script_copy_path|
35
+ script_basename = script_copy_path.split("/").last.sub(/.py$/, "")
36
+ script_path = "/tmp/#{script_basename}/"
37
+ init_script_filename = "#{script_basename}_storage_init.tz"
38
+ contract_script_filename = "#{script_basename}_compiled.json"
39
+ call_smartpy ["compile", script_copy_path, args[:init_params], script_path]
40
+
41
+ yield(script_path + contract_script_filename, script_path + init_script_filename)
43
42
  end
43
+ end
44
44
  end
45
45
  end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ class TezosClient::Tools::AnnotsToType < ActiveInteraction::Base
4
+ # example of typed_annots :
5
+ # {
6
+ # spending_ref: "string",
7
+ # remainder_amount: "nat",
8
+ # expires_at: "timestamp"
9
+ # }
10
+ hash :typed_annots, strip: false
11
+
12
+ validate :validate_types
13
+
14
+ def execute
15
+ return { "prim" => typed_annots.values.first } if typed_annots.size == 1
16
+
17
+ { "prim" => "pair", "args" => generate_type_args(ordered_annots) }
18
+ end
19
+
20
+ private
21
+ def generate_type_args(annots)
22
+ annot = annots.pop
23
+ annot_type = typed_annots[annot]
24
+
25
+ unless annots.size == 1
26
+ return [
27
+ {
28
+ "prim" => annot_type,
29
+ "annots" => ["%#{annot}"]
30
+ },
31
+ {
32
+ "prim" => "pair",
33
+ "args" => generate_type_args(annots)
34
+ }
35
+ ]
36
+ end
37
+
38
+ generated_args = [{ "prim" => annot_type, "annots" => ["%#{annot}"] }]
39
+ annot = annots.pop
40
+ annot_type = typed_annots[annot]
41
+ generated_args.append({ "prim" => annot_type, "annots" => ["%#{annot}"] })
42
+
43
+ generated_args
44
+ end
45
+
46
+ def ordered_annots
47
+ @ordered_annots ||= typed_annots.keys.sort.reverse
48
+ end
49
+
50
+ def validate_types
51
+ allowed_types = TezosClient::Tools::HashToMicheline::TYPES_MAPPING.keys
52
+ return if typed_annots.values.map(&:to_sym).all? { |type| type.in? allowed_types }
53
+
54
+ errors.add(:base, "The allowed types are: #{allowed_types.join(', ')}")
55
+ end
56
+ end
@@ -13,7 +13,6 @@ class TezosClient
13
13
  def execute
14
14
  TezosClient::Tools::ConvertToHash::Base.new(data: data, type: type).value
15
15
  end
16
-
17
16
  end
18
17
  end
19
18
  end
@@ -26,4 +26,4 @@ class TezosClient
26
26
  end
27
27
  end
28
28
  end
29
- end
29
+ end
@@ -3,7 +3,6 @@
3
3
  class TezosClient
4
4
  module Tools
5
5
  class ConvertToHash < ActiveInteraction::Base
6
-
7
6
  class Base
8
7
  def initialize(data:, type:)
9
8
  @data = data
@@ -17,34 +16,35 @@ class TezosClient
17
16
  end
18
17
 
19
18
  protected
19
+ def decode
20
+ klass.new(
21
+ data: data,
22
+ type: type
23
+ ).decode
20
24
 
21
- def decode
22
- klass.new(data: data, type: type).decode
23
-
24
- rescue NameError
25
- raise NotImplementedError, "type '#{type[:prim]}' not implemented"
26
- end
25
+ rescue NameError
26
+ raise NotImplementedError, "type '#{type[:prim]}' not implemented"
27
+ end
27
28
 
28
- def anonymous?
29
- !(type.key?(:annots) && type[:annots].any?)
30
- end
29
+ def anonymous?
30
+ !(type.key?(:annots) && type[:annots].any?)
31
+ end
31
32
 
32
- def var_name_annot
33
- type[:annots].first
34
- end
33
+ def var_name_annot
34
+ type[:annots].first
35
+ end
35
36
 
36
- def var_name
37
- return nil if anonymous?
37
+ def var_name
38
+ return nil if anonymous?
38
39
 
39
- "#{var_name_annot[1..-1]}".to_sym
40
- end
40
+ "#{var_name_annot[1..-1]}".to_sym
41
+ end
41
42
 
42
43
  private
43
-
44
- def klass
45
- "TezosClient::Tools::ConvertToHash::#{type[:prim].camelize}".constantize
46
- end
44
+ def klass
45
+ "TezosClient::Tools::ConvertToHash::#{type[:prim].camelize}".constantize
46
+ end
47
47
  end
48
48
  end
49
49
  end
50
- end
50
+ end
@@ -17,4 +17,4 @@ class TezosClient
17
17
  end
18
18
  end
19
19
  end
20
- end
20
+ end
@@ -10,4 +10,4 @@ class TezosClient
10
10
  end
11
11
  end
12
12
  end
13
- end
13
+ end
@@ -10,4 +10,4 @@ class TezosClient
10
10
  end
11
11
  end
12
12
  end
13
- end
13
+ end
@@ -24,4 +24,4 @@ class TezosClient
24
24
  end
25
25
  end
26
26
  end
27
- end
27
+ end
@@ -19,4 +19,4 @@ class TezosClient
19
19
  end
20
20
  end
21
21
  end
22
- end
22
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ class TezosClient
4
+ module Tools
5
+ class ConvertToHash < ActiveInteraction::Base
6
+ class Map < Base
7
+ def decode
8
+ new_map = {}
9
+
10
+ data.each do |elem|
11
+ raise "Not a 'Map' type" unless elem[:prim] == "Elt"
12
+
13
+ key = TezosClient::Tools::ConvertToHash::Base.new(
14
+ data: elem[:args].first,
15
+ type: type[:args].first
16
+ ).value
17
+
18
+ value = TezosClient::Tools::ConvertToHash::Base.new(
19
+ data: elem[:args].second,
20
+ type: type[:args].second
21
+ ).value
22
+
23
+ new_map[key] = value
24
+ end
25
+
26
+ new_map
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -10,4 +10,4 @@ class TezosClient
10
10
  end
11
11
  end
12
12
  end
13
- end
13
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ class TezosClient
4
+ module Tools
5
+ class ConvertToHash < ActiveInteraction::Base
6
+ class Option < Base
7
+ def decode
8
+ if data[:prim] == "None"
9
+ return nil
10
+ elsif data[:prim] == "Some"
11
+ TezosClient::Tools::ConvertToHash::Base.new(
12
+ data: data[:args][0],
13
+ type: type[:args][0]
14
+ ).value
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -18,4 +18,4 @@ class TezosClient
18
18
  end
19
19
  end
20
20
  end
21
- end
21
+ end
@@ -16,4 +16,4 @@ class TezosClient
16
16
  end
17
17
  end
18
18
  end
19
- end
19
+ end
@@ -10,4 +10,4 @@ class TezosClient
10
10
  end
11
11
  end
12
12
  end
13
- end
13
+ end
@@ -5,9 +5,15 @@ class TezosClient
5
5
  class ConvertToHash < ActiveInteraction::Base
6
6
  class Timestamp < Base
7
7
  def decode
8
- Time.zone.at(data[:int].to_i)
8
+ if data.key? :int
9
+ Time.zone.at(data[:int].to_i)
10
+ elsif data.key? :string
11
+ Time.zone.parse(data[:string])
12
+ else
13
+ raise "Can not convert timestamp: #{data}"
14
+ end
9
15
  end
10
16
  end
11
17
  end
12
18
  end
13
- end
19
+ end
@@ -0,0 +1,110 @@
1
+ # frozen_string_literal: true
2
+
3
+ class TezosClient::Tools::HashToMicheline < ActiveInteraction::Base
4
+ # TODO: handle Arrays and Maps
5
+ TYPES_MAPPING = {
6
+ int: :int,
7
+ nat: :int,
8
+ string: :string,
9
+ signature: :string,
10
+ bytes: :bytes,
11
+ timestamp: :int,
12
+ key: :string,
13
+ address: :string
14
+ }.freeze
15
+
16
+ string :contract_address, default: nil
17
+ string :entrypoint, default: nil
18
+ # example of params:
19
+ # {
20
+ # spending_ref: "toto",
21
+ # expires_at: Time.now
22
+ # }
23
+ hash :params, strip: false
24
+ hash :storage_type, strip: false, default: {}
25
+ interface :blockchain_client, methods: %i[entrypoint entrypoints], default: -> { TezosClient.new }
26
+
27
+ # if storage_type is not received, it is fetched from the blockchain using
28
+ # contract_address and entrypoint (that are mandatory in this case)
29
+ validate :storage_type_or_contract_address_presence
30
+
31
+ def execute
32
+ return hash_type_to_hash_data(_storage_type.fetch(:prim), params.values.first) if params.size == 1
33
+
34
+ { prim: "Pair", args: generate_micheline(_storage_type[:args]) }
35
+ end
36
+
37
+ private
38
+ def generate_micheline(remaining_storage_type)
39
+ remaining_storage_type.each_with_object([]) do |h, acc|
40
+ next acc << { prim: "Pair", args: generate_micheline(h[:args]) } if h[:prim] == "pair"
41
+
42
+ annot = h[:annots].first.slice(1..-1).to_sym # remove '%'
43
+
44
+ if h[:prim] == "option"
45
+ value = params.fetch(annot)
46
+ if value
47
+ acc << {
48
+ "prim": "Some",
49
+ "args": [
50
+ hash_type_to_hash_data(h[:args][0][:prim], params.fetch(annot))
51
+ ]
52
+ }
53
+ else
54
+ acc << {
55
+ "prim": "None"
56
+ }
57
+ end
58
+ else
59
+ acc << hash_type_to_hash_data(h[:prim], params.fetch(annot))
60
+ end
61
+ end
62
+ end
63
+
64
+ def convert_type(michelson_type)
65
+ TYPES_MAPPING.fetch(michelson_type.to_sym)
66
+ end
67
+
68
+ def hash_type_to_hash_data(michelson_type, value)
69
+ type = convert_type(michelson_type)
70
+
71
+ converted_value = case michelson_type.to_sym
72
+ when :nat, :int
73
+ value.to_s
74
+ when :timestamp
75
+ errors.add(:base, "timestamp input must be an instance of Time") unless value.is_a? Time
76
+
77
+ value.to_i.to_s
78
+ else
79
+ value
80
+ end
81
+
82
+ { type => converted_value }
83
+ end
84
+
85
+ def _entrypoint
86
+ @_entrypoint ||= select_entrypoint
87
+ end
88
+
89
+ def select_entrypoint
90
+ entrypoints = blockchain_client.entrypoints(contract_address)["entrypoints"].keys
91
+ if entrypoints.count == 0
92
+ "default"
93
+ elsif entrypoints.include?(entrypoint)
94
+ entrypoint
95
+ else
96
+ errors.add(:entrypoint, :not_found)
97
+ end
98
+ end
99
+
100
+ def _storage_type
101
+ (storage_type.presence || blockchain_client.entrypoint(contract_address, _entrypoint)).deep_symbolize_keys
102
+ end
103
+
104
+ def storage_type_or_contract_address_presence
105
+ return if storage_type.present? ^ (contract_address.present?)
106
+
107
+ errors.add(:base,
108
+ "You should provide the contract_address and the entrypoint only if storage_type is not provided")
109
+ end
110
+ end
@@ -5,10 +5,10 @@ class TezosClient
5
5
  module SystemCall
6
6
  def self.execute(cmd)
7
7
  Open3.popen3(*cmd) do |_stdin, stdout, stderr, wait_thr|
8
- err = stderr.read
9
8
  status = wait_thr.value.exitstatus
10
9
 
11
10
  if status != 0
11
+ err = stdout.read + stderr.read
12
12
  raise ::TezosClient::SysCallError, "command '#{cmd}' existed with status #{status}: #{err}"
13
13
  end
14
14
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class TezosClient
4
- VERSION = "1.2.0"
4
+ VERSION = "1.3.1"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tezos_client
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pierre Michard
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-03-09 00:00:00.000000000 Z
11
+ date: 2020-09-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -274,6 +274,7 @@ files:
274
274
  - lib/tezos_client/smartpy_inteface/smartpy_wrapper.rb
275
275
  - lib/tezos_client/smartpy_interface.rb
276
276
  - lib/tezos_client/string_utils.rb
277
+ - lib/tezos_client/tools/annots_to_type.rb
277
278
  - lib/tezos_client/tools/convert_to_hash.rb
278
279
  - lib/tezos_client/tools/convert_to_hash/address.rb
279
280
  - lib/tezos_client/tools/convert_to_hash/base.rb
@@ -282,12 +283,15 @@ files:
282
283
  - lib/tezos_client/tools/convert_to_hash/int.rb
283
284
  - lib/tezos_client/tools/convert_to_hash/key.rb
284
285
  - lib/tezos_client/tools/convert_to_hash/list.rb
286
+ - lib/tezos_client/tools/convert_to_hash/map.rb
285
287
  - lib/tezos_client/tools/convert_to_hash/nat.rb
288
+ - lib/tezos_client/tools/convert_to_hash/option.rb
286
289
  - lib/tezos_client/tools/convert_to_hash/pair.rb
287
290
  - lib/tezos_client/tools/convert_to_hash/signature.rb
288
291
  - lib/tezos_client/tools/convert_to_hash/string.rb
289
292
  - lib/tezos_client/tools/convert_to_hash/timestamp.rb
290
293
  - lib/tezos_client/tools/find_big_maps_in_storage.rb
294
+ - lib/tezos_client/tools/hash_to_micheline.rb
291
295
  - lib/tezos_client/tools/system_call.rb
292
296
  - lib/tezos_client/tools/temporary_file.rb
293
297
  - lib/tezos_client/version.rb
@@ -298,7 +302,7 @@ licenses:
298
302
  - MIT
299
303
  metadata:
300
304
  allowed_push_host: https://rubygems.org
301
- post_install_message:
305
+ post_install_message:
302
306
  rdoc_options: []
303
307
  require_paths:
304
308
  - lib
@@ -313,9 +317,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
313
317
  - !ruby/object:Gem::Version
314
318
  version: '0'
315
319
  requirements: []
316
- rubyforge_project:
317
- rubygems_version: 2.7.6
318
- signing_key:
320
+ rubygems_version: 3.0.3
321
+ signing_key:
319
322
  specification_version: 4
320
323
  summary: Wrapper to the tezos client.
321
324
  test_files: []