tezos_client 1.2.2 → 1.3.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -1
  3. data/.travis.yml +2 -5
  4. data/Gemfile.lock +19 -19
  5. data/README.md +15 -36
  6. data/lib/tezos_client.rb +19 -2
  7. data/lib/tezos_client/commands.rb +3 -1
  8. data/lib/tezos_client/crypto.rb +20 -0
  9. data/lib/tezos_client/exceptions.rb +3 -0
  10. data/lib/tezos_client/logger.rb +1 -1
  11. data/lib/tezos_client/operation_mgr.rb +28 -29
  12. data/lib/tezos_client/rpc_interface/contracts.rb +4 -0
  13. data/lib/tezos_client/smartpy_interface.rb +10 -10
  14. data/lib/tezos_client/tools/annots_to_type.rb +38 -7
  15. data/lib/tezos_client/tools/convert_to_hash/base.rb +2 -2
  16. data/lib/tezos_client/tools/convert_to_hash/option.rb +20 -0
  17. data/lib/tezos_client/tools/hash_to_micheline.rb +20 -44
  18. data/lib/tezos_client/tools/hash_to_micheline/address.rb +14 -0
  19. data/lib/tezos_client/tools/hash_to_micheline/base.rb +52 -0
  20. data/lib/tezos_client/tools/hash_to_micheline/bytes.rb +14 -0
  21. data/lib/tezos_client/tools/hash_to_micheline/contract.rb +14 -0
  22. data/lib/tezos_client/tools/hash_to_micheline/int.rb +13 -0
  23. data/lib/tezos_client/tools/hash_to_micheline/key.rb +14 -0
  24. data/lib/tezos_client/tools/hash_to_micheline/nat.rb +13 -0
  25. data/lib/tezos_client/tools/hash_to_micheline/option.rb +23 -0
  26. data/lib/tezos_client/tools/hash_to_micheline/pair.rb +45 -0
  27. data/lib/tezos_client/tools/hash_to_micheline/signature.rb +14 -0
  28. data/lib/tezos_client/tools/hash_to_micheline/string.rb +14 -0
  29. data/lib/tezos_client/tools/hash_to_micheline/timestamp.rb +14 -0
  30. data/lib/tezos_client/tools/system_call.rb +1 -1
  31. data/lib/tezos_client/version.rb +1 -1
  32. data/travis-scripts/prepare-ubuntu.sh +6 -1
  33. metadata +16 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a1459f7dd534e408bd13520b14789b9f719a6cec9b004f5ab3ca00c151da1ac4
4
- data.tar.gz: 2aa7c36fc10c82537de03593e592703274daedcff36edec84130c98cc385098f
3
+ metadata.gz: 52e7b70d781942af2a66c3db62098d68541585a00afa73c09e24993d16e3c426
4
+ data.tar.gz: 8aa477e4e46f96584904c5d6dc625545dc6a606f69225969ac4b5efc472c5573
5
5
  SHA512:
6
- metadata.gz: fa9dc95f337c4bbbda410392c03d6305c93ee8f4dfec1810f629c0143a4beb3ce88789f5c4eaa809ae572bb4871ad44b0e87d35071727f9800cc9167f290492f
7
- data.tar.gz: e625840ea65befc0adc6ece5e334d8e869daabbaa2e6a9fc51881dda0ba3971dcec2f0d3274968e07a7e9268e1af93469c1f70f1395fa3d773119e871ab55f2a
6
+ metadata.gz: 0a1f456ca8177be6127e90da3c2ca964361180e2ca6b2f1d81f6875124ce9a1e8e8f512476d4470d9d0821078be5c42d1382bd5e761fed4f1a8ce95c0eb2c535
7
+ data.tar.gz: b9ec354b6fdba9e4f1eabe5265ffa68966c2035e11900b09ca2f7d501890fe2b7abb99a693b2b8cfe16df83453d8c677f27bc657f157622db4a5e3f02986ccb2
@@ -1 +1 @@
1
- 2.5.1
1
+ 2.6.5
@@ -13,11 +13,8 @@ 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
17
- - chmod +x ./SmartPy.sh
18
- - ./SmartPy.sh local-install $HOME/bin/smartpy
19
- - rm ./SmartPy.sh
20
- - export PATH="$PATH:$HOME/bin/:$HOME/bin/smartpy/SmartPyBasic/"
16
+ - curl -s https://smartpy.io/cli/install.sh > SmartPyInstaller.sh && yes | sh SmartPyInstaller.sh
17
+ - export PATH="$PATH:$HOME/bin/:$HOME/smartpy-cli/"
21
18
  - npm link michelson-to-micheline
