steem-ruby 0.9.3 → 0.9.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +9 -5
  3. data/README.md +10 -10
  4. data/lib/steem.rb +48 -0
  5. data/lib/steem/api.rb +0 -21
  6. data/lib/steem/base_error.rb +5 -3
  7. data/lib/steem/broadcast.rb +21 -4
  8. data/lib/steem/marshal.rb +231 -0
  9. data/lib/steem/mixins/jsonable.rb +37 -0
  10. data/lib/steem/mixins/serializable.rb +45 -0
  11. data/lib/steem/operation.rb +141 -0
  12. data/lib/steem/operation/account_create.rb +10 -0
  13. data/lib/steem/operation/account_create_with_delegation.rb +12 -0
  14. data/lib/steem/operation/account_update.rb +8 -0
  15. data/lib/steem/operation/account_witness_proxy.rb +4 -0
  16. data/lib/steem/operation/account_witness_vote.rb +5 -0
  17. data/lib/steem/operation/cancel_transfer_from_savings.rb +4 -0
  18. data/lib/steem/operation/challenge_authority.rb +5 -0
  19. data/lib/steem/operation/change_recovery_account.rb +5 -0
  20. data/lib/steem/operation/claim_account.rb +5 -0
  21. data/lib/steem/operation/claim_reward_balance.rb +6 -0
  22. data/lib/steem/operation/comment.rb +9 -0
  23. data/lib/steem/operation/comment_options.rb +10 -0
  24. data/lib/steem/operation/convert.rb +5 -0
  25. data/lib/steem/operation/create_claimed_account.rb +10 -0
  26. data/lib/steem/operation/custom.rb +5 -0
  27. data/lib/steem/operation/custom_binary.rb +8 -0
  28. data/lib/steem/operation/custom_json.rb +6 -0
  29. data/lib/steem/operation/decline_voting_rights.rb +4 -0
  30. data/lib/steem/operation/delegate_vesting_shares.rb +5 -0
  31. data/lib/steem/operation/delete_comment.rb +4 -0
  32. data/lib/steem/operation/escrow_approve.rb +8 -0
  33. data/lib/steem/operation/escrow_dispute.rb +7 -0
  34. data/lib/steem/operation/escrow_release.rb +10 -0
  35. data/lib/steem/operation/escrow_transfer.rb +12 -0
  36. data/lib/steem/operation/feed_publish.rb +4 -0
  37. data/lib/steem/operation/limit_order_cancel.rb +4 -0
  38. data/lib/steem/operation/limit_order_create.rb +8 -0
  39. data/lib/steem/operation/limit_order_create2.rb +8 -0
  40. data/lib/steem/operation/prove_authority.rb +4 -0
  41. data/lib/steem/operation/recover_account.rb +6 -0
  42. data/lib/steem/operation/report_over_production.rb +5 -0
  43. data/lib/steem/operation/request_account_recovery.rb +6 -0
  44. data/lib/steem/operation/reset_account.rb +5 -0
  45. data/lib/steem/operation/set_reset_account.rb +5 -0
  46. data/lib/steem/operation/set_withdraw_vesting_route.rb +6 -0
  47. data/lib/steem/operation/transfer.rb +6 -0
  48. data/lib/steem/operation/transfer_from_savings.rb +7 -0
  49. data/lib/steem/operation/transfer_to_savings.rb +6 -0
  50. data/lib/steem/operation/transfer_to_vesting.rb +5 -0
  51. data/lib/steem/operation/vote.rb +6 -0
  52. data/lib/steem/operation/withdraw_vesting.rb +4 -0
  53. data/lib/steem/operation/witness_set_properties.rb +5 -0
  54. data/lib/steem/operation/witness_update.rb +7 -0
  55. data/lib/steem/rpc/base_client.rb +13 -0
  56. data/lib/steem/rpc/http_client.rb +17 -1
  57. data/lib/steem/stream.rb +12 -4
  58. data/lib/steem/transaction.rb +96 -0
  59. data/lib/steem/transaction_builder.rb +69 -69
  60. data/lib/steem/type/amount.rb +2 -0
  61. data/lib/steem/version.rb +1 -1
  62. data/steem-ruby.gemspec +2 -0
  63. metadata +90 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 57f84dd9185bb2ad616730cb370450ff56816706a8ad5b26d452bf3a7921cd68
