tezos_client 1.2.0 → 1.3.1

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.
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: []