22
19
  - gem install bundler -v 1.16.3
23
20
  script:
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- tezos_client (1.2.2)
4
+ tezos_client (1.3.3)
5
5
  active_interaction (~> 3.7)
6
6
  activesupport (~> 6.0.0)
7
7
  base58 (~> 0.2.3)
@@ -14,24 +14,24 @@ PATH
14
14
  GEM
15
15
  remote: https://rubygems.org/
16
16
  specs:
17
- actionpack (6.0.3.2)
18
- actionview (= 6.0.3.2)
19
- activesupport (= 6.0.3.2)
17
+ actionpack (6.0.3.3)
18
+ actionview (= 6.0.3.3)
19
+ activesupport (= 6.0.3.3)
20
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.3.2)
25
- activesupport (= 6.0.3.2)
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.2)
30
+ active_interaction (3.8.3)
31
31
  activemodel (>= 4, < 7)
32
- activemodel (6.0.3.2)
33
- activesupport (= 6.0.3.2)
34
- activesupport (6.0.3.2)
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)
@@ -44,7 +44,7 @@ GEM
44
44
  bip_mnemonic (0.0.4)
45
45
  builder (3.2.4)
46
46
  coderay (1.1.2)
47
- concurrent-ruby (1.1.6)
47
+ concurrent-ruby (1.1.7)
48
48
  crack (0.4.3)
49
49
  safe_yaml (~> 1.0.0)
50
50
  crass (1.0.6)
@@ -59,10 +59,10 @@ GEM
59
59
  httparty (0.17.3)
60
60
  mime-types (~> 3.0)
61
61
  multi_xml (>= 0.5.2)
62
- i18n (1.8.3)
62
+ i18n (1.8.5)
63
63
  concurrent-ruby (~> 1.0)
64
64
  jaro_winkler (1.5.3)
65
- loofah (2.6.0)
65
+ loofah (2.7.0)
66
66
  crass (~> 1.0.2)
67
67
  nokogiri (>= 1.5.9)
68
68
  method_source (0.9.2)
@@ -70,12 +70,12 @@ GEM
70
70
  mime-types-data (~> 3.2015)
71
71
  mime-types-data (3.2020.0512)
72
72
  mini_portile2 (2.4.0)
73
- minitest (5.14.1)
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.9)
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)
@@ -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.3.2)
96
- actionpack (= 6.0.3.2)
97
- activesupport (= 6.0.3.2)
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)
@@ -151,7 +151,7 @@ GEM
151
151
  addressable (>= 2.3.6)
152
152
  crack (>= 0.3.2)
153
153
  hashdiff (>= 0.4.0, < 2.0.0)
154
- zeitwerk (2.3.0)
154
+ zeitwerk (2.4.0)
155
155
 
156
156
  PLATFORMS
157
157
  ruby
data/README.md CHANGED
@@ -4,11 +4,12 @@
4
4
 