4
- data.tar.gz: 59934f9af8d4e20da692c06b9d8b55b71c54aaead980bec892c400ef100cc77c
3
+ metadata.gz: 67cb40fbb1b8cf229d3b7fe3388ce1f9ea0b922b2f16f42d73873d965971e209
4
+ data.tar.gz: b687c618e644cf4a0128875b4e40d16407b3138d91d777c69879585b0c561a93
5
5
  SHA512:
6
- metadata.gz: f909db06bc8e7db70da6180d385e0527e6153134b2535e275e6864f9c21511506bb93ae685fee51187024819dd9ad243939efa88213f29af8b51d28c6826290b
7
- data.tar.gz: 1b9d47fbb3775b639c53fc767f4a71a7d19578ca848f9f196ce1fd53ffe09d2b4eabc90ce70404a9deb523b448d0e2c70ceff53f2058b708e1b9d6be7dd983a2
6
+ metadata.gz: 8235f9f83af323bce4df042c7eb2c6c504af5385cc137520b068c850ca5bc2f661e492ac547001dbb1892f6cc3dd053f1d1db8c9df3977b5ca0dcdb5ab7d31b9
7
+ data.tar.gz: 23948d457b71f64db355850214d61b8d5a61439b8ae7af3f60e8583a7cb3335af861572f21a0daba5ae218e92a60caeec1bb651ab64399de73ea88f47a6ab743
@@ -1,7 +1,9 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- steem-ruby (0.9.3)
4
+ steem-ruby (0.9.4)
5
+ base58 (~> 0.2, >= 0.2.3)
6
+ bindata (~> 2.4, >= 2.4.4)
5
7
  bitcoin-ruby (~> 0.0, >= 0.0.18)
6
8
  ffi (~> 1.9, >= 1.9.23)
7
9
  hashie (~> 3.5, >= 3.5.7)
@@ -14,6 +16,8 @@ GEM
14
16
  addressable (2.5.2)
15
17
  public_suffix (>= 2.0.2, < 4.0)
16
18
  awesome_print (1.8.0)
19
+ base58 (0.2.3)
20
+ bindata (2.4.4)
17
21
  bitcoin-ruby (0.0.18)
18
22
  coderay (1.1.2)
19
23
  crack (0.4.3)
@@ -27,17 +31,17 @@ GEM
27
31
  logging (2.2.2)
28
32
  little-plugger (~> 1.1)
29
33
  multi_json (~> 1.10)
30
- method_source (0.9.0)
34
+ method_source (0.9.1)
31
35
  minitest (5.11.3)
32
36
  minitest-line (0.6.5)
33
37
  minitest (~> 5.0)
34
38
  minitest-proveit (1.0.0)
35
39
  minitest (> 5, < 7)
36
40
  multi_json (1.13.1)
37
- pry (0.11.3)
41
+ pry (0.12.0)
38
42
  coderay (~> 1.1.0)
39
43
  method_source (~> 0.9.0)
40
- public_suffix (3.0.2)
44
+ public_suffix (3.0.3)
41
45
  rake (12.3.1)
42
46
  safe_yaml (1.0.4)
43
47
  simplecov (0.16.1)
@@ -50,7 +54,7 @@ GEM
50
54
  addressable (>= 2.3.6)
51
55
  crack (>= 0.3.2)
52
56
  hashdiff
53
- yard (0.9.15)
57
+ yard (0.9.16)
54
58
 
55
59
  PLATFORMS
56
60
  ruby
data/README.md CHANGED
@@ -15,15 +15,15 @@ The `steem-ruby` gem was written from the ground up by `@inertia`, who is also t
15
15
 