5
5
  [![Build Status](https://travis-ci.org/moneytrackio/tezos_client.svg?branch=master)](https://travis-ci.org/moneytrackio/tezos_client)
6
6
 
7
- Tezos Client interracts with tezos nodes using RPC commands.
7
+ Tezos Client interacts with Tezos nodes using RPC commands.
8
8
 
9
- ## Requirements:
10
- Tezos client requires liquidity to be installed in order to work properly.
11
- For installing on linux, you can basically follow the steps coded in travis-script folder.
9
+ ## Requirements
10
+
11
+ Tezos client requires SmartPy to be installed in order to work properly.
12
+ To install it on Linux, you can basically follow the steps coded in travis-script folder.
12
13
 
13
14
  ## Dependency
14
15
 
@@ -18,16 +19,12 @@ sudo apt-get install nodejs
18
19
  npm i -g michelson-to-micheline
19
20
  ```
20
21
 
21
- ### liquidity
22
- [liquidity installation](http://www.liquidity-lang.org/doc/installation/index.html)
23
-
24
- need the tezos version (not Dune version)
25
-
26
22
  ### SmartPy
27
23
  [SmartPy](https://smartpy.io/)
28
24
 
29
25
  ```bash
30
- sh <(curl -s https://SmartPy.io/SmartPyBasic/SmartPy.sh) local-install /
26
+ sh <(curl -s https://smartpy.io/dev-20200924-23b26494361d96abf034bdbb1ad1af396f95fd61/cli/SmartPy.sh) local-install-auto
27
+ export PATH=$PATH:$HOME/smartpy-cli/
31
28
  ```
32
29
 
33
30
  ### TypeScript (for dev)
@@ -53,9 +50,10 @@ Or install it yourself as:
53
50
 
54
51
  ## Usage
55
52
 
56
- ### Generate Tezos key paris
53
+ ### Generate Tezos key pairs
54
+
55
+ Generate a perfectly random key pair:
57
56
 
58
- Generate a prefectly random key pair:
59
57
  ```ruby
60
58
  client = TezosClient.new
61
59
  key = subject.generate_key
@@ -68,6 +66,7 @@ key = subject.generate_key
68
66
  ```
69
67
 
70
68
  Generate a key pair from a seed and a BIP 44 Path:
69
+
71
70
  ```ruby
72
71
  key = subject.generate_key(wallet_seed:"000102030405060708090a0b0c0d0e0f", path: "m/44'/1729'/0'/0'/0'")
73
72
  expect(key[:address]).to eq "tz1RfnzRopJXH32SSDap2wMYGULBAnmHxdP1"
@@ -77,7 +76,8 @@ key = subject.generate_key(wallet_seed:"000102030405060708090a0b0c0d0e0f", path:
77
76
  # :address=>"tz1a97x7GAvMDyrwwKTLQo131CoidXyUef48"
78
77
  # }
79
78
  ```
80
- Generate a key pair from a BIP-39 mnemonic sentence and a BIP 44 Path:
79
+ Generate a key pair from a BIP-39 mnemonic sentence and a BIP 44 Path:
80
+
81
81
  ```ruby
82
82
  key = subject.generate_key(
83
83
  mnemonic: "below dove cushion divide future artefact orange congress maple fiscal flower enable",
@@ -117,28 +117,6 @@ client.transfer(
117
117
  )
118
118
  ```
119
119
 
120
- ### Originate a contract written in liquidity
121
-
122
- ```ruby
123
- script = File.expand_path("./spec/fixtures/demo.py")
124
- source = "tz1ZWiiPXowuhN1UqNGVTrgNyf5tdxp4XUUq"
125
- secret_key = "edsk4EcqupPmaebat5mP57ZQ3zo8NDkwv8vQmafdYZyeXxrSc72pjN"
126
- amount = 0
127
- init_params= "MyContract()"
128
- client = TezosClient.new
129
-
130
- res = client.originate_contract(
131
- from: source,
132
- amount: amount,
133
- script: script,
134
- secret_key: secret_key,
135
- init_params: init_params
136
- )
137
-
138
- puts "Origination operation: #{res[:operation_id]}"
139
- puts "Contract address: #{res[:originated_contract]}"
140
- ```
141
-
142
120
  ### Originate a contract written in SmartPy
143
121
 
144
122
  ```ruby
@@ -146,7 +124,7 @@ script = File.expand_path("./spec/fixtures/demo.py")
146
124
  source = "tz1ZWiiPXowuhN1UqNGVTrgNyf5tdxp4XUUq"
147
125
  secret_key = "edsk4EcqupPmaebat5mP57ZQ3zo8NDkwv8vQmafdYZyeXxrSc72pjN"
148
126
  amount = 0
149
- init_params = "MyContract(1, 1)"
127
+ init_params= "MyContract()"
150
128
  client = TezosClient.new
151
129
 
152
130
  res = client.originate_contract(
@@ -162,6 +140,7 @@ puts "Contract address: #{res[:originated_contract]}"
162
140
  ```
163
141
 
164
142
  ### Call a contract written in SmartPy
143
+
165
144
  ```ruby
166
145
  TezosClient.new.call_contract(
167
146
  from: "tz1ZWiiPXowuhN1UqNGVTrgNyf5tdxp4XUUq",
@@ -165,14 +165,19 @@ class TezosClient
165
165
  end
166
166
 
167
167
  def call_contract(dry_run: false, entrypoint:, params:, params_type:, **args)
168
+ _entrypoint = select_entrypoint(
169
+ contract_address: args[:to],
170
+ entrypoint: entrypoint
171
+ )
172
+
168
173
  json_params = micheline_params(
169
174
  params: params,
170
- entrypoint: entrypoint,
175
+ entrypoint: _entrypoint,
171
176
  params_type: params_type
172
177
  )
173
178
 
174
179
  transfer_args = args.merge(
175
- entrypoint: entrypoint,
180
+ entrypoint: _entrypoint,
176
181
  parameters: json_params,
177
182
  dry_run: dry_run
178
183
  )
@@ -180,6 +185,18 @@ class TezosClient
180
185
  transfer(transfer_args)
181
186
  end
182
187
 
188
+ def select_entrypoint(contract_address:, entrypoint:)
189
+ entrypoints = entrypoints(contract_address)["entrypoints"].keys
190
+
191
+ if entrypoints.count == 0
192
+ "default"
193
+ elsif entrypoints.include?(entrypoint)
194
+ entrypoint
195
+ else
196
+ raise ::ArgumentError, "entrypoint #{entrypoint} not found in #{entrypoints}"
197
+ end
198
+ end
199
+
183
200
  def inject_raw_operations(secret_key:, raw_operations:, dry_run: false, **args)
184
201
  public_key = secret_key_to_public_key(secret_key)
185
202
  from = public_key_to_address(public_key)
@@ -25,6 +25,8 @@ class TezosClient
25
25
  :contract_big_maps,
26
26
  :block_operations,
27
27
  :contract_storage_type,
28
- :entrypoint
28
+ :entrypoint,
29
+ :entrypoints,
30
+ :select_entrypoint
29
31
  end
30
32
  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
 
@@ -13,7 +13,7 @@ class TezosClient
13
13
  self.class.logger << out + "\n"
14
14
  end
15
15
 
16
- FILTERED_KEYS = [:code, :contractCode]
16
+ FILTERED_KEYS = [:code, :contractCode, :contract_code]
17
17
  def tezos_contents_log_filter(content)
18
18
  if content.is_a? Array
19
19
  content.map { |el| tezos_contents_log_filter(el) }
@@ -202,40 +202,39 @@ class TezosClient
202
202
  end
203
203
 
204
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
205
214
 
206
- def ensure_applied!(rpc_responses)
207
- metadatas = rpc_responses.map { |response| response[:metadata] }
208
- operation_results = metadatas.map { |metadata| metadata[:operation_result] }
209
- internal_operations = metadatas.map { |metadata| metadata[:internal_operation_results] }.flatten.compact
210
- operation_results.concat(internal_operations.map { |internal_operation| internal_operation[:result] })
211
-
212
- failed = operation_results.detect do |operation_result|
213
- operation_result != nil && operation_result[:status] != "applied"
214
- end
215
+ return metadatas if failed.nil?
215
216
 
216
- return metadatas if failed.nil?
217
+ failed_operation_result = operation_results.detect do |operation_result|
218
+ operation_result[:status] == "failed"
219
+ end
217
220
 
218
- failed_operation_result = operation_results.detect do |operation_result|
219
- operation_result[:status] == "failed"
221
+ failed!("failed", failed_operation_result[:errors], operation_results)
220
222
  end
221
223
 
222
- failed!("failed", failed_operation_result[:errors], operation_results)
223
- end
224
-
225
- def exception_klass(errors)
226
- error = errors[0]
227
- case error[:id]
228
- when TezBalanceTooLow::FIRST_ERROR_REGEXP
229
- TezBalanceTooLow
230
- when ScriptRuntimeError::FIRST_ERROR_REGEXP
231
- ScriptRuntimeError
232
- else
233
- 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
234
234
  end
235
- end
236
235
 
237
- def failed!(status, errors, metadata)
238
- raise exception_klass(errors).new(metadata: metadata, errors: errors, status: status)
239
- end
236
+ def failed!(status, errors, metadata)
237
+ raise exception_klass(errors).new(metadata: metadata, errors: errors, status: status)
238
+ end
240
239
  end
241
- end
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
@@ -11,6 +11,17 @@ class TezosClient::Tools::AnnotsToType < ActiveInteraction::Base
11
11
 
12
12
  validate :validate_types
13
13
 
14
+ TYPES_MAPPING = {
15
+ int: :int,
16
+ nat: :int,
17
+ string: :string,
18
+ signature: :string,
19
+ bytes: :bytes,
20
+ timestamp: :int,
21
+ key: :string,
22
+ address: :string
23
+ }.freeze
24
+
14
25
  def execute
15
26
  return { "prim" => typed_annots.values.first } if typed_annots.size == 1
16
27
 
@@ -18,30 +29,50 @@ class TezosClient::Tools::AnnotsToType < ActiveInteraction::Base
18
29
  end
19
30
 
20
31
  private
32
+ def micheline_type(annot_type, annot)
33
+ if annot_type.to_s.start_with?("optional_")
34
+ {
35
+ "prim" => "option",
36
+ "args" => [{ "prim" => annot_type.to_s.delete_prefix("optional_") }],
37
+ "annots" => ["%#{annot}"]
38
+ }
39
+ else
40
+ {
41
+ "prim" => annot_type,
42
+ "annots" => ["%#{annot}"]
43
+ }
44
+ end
45
+ end
46
+
21
47
  def generate_type_args(annots)
22
48
  annot = annots.pop
23
49
  annot_type = typed_annots[annot]
24
50
 
25
51
  unless annots.size == 1
26
- return [{ "prim" => "pair", "args" => generate_type_args(annots) },
27
- { "prim" => annot_type, "annots" => ["%#{annot}"] }]
52
+ return [
53
+ micheline_type(annot_type, annot),
54
+ {
55
+ "prim" => "pair",
56
+ "args" => generate_type_args(annots)
57
+ }
58
+ ]
28
59
  end
29
60
 
30
- generated_args = [{ "prim" => annot_type, "annots" => ["%#{annot}"] }]
61
+ generated_args = [micheline_type(annot_type, annot)]
31
62
  annot = annots.pop
32
63
  annot_type = typed_annots[annot]
33
- generated_args.unshift({ "prim" => annot_type, "annots" => ["%#{annot}"] })
64
+ generated_args.append(micheline_type(annot_type, annot))
34
65
 
35
66
  generated_args
36
67
  end
37
68
 
38
69
  def ordered_annots
39
- @ordered_annots ||= typed_annots.keys.sort
70
+ @ordered_annots ||= typed_annots.keys.sort.reverse
40
71
  end
41
72
 
42
73
  def validate_types
43
- allowed_types = TezosClient::Tools::HashToMicheline::TYPES_MAPPING.keys
44
- return if typed_annots.values.map(&:to_sym).all? { |type| type.in? allowed_types }
74
+ allowed_types = TYPES_MAPPING.keys
75
+ return if typed_annots.values.map{|type| type.to_s.delete_prefix("optional_").to_sym}.all? { |type| type.in? allowed_types }
45
76
 
46
77
  errors.add(:base, "The allowed types are: #{allowed_types.join(', ')}")
47
78
  end
@@ -22,7 +22,7 @@ class TezosClient
22
22
  type: type
23
23
  ).decode
24
24
 
25
- rescue NameError => e
25
+ rescue NameError
26
26
  raise NotImplementedError, "type '#{type[:prim]}' not implemented"
27
27
  end
28
28
 
@@ -42,7 +42,7 @@ class TezosClient
42
42
 
43
43
  private
44
44
  def klass
45
- "TezosClient::Tools::ConvertToHash::#{type[:prim].camelize}".constantize
45
+ "#{self.class.name.deconstantize}::#{type[:prim].camelize}".constantize
46
46
  end
47
47
  end
48
48
  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
@@ -1,18 +1,11 @@
1
1
  # frozen_string_literal: true
2
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
3
+ require_relative "hash_to_micheline/base"
4
+
5
+ Dir[File.join(__dir__, "hash_to_micheline", "*.rb")].each { |file| require file }
6
+
15
7
 
8
+ class TezosClient::Tools::HashToMicheline < ActiveInteraction::Base
16
9
  string :contract_address, default: nil
17
10
  string :entrypoint, default: nil
18
11
  # example of params:
@@ -20,57 +13,40 @@ class TezosClient::Tools::HashToMicheline < ActiveInteraction::Base
20
13
  # spending_ref: "toto",
21
14
  # expires_at: Time.now
22
15
  # }
23
- hash :params, strip: false
16
+ interface :params
24
17
  hash :storage_type, strip: false, default: {}
25
- interface :blockchain_client, methods: [:entrypoint], default: -> { TezosClient.new }
18
+ interface :blockchain_client, methods: %i[entrypoint entrypoints select_entrypoint], default: -> { TezosClient.new }
26
19
 
27
20
  # if storage_type is not received, it is fetched from the blockchain using
28
21
  # contract_address and entrypoint (that are mandatory in this case)
29
22
  validate :storage_type_or_contract_address_presence
30
23
 
31
24
  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]) }
25
+ TezosClient::Tools::HashToMicheline::Base.new(data: _params, type: _storage_type).value
35
26
  end
36
27
 
37
28
  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
- acc << hash_type_to_hash_data(h[:prim], params.fetch(annot))
29
+ def _params
30
+ if params.respond_to?(:keys) && params.keys.size == 1 && !_storage_type.key?(:annots)
31
+ params.values.first
32
+ else
33
+ params
44
34
  end
45
35
  end
46
36
 
47
- def convert_type(michelson_type)
48
- TYPES_MAPPING.fetch(michelson_type.to_sym)
49
- end
50
-
51
- def hash_type_to_hash_data(michelson_type, value)
52
- type = convert_type(michelson_type)
53
-
54
- converted_value = case michelson_type.to_sym
55
- when :nat, :int
56
- value.to_s
57
- when :timestamp
58
- errors.add(:base, "timestamp input must be an instance of Time") unless value.is_a? Time
59
-
60
- value.to_i.to_s
61
- else
62
- value
63
- end
64
-
65
- { type => converted_value }
37
+ def _entrypoint
38
+ @_entrypoint ||= blockchain_client.select_entrypoint(
39
+ contract_address: contract_address,
40
+ entrypoint: entrypoint
41
+ )
66
42
  end
67
43
 
68
44
  def _storage_type
69
- (storage_type.presence || blockchain_client.entrypoint(contract_address, entrypoint)).deep_symbolize_keys
45
+ (storage_type.presence || blockchain_client.entrypoint(contract_address, _entrypoint)).deep_symbolize_keys
70
46
  end
71
47
 
72
48
  def storage_type_or_contract_address_presence
73
- return if storage_type.present? ^ (contract_address.present? && entrypoint.present?)
49
+ return if storage_type.present? ^ (contract_address.present?)
74
50
 
75
51
  errors.add(:base,
76
52
  "You should provide the contract_address and the entrypoint only if storage_type is not provided")
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ class TezosClient
4
+ module Tools
5
+ class HashToMicheline < ActiveInteraction::Base
6
+ class Address < Base
7
+ def encode
8
+ raise "#{data} #{data.class} Not a 'String' type" unless data.is_a? ::String
9
+ { string: data }
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ class TezosClient
4
+ module Tools
5
+ class HashToMicheline < ActiveInteraction::Base
6
+ class Base
7
+ def initialize(data:, type:)
8
+ @data = data
9
+ @type = type
10
+ end
11
+
12
+ attr_accessor :data, :type
13
+
14
+ def value
15
+ @data = anonymous? ? @data : @data.fetch(var_name)
16
+ encode
17
+ end
18
+
19
+ protected
20
+ def encode
21
+ klass.new(
22
+ data: data,
23
+ type: type
24
+ ).encode
25
+
26
+ rescue NameError
27
+ raise
28
+ raise NotImplementedError, "type '#{type[:prim]}' not implemented"
29
+ end
30
+
31
+ def anonymous?
32
+ !(type.key?(:annots) && type[:annots].any?)
33
+ end
34
+
35
+ def var_name_annot
36
+ type[:annots].first
37
+ end
38
+
39
+ def var_name
40
+ return nil if anonymous?
41
+
42
+ "#{var_name_annot[1..-1]}".to_sym
43
+ end
44
+
45
+ private
46
+ def klass
47
+ "#{self.class.name.deconstantize}::#{type[:prim].to_s.camelize}".constantize
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ class TezosClient
4
+ module Tools
5
+ class HashToMicheline < ActiveInteraction::Base
6
+ class Bytes < Base
7
+ def encode
8
+ raise "#{data} #{data.class} Not a 'String' type" unless data.is_a? ::String
9
+ { bytes: data }
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ class TezosClient
4
+ module Tools
5
+ class HashToMicheline < ActiveInteraction::Base
6
+ class Contract < Base
7
+ def encode
8
+ raise "#{data} #{data.class} Not a 'String' type" unless data.is_a? ::String
9
+ { string: data }
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ class TezosClient
4
+ module Tools
5
+ class HashToMicheline < ActiveInteraction::Base
6
+ class Int < Base
7
+ def encode
8
+ { int: data.to_s }
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ class TezosClient
4
+ module Tools
5
+ class HashToMicheline < ActiveInteraction::Base
6
+ class Key < Base
7
+ def encode
8
+ raise "#{data} #{data.class} Not a 'String' type" unless data.is_a? ::String
9
+ { string: data }
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ class TezosClient
4
+ module Tools
5
+ class HashToMicheline < ActiveInteraction::Base
6
+ class Nat < Base
7
+ def encode
8
+ { int: data.to_s }
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ class TezosClient
4
+ module Tools
5
+ class HashToMicheline < ActiveInteraction::Base
6
+ class Option < Base
7
+ def encode
8
+ return { prim: "None" } if data.nil?
9
+
10
+ {
11
+ prim: "Some",
12
+ args: [
13
+ TezosClient::Tools::HashToMicheline::Base.new(
14
+ data: data,
15
+ type: type[:args][0]
16
+ ).value
17
+ ]
18
+ }
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ class TezosClient
4
+ module Tools
5
+ class HashToMicheline < ActiveInteraction::Base
6
+ class Pair < Base
7
+ def encode
8
+ {
9
+ prim: "Pair",
10
+ args: [
11
+ TezosClient::Tools::HashToMicheline::Base.new(
12
+ data: data_0,
13
+ type: type[:args][0]
14
+ ).value,
15
+ TezosClient::Tools::HashToMicheline::Base.new(
16
+ data: data_1,
17
+ type: type[:args][1]
18
+ ).value
19
+ ]
20
+ }
21
+ end
22
+
23
+ def data_0
24
+ if data.is_a? ::Array
25
+ data[0]
26
+ else
27
+ data
28
+ end
29
+ end
30
+
31
+ def data_1
32
+ if data.is_a? ::Array
33
+ if data.size > 2
34
+ data.drop(1)
35
+ else
36
+ data[1]
37
+ end
38
+ else
39
+ data
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ class TezosClient
4
+ module Tools
5
+ class HashToMicheline < ActiveInteraction::Base
6
+ class Signature < Base
7
+ def encode
8
+ raise "#{data} does not seem to be a signature" unless data.starts_with?("edsig")
9
+ { string: data }
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ class TezosClient
4
+ module Tools
5
+ class HashToMicheline < ActiveInteraction::Base
6
+ class String < Base
7
+ def encode
8
+ raise "#{data} #{data.class} Not a 'String' type" unless data.is_a? ::String
9
+ { string: data }
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ class TezosClient
4
+ module Tools
5
+ class HashToMicheline < ActiveInteraction::Base
6
+ class Timestamp < Base
7
+ def encode
8
+ raise "timestamp input (#{data}) must be an instance of Time" unless data.is_a? Time
9
+ { int: data.to_i.to_s }
10
+ end
11
+ end
12
+ end
13
+ end
14
+ 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.2"
4
+ VERSION = "1.3.3"
5
5
  end
@@ -11,4 +11,9 @@ sudo add-apt-repository "deb http://fr.archive.ubuntu.com/ubuntu bionic main uni
11
11
  sudo apt-get update -qq
12
12
  sudo apt-get install -y -qq \
13
13
  libsecp256k1-dev libsecp256k1-0 libsodium-dev libssl-dev \
14
- bubblewrap libev-dev libhidapi-dev npm
14
+ bubblewrap libev-dev libhidapi-dev
15
+
16
+ wget -qO- https://deb.nodesource.com/setup_14.x | sudo -E bash -
17
+ sudo apt install -y nodejs
18
+ node --version
19
+ npm --version
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.2
4
+ version: 1.3.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pierre Michard
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-07-15 00:00:00.000000000 Z
11
+ date: 2021-01-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -285,12 +285,25 @@ files:
285
285
  - lib/tezos_client/tools/convert_to_hash/list.rb
286
286
  - lib/tezos_client/tools/convert_to_hash/map.rb
287
287
  - lib/tezos_client/tools/convert_to_hash/nat.rb
288
+ - lib/tezos_client/tools/convert_to_hash/option.rb
288
289
  - lib/tezos_client/tools/convert_to_hash/pair.rb
289
290
  - lib/tezos_client/tools/convert_to_hash/signature.rb
290
291
  - lib/tezos_client/tools/convert_to_hash/string.rb
291
292
  - lib/tezos_client/tools/convert_to_hash/timestamp.rb
292
293
  - lib/tezos_client/tools/find_big_maps_in_storage.rb
293
294
  - lib/tezos_client/tools/hash_to_micheline.rb
295
+ - lib/tezos_client/tools/hash_to_micheline/address.rb
296
+ - lib/tezos_client/tools/hash_to_micheline/base.rb
297
+ - lib/tezos_client/tools/hash_to_micheline/bytes.rb
298
+ - lib/tezos_client/tools/hash_to_micheline/contract.rb
299
+ - lib/tezos_client/tools/hash_to_micheline/int.rb
300
+ - lib/tezos_client/tools/hash_to_micheline/key.rb
301
+ - lib/tezos_client/tools/hash_to_micheline/nat.rb
302
+ - lib/tezos_client/tools/hash_to_micheline/option.rb
303
+ - lib/tezos_client/tools/hash_to_micheline/pair.rb
304
+ - lib/tezos_client/tools/hash_to_micheline/signature.rb
305
+ - lib/tezos_client/tools/hash_to_micheline/string.rb
306
+ - lib/tezos_client/tools/hash_to_micheline/timestamp.rb
294
307
  - lib/tezos_client/tools/system_call.rb
295
308
  - lib/tezos_client/tools/temporary_file.rb
296
309
  - lib/tezos_client/version.rb
@@ -316,7 +329,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
316
329
  - !ruby/object:Gem::Version
317
330
  version: '0'
318
331
  requirements: []
319
- rubygems_version: 3.0.4
332
+ rubygems_version: 3.0.3
320
333
  signing_key:
321
334
  specification_version: 4
322
335
  summary: Wrapper to the tezos client.