16
16
  > "I intend to continue work on `radiator` indefinitely. But in `radiator-0.5`, I intend to refactor `radiator` so that is uses `steem-ruby` as its core. This means that some features of `radiator` like Serialization will become redundant. I think it's still useful for radiator to do its own serialization because it reduces the number of API requests." - @inertia
17
17
 
18
- | `radiator` | `steem-ruby` |
19
- |-|-|
20
- | Has internal failover logic | Can have failover delegated externally |
21
- | Passes `error` responses to the caller | Handles `error` responses and raises exceptions |
22
- | Supports tx signing, does its own serialization | Also supports tx signing, but delegates serialization to `database_api.get_transaction_hex` |
23
- | All apis and methods are hardcoded | Asks `jsonrpc` what apis and methods are available from the node |
24
- | (`radiator-0.4.x`) Only supports AppBase but relies on `condenser_api` | Only supports AppBase but does not rely on `condenser_api` **(WIP)**
25
- | Small list of helper methods for select ops (in addition to build your own transaction) | Complete implementation of helper methods for every op (in addition to build your own transaction) |
26
- | Does not (yet) support `json-rpc-batch` requests | Supports `json-rpc-batch` requests |
18
+ `radiator` | `steem-ruby`
19
+ ---------- | ------------
20
+ Has internal failover logic | Can have failover delegated externally
21
+ Passes `error` responses to the caller | Handles `error` responses and raises exceptions
22
+ Supports tx signing, does its own serialization | Also supports tx signing, but delegates serialization to `database_api.get_transaction_hex`, then deserializes to verify
23
+ All apis and methods are hardcoded | Asks `jsonrpc` what apis and methods are available from the node
24
+ (`radiator-0.4.x`) Only supports AppBase but relies on `condenser_api` | Only supports AppBase but does not rely on `condenser_api` **(WIP)**
25
+ Small list of helper methods for select ops (in addition to build your own transaction) | Complete implementation of helper methods for every op (in addition to build your own transaction)
26
+ Does not (yet) support `json-rpc-batch` requests | Supports `json-rpc-batch` requests
27
27
 
28
28
  ## Getting Started
29
29
 
@@ -186,7 +186,7 @@ trx = open('trx.json').read
186
186
  builder = Steem::TransactionBuilder.new(wif: wif2, trx: trx)
187
187
  api = Steem::CondenserApi.new
188
188
  trx = builder.transaction
189
- api.broadcast_transaction_synchronous(trx: trx)
189
+ api.broadcast_transaction_synchronous(trx)
190
190
  ```
191
191
 
192
192
  ### Get Accounts
@@ -6,10 +6,58 @@ require 'hashie'
6
6
  require 'steem/version'
7
7
  require 'steem/utils'
8
8
  require 'steem/base_error'
9
+ require 'steem/mixins/serializable'
10
+ require 'steem/mixins/jsonable'
9
11
  require 'steem/mixins/retriable'
10
12
  require 'steem/chain_config'
11
13
  require 'steem/type/base_type'
12
14
  require 'steem/type/amount'
15
+ require 'steem/operation'
16
+ require 'steem/operation/account_create.rb'
17
+ require 'steem/operation/account_create_with_delegation.rb'
18
+ require 'steem/operation/account_update.rb'
19
+ require 'steem/operation/account_witness_proxy.rb'
20
+ require 'steem/operation/account_witness_vote.rb'
21
+ require 'steem/operation/cancel_transfer_from_savings.rb'
22
+ require 'steem/operation/challenge_authority.rb'
23
+ require 'steem/operation/change_recovery_account.rb'
24
+ require 'steem/operation/claim_account.rb'
25
+ require 'steem/operation/claim_reward_balance.rb'
26
+ require 'steem/operation/comment.rb'
27
+ require 'steem/operation/comment_options.rb'
28
+ require 'steem/operation/convert.rb'
29
+ require 'steem/operation/create_claimed_account.rb'
30
+ require 'steem/operation/custom.rb'
31
+ require 'steem/operation/custom_binary.rb'
32
+ require 'steem/operation/custom_json.rb'
33
+ require 'steem/operation/decline_voting_rights.rb'
34
+ require 'steem/operation/delegate_vesting_shares.rb'
35
+ require 'steem/operation/delete_comment.rb'
36
+ require 'steem/operation/escrow_approve.rb'
37
+ require 'steem/operation/escrow_dispute.rb'
38
+ require 'steem/operation/escrow_release.rb'
39
+ require 'steem/operation/escrow_transfer.rb'
40
+ require 'steem/operation/feed_publish.rb'
41
+ require 'steem/operation/limit_order_cancel.rb'
42
+ require 'steem/operation/limit_order_create.rb'
43
+ require 'steem/operation/limit_order_create2.rb'
44
+ require 'steem/operation/prove_authority.rb'
45
+ require 'steem/operation/recover_account.rb'
46
+ require 'steem/operation/report_over_production.rb'
47
+ require 'steem/operation/request_account_recovery.rb'
48
+ require 'steem/operation/reset_account.rb'
49
+ require 'steem/operation/set_reset_account.rb'
50
+ require 'steem/operation/set_withdraw_vesting_route.rb'
51
+ require 'steem/operation/transfer.rb'
52
+ require 'steem/operation/transfer_from_savings.rb'
53
+ require 'steem/operation/transfer_to_savings.rb'
54
+ require 'steem/operation/transfer_to_vesting.rb'
55
+ require 'steem/operation/vote.rb'
56
+ require 'steem/operation/withdraw_vesting.rb'
57
+ require 'steem/operation/witness_update.rb'
58
+ require 'steem/operation/witness_set_properties.rb'
59
+ require 'steem/marshal'
60
+ require 'steem/transaction'
13
61
  require 'steem/transaction_builder'
14
62
  require 'steem/rpc/base_client'
15
63
  require 'steem/rpc/http_client'
@@ -149,19 +149,6 @@ module Steem
149
149
  @@signatures[url][rpc_method_name] ||= Api::jsonrpc(url).get_signature(method: rpc_method_name).result
150
150
  end
151
151
 
152
- # @private
153
- def raise_error_response(rpc_method_name, rpc_args, response)
154
- raise UnknownError, "#{rpc_method_name}: #{response}" if response.error.nil?
155
-
156
- error = response.error
157
-
158
- if error.message == 'Invalid Request'
159
- raise Steem::ArgumentError, "Unexpected arguments: #{rpc_args.inspect}. Expected: #{rpc_method_name} (#{args_keys_to_s(rpc_method_name)})"
160
- end
161
-
162
- BaseError.build_error(error, rpc_method_name)
163
- end
164
-
165
152
  # @private
166
153
  def respond_to_missing?(m, include_private = false)
167
154
  methods.nil? ? false : methods.include?(m.to_sym)
@@ -203,14 +190,6 @@ module Steem
203
190
 
204
191
  response = rpc_client.rpc_execute(@api_name, m, rpc_args)
205
192
 
206
- if defined?(response.error) && !!response.error
207
- if !!response.error.message
208
- raise_error_response rpc_method_name, rpc_args, response
209
- else
210
- raise Steem::ArgumentError, response.error.inspect
211
- end
212
- end
213
-
214
193
  if !!block
215
194
  case response
216
195
  when Hashie::Mash then yield response.result, response.error, response.id
@@ -10,7 +10,7 @@ module Steem
10
10
  detail[:error] = @error if !!@error
11
11
  detail[:cause] = @cause if !!@cause
12
12
 
13
- JSON[detail] rescue detai.to_s
13
+ JSON[detail] rescue detail.to_s
14
14
  end
15
15
 
16
16
  def self.build_error(error, context)
@@ -19,11 +19,11 @@ module Steem
19
19
  end
20
20
 
21
21
  if error.message.include? 'Internal Error'
22
- raise Steem::RemoteNodeError.new, error.message, build_backtrace(error)
22
+ raise Steem::RemoteNodeError, error.message, build_backtrace(error)
23
23
  end
24
24
 
25
25
  if error.message.include? 'Server error'
26
- raise Steem::RemoteNodeError.new, error.message, build_backtrace(error)
26
+ raise Steem::RemoteNodeError, error.message, build_backtrace(error)
27
27
  end
28
28
 
29
29
  if error.message.include? 'plugin not enabled'
@@ -176,6 +176,8 @@ module Steem
176
176
  end
177
177
  end
178
178
 
179
+ class DeserializationError < BaseError; end
180
+ class SerializationMismatchError < BaseError; end
179
181
  class UnsupportedChainError < BaseError; end
180
182
  class ArgumentError < BaseError; end
181
183
  class TypeError < BaseError; end
@@ -197,13 +197,17 @@ module Steem
197
197
  permlink: params[:permlink],
198
198
  max_accepted_payout: max_accepted_payout,
199
199
  percent_steem_dollars: params[:percent_steem_dollars] || 10000,
200
+ # allow_replies: allow_replies,
200
201
  allow_votes: allow_votes,
201
202
  allow_curation_rewards: allow_curation_rewards,
202
203
  extensions: []
203
204
  }
204
205
 
205
206
  if !!params[:beneficiaries]
206
- comment_options[:extensions] << [0, {beneficiaries: params[:beneficiaries]}]
207
+ comment_options[:extensions] << [
208
+ comment_options[:extensions].size,
209
+ normalize_beneficiaries(options.merge(beneficiaries: params[:beneficiaries]))
210
+ ]
207
211
  end
208
212
 
209
213
  ops << [:comment_options, comment_options]
@@ -567,7 +571,7 @@ module Steem
567
571
  check_required_fields(params, *required_fields)
568
572
 
569
573
  params[:extensions] ||= []
570
- ops = [[:account_create, params]]
574
+ ops = [[:create_claimed_account, params]]
571
575
 
572
576
  process(options.merge(ops: ops), &block)
573
577
  end
@@ -714,13 +718,21 @@ module Steem
714
718
  end
715
719
 
716
720
  if !!(sbd_exchange_rate = params[:props][:sbd_exchange_rate] rescue nil)
717
- params[:props][:sbd_exchange_rate] = normalize_amount(options.merge amount: sbd_exchange_rate, serialize: true)
721
+ params[:props][:sbd_exchange_rate][:base] = normalize_amount(options.merge amount: sbd_exchange_rate[:base], serialize: true)
722
+ params[:props][:sbd_exchange_rate][:quote] = normalize_amount(options.merge amount: sbd_exchange_rate[:quote], serialize: true)
723
+ params[:props][:sbd_exchange_rate] = params[:props][:sbd_exchange_rate].to_json
724
+ end
725
+
726
+ %i(key new_signing_key).each do |key|
727
+ if !!params[key] && params[key].size == 53
728
+ params[key] = params[key][3..-1]
729
+ end
718
730
  end
719
731
 
720
732
  %i(account_creation_fee sbd_exchange_rate url new_signing_key).each do |key|
721
733
  next unless !!params[:props][key]
722
734
 
723
- val = params[:props][key]
735
+ val = params[:props][key].to_s
724
736
 
725
737
  params[:props][key] = hexlify val unless val =~ /^[0-9A-F]+$/i
726
738
  end
@@ -1282,6 +1294,11 @@ module Steem
1282
1294
  end
1283
1295
  end
1284
1296
 
1297
+ def self.normalize_beneficiaries(options)
1298
+ # Type::Beneficiaries.new(options[:beneficiaries])
1299
+ {beneficiaries: options[:beneficiaries]}
1300
+ end
1301
+
1285
1302
  # @private
1286
1303
  def self.database_api(options)
1287
1304
  options[:database_api] ||= if !!options[:app_base]
@@ -0,0 +1,231 @@
1
+ require 'bindata'
2
+ require 'base58'
3
+
4
+ module Steem
5
+ class Marshal
6
+ include Utils
7
+ include ChainConfig
8
+
9
+ PUBLIC_KEY_DISABLED = '1111111111111111111111111111111114T1Anm'
10
+
11
+ attr_reader :bytes, :cursor
12
+
13
+ def initialize(options = {})
14
+ @bytes = if !!(hex = options[:hex])
15
+ unhexlify hex
16
+ else
17
+ options[:bytes]
18
+ end
19
+
20
+ @chain = options[:chain] || :steem
21
+ @prefix ||= case @chain
22
+ when :steem then NETWORKS_STEEM_ADDRESS_PREFIX
23
+ when :test then NETWORKS_TEST_ADDRESS_PREFIX
24
+ else; raise UnsupportedChainError, "Unsupported chain: #{@chain}"
25
+ end
26
+ @cursor = 0
27
+ end
28
+
29
+ def hex
30
+ hexlify bytes
31
+ end
32
+
33
+ def rewind!
34
+ @cursor = 0
35
+ end
36
+
37
+ def step(n = 0)
38
+ @cursor += n
39
+ end
40
+
41
+ def scan(len)
42
+ bytes.slice(@cursor..(@cursor - 1) + len).tap { |_| @cursor += len }
43
+ end
44
+
45
+ def operation_type
46
+ Operation::IDS[unsigned_char]
47
+ end
48
+
49
+ def unsigned_char; BinData::Uint8le.read(scan(1)); end # 8-bit unsigned
50
+ def uint16; BinData::Uint16le.read(scan(2)); end # 16-bit unsigned, VAX (little-endian) byte order
51
+ def uint32; BinData::Uint32le.read(scan(4)); end # 32-bit unsigned, VAX (little-endian) byte order
52
+ def uint64; BinData::Uint64le.read(scan(8)); end # 64-bit unsigned, little-endian
53
+
54
+ def signed_char; BinData::Int8le.read(scan(1)); end # 8-bit signed
55
+ def int16; BinData::Int16le.read(scan(2)); end # 16-bit signed, little-endian
56
+ def int32; BinData::Int32le.read(scan(4)); end # 32-bit signed, little-endian
57
+ def int64; BinData::Int64le.read(scan(8)); end # 64-bit signed, little-endian
58
+
59
+ def boolean; scan(1) == "\x01"; end
60
+
61
+ def varint
62
+ shift = 0
63
+ result = 0
64
+ bytes = []
65
+
66
+ while (n = unsigned_char) >> 7 == 1
67
+ bytes << n
68
+ end
69
+
70
+ bytes << n
71
+
72
+ bytes.each do |b|
73
+ result += ((b & 0x7f) << shift)
74
+ break unless (b & 0x80)
75
+ shift += 7
76
+ end
77
+
78
+ result
79
+ end
80
+
81
+ def string(len = nil); scan(len || varint); end
82
+
83
+ def raw_bytes(len = nil); scan(len || varint).force_encoding('BINARY'); end
84
+
85
+ def point_in_time
86
+ if (time = uint32) == 2**32-1
87
+ Time.at -1
88
+ else
89
+ Time.at time
90
+ end.utc
91
+ end
92
+
93
+ def public_key(prefix = @prefix)
94
+ raw_public_key = raw_bytes(33)
95
+ checksum = OpenSSL::Digest::RIPEMD160.digest(raw_public_key)
96
+ key = Base58.binary_to_base58(raw_public_key + checksum.slice(0, 4), :bitcoin)
97
+
98
+ prefix + key unless key == PUBLIC_KEY_DISABLED
99
+ end
100
+
101
+ def amount
102
+ amount = uint64.to_f
103
+ precision = signed_char
104
+ asset = scan(7).strip
105
+
106
+ amount = "%.#{precision}f #{asset}" % (amount / 10 ** precision)
107
+
108
+ Steem::Type::Amount.new(amount)
109
+ end
110
+
111
+ def price
112
+ {base: amount, quote: amount}
113
+ end
114
+
115
+ def authority(options = {optional: false})
116
+ return if !!options[:optional] && unsigned_char == 0
117
+
118
+ {
119
+ weight_threshold: uint32,
120
+ account_auths: varint.times.map { [string, uint16] },
121
+ key_auths: varint.times.map { [public_key, uint16] }
122
+ }
123
+ end
124
+
125
+ def optional_authority
126
+ authority(optional: true)
127
+ end
128
+
129
+ def comment_options_extensions
130
+ if scan(1) == "\x01"
131
+ beneficiaries
132
+ else
133
+ []
134
+ end
135
+ end
136
+
137
+ def beneficiaries
138
+ if scan(1) == "\x00"
139
+ varint.times.map {{account: string, weight: uint16}}
140
+ end
141
+ end
142
+
143
+ def chain_properties
144
+ {
145
+ account_creation_fee: amount,
146
+ maximum_block_size: uint32,
147
+ sbd_interest_rate: uint16
148
+ }
149
+ end
150
+
151
+ def required_auths
152
+ varint.times.map { string }
153
+ end
154
+
155
+ def witness_properties
156
+ properties = {}
157
+
158
+ varint.times do
159
+ key = string.to_sym
160
+ properties[key] = case key
161
+ when :account_creation_fee then Steem::Type::Amount.new(string)
162
+ when :account_subsidy_budget then scan(3)
163
+ when :account_subsidy_decay, :maximum_block_size then uint32
164
+ when :url then string
165
+ when :sbd_exchange_rate
166
+ JSON[string].tap do |rate|
167
+ rate["base"] = Steem::Type::Amount.new(rate["base"])
168
+ rate["quote"] = Steem::Type::Amount.new(rate["quote"])
169
+ end
170
+ when :sbd_interest_rate then uint16
171
+ when :key, :new_signing_key then @prefix + scan(50)
172
+ else; raise "Unknown witness property: #{key}"
173
+ end
174
+ end
175
+
176
+ properties
177
+ end
178
+
179
+ def empty_array
180
+ unsigned_char == 0 and [] or raise "Found non-empty array."
181
+ end
182
+
183
+ def transaction(options = {})
184
+ trx = options[:trx] || Transaction.new
185
+
186
+ trx.ref_block_num = uint16
187
+ trx.ref_block_prefix = uint32
188
+ trx.expiration = point_in_time
189
+
190
+ trx.operations = operations
191
+
192
+ trx
193
+ rescue => e
194
+ raise DeserializationError.new("Transaction failed\nOriginal serialized bytes:\n[#{hex[0..(@cursor * 2) - 1]}]#{hex[((@cursor) * 2)..-1]}", e)
195
+ end
196
+
197
+ def operations
198
+ operations_len = signed_char
199
+ operations = []
200
+
201
+ while operations.size < operations_len do
202
+ begin
203
+ type = operation_type
204
+ break if type.nil?
205
+
206
+ op_class_name = type.to_s.sub!(/_operation$/, '')
207
+ op_class_name = "Steem::Operation::" + op_class_name.split('_').map(&:capitalize).join
208
+ op_class = Object::const_get(op_class_name)
209
+ op = op_class.new
210
+
211
+ op_class::serializable_types.each do |k, v|
212
+ begin
213
+ # binding.pry if v == :comment_options_extensions
214
+ op.send("#{k}=", send(v))
215
+ rescue => e
216
+ raise DeserializationError.new("#{type}.#{k} (#{v}) failed", e)
217
+ end
218
+ end
219
+
220
+ operations << {type: type, value: op}
221
+ rescue => e
222
+ raise DeserializationError.new("#{type} failed", e)
223
+ end
224
+ end
225
+
226
+ operations
227
+ rescue => e
228
+ raise DeserializationError.new("Operations failed", e)
229
+ end
230
+ end
231
+